Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

jump_label: Annotate entries that operate on __init code earlier

Jump table entries are mostly read-only, with the exception of the
init and module loader code that defuses entries that point into init
code when the code being referred to is freed.

For robustness, it would be better to move these entries into the
ro_after_init section, but clearing the 'code' member of each jump
table entry referring to init code at module load time races with the
module_enable_ro() call that remaps the ro_after_init section read
only, so we'd like to do it earlier.

So given that whether such an entry refers to init code can be decided
much earlier, we can pull this check forward. Since we may still need
the code entry at this point, let's switch to setting a low bit in the
'key' member just like we do to annotate the default state of a jump
table entry.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Kees Cook <keescook@chromium.org>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-s390@vger.kernel.org
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Jessica Yu <jeyu@kernel.org>
Link: https://lkml.kernel.org/r/20180919065144.25010-8-ard.biesheuvel@linaro.org

authored by

Ard Biesheuvel and committed by
Thomas Gleixner
19483677 b34006c4

+18 -42
+4 -7
include/linux/jump_label.h
··· 141 141 142 142 static inline struct static_key *jump_entry_key(const struct jump_entry *entry) 143 143 { 144 - long offset = entry->key & ~1L; 144 + long offset = entry->key & ~3L; 145 145 146 146 return (struct static_key *)((unsigned long)&entry->key + offset); 147 147 } ··· 160 160 161 161 static inline struct static_key *jump_entry_key(const struct jump_entry *entry) 162 162 { 163 - return (struct static_key *)((unsigned long)entry->key & ~1UL); 163 + return (struct static_key *)((unsigned long)entry->key & ~3UL); 164 164 } 165 165 166 166 #endif ··· 172 172 173 173 static inline bool jump_entry_is_init(const struct jump_entry *entry) 174 174 { 175 - return entry->code == 0; 175 + return (unsigned long)entry->key & 2UL; 176 176 } 177 177 178 178 static inline void jump_entry_set_init(struct jump_entry *entry) 179 179 { 180 - entry->code = 0; 180 + entry->key |= 2; 181 181 } 182 182 183 183 #endif ··· 213 213 extern struct jump_entry __stop___jump_table[]; 214 214 215 215 extern void jump_label_init(void); 216 - extern void jump_label_invalidate_initmem(void); 217 216 extern void jump_label_lock(void); 218 217 extern void jump_label_unlock(void); 219 218 extern void arch_jump_label_transform(struct jump_entry *entry, ··· 259 260 { 260 261 static_key_initialized = true; 261 262 } 262 - 263 - static inline void jump_label_invalidate_initmem(void) {} 264 263 265 264 static __always_inline bool static_key_false(struct static_key *key) 266 265 {
-1
init/main.c
··· 1064 1064 /* need to finish all async __init code before freeing the memory */ 1065 1065 async_synchronize_full(); 1066 1066 ftrace_free_init_mem(); 1067 - jump_label_invalidate_initmem(); 1068 1067 free_initmem(); 1069 1068 mark_readonly(); 1070 1069
+14 -34
kernel/jump_label.c
··· 373 373 374 374 static void __jump_label_update(struct static_key *key, 375 375 struct jump_entry *entry, 376 - struct jump_entry *stop) 376 + struct jump_entry *stop, 377 + bool init) 377 378 { 378 379 for (; (entry < stop) && (jump_entry_key(entry) == key); entry++) { 379 380 /* 380 381 * An entry->code of 0 indicates an entry which has been 381 382 * disabled because it was in an init text area. 382 383 */ 383 - if (!jump_entry_is_init(entry)) { 384 + if (init || !jump_entry_is_init(entry)) { 384 385 if (kernel_text_address(jump_entry_code(entry))) 385 386 arch_jump_label_transform(entry, jump_label_type(entry)); 386 387 else ··· 421 420 if (jump_label_type(iter) == JUMP_LABEL_NOP) 422 421 arch_jump_label_transform_static(iter, JUMP_LABEL_NOP); 423 422 423 + if (init_section_contains((void *)jump_entry_code(iter), 1)) 424 + jump_entry_set_init(iter); 425 + 424 426 iterk = jump_entry_key(iter); 425 427 if (iterk == key) 426 428 continue; ··· 434 430 static_key_initialized = true; 435 431 jump_label_unlock(); 436 432 cpus_read_unlock(); 437 - } 438 - 439 - /* Disable any jump label entries in __init/__exit code */ 440 - void __init jump_label_invalidate_initmem(void) 441 - { 442 - struct jump_entry *iter_start = __start___jump_table; 443 - struct jump_entry *iter_stop = __stop___jump_table; 444 - struct jump_entry *iter; 445 - 446 - for (iter = iter_start; iter < iter_stop; iter++) { 447 - if (init_section_contains((void *)jump_entry_code(iter), 1)) 448 - jump_entry_set_init(iter); 449 - } 450 433 } 451 434 452 435 #ifdef CONFIG_MODULES ··· 515 524 stop = __stop___jump_table; 516 525 else 517 526 stop = m->jump_entries + m->num_jump_entries; 518 - __jump_label_update(key, mod->entries, stop); 527 + __jump_label_update(key, mod->entries, stop, 528 + m->state == MODULE_STATE_COMING); 519 529 } 520 530 } 521 531 ··· 562 570 for (iter = iter_start; iter < iter_stop; iter++) { 563 571 struct static_key *iterk; 564 572 573 + if (within_module_init(jump_entry_code(iter), mod)) 574 + jump_entry_set_init(iter); 575 + 565 576 iterk = jump_entry_key(iter); 566 577 if (iterk == key) 567 578 continue; ··· 600 605 601 606 /* Only update if we've changed from our initial state */ 602 607 if (jump_label_type(iter) != jump_label_init_type(iter)) 603 - __jump_label_update(key, iter, iter_stop); 608 + __jump_label_update(key, iter, iter_stop, true); 604 609 } 605 610 606 611 return 0; ··· 656 661 } 657 662 } 658 663 659 - /* Disable any jump label entries in module init code */ 660 - static void jump_label_invalidate_module_init(struct module *mod) 661 - { 662 - struct jump_entry *iter_start = mod->jump_entries; 663 - struct jump_entry *iter_stop = iter_start + mod->num_jump_entries; 664 - struct jump_entry *iter; 665 - 666 - for (iter = iter_start; iter < iter_stop; iter++) { 667 - if (within_module_init(jump_entry_code(iter), mod)) 668 - jump_entry_set_init(iter); 669 - } 670 - } 671 - 672 664 static int 673 665 jump_label_module_notify(struct notifier_block *self, unsigned long val, 674 666 void *data) ··· 676 694 break; 677 695 case MODULE_STATE_GOING: 678 696 jump_label_del_module(mod); 679 - break; 680 - case MODULE_STATE_LIVE: 681 - jump_label_invalidate_module_init(mod); 682 697 break; 683 698 } 684 699 ··· 746 767 entry = static_key_entries(key); 747 768 /* if there are no users, entry can be NULL */ 748 769 if (entry) 749 - __jump_label_update(key, entry, stop); 770 + __jump_label_update(key, entry, stop, 771 + system_state < SYSTEM_RUNNING); 750 772 } 751 773 752 774 #ifdef CONFIG_STATIC_KEYS_SELFTEST