Skip to content

Commit 1948367

Browse files
Ard BiesheuvelKAGA-KOKO
authored andcommitted
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 <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Reviewed-by: Kees Cook <[email protected]> Acked-by: Peter Zijlstra (Intel) <[email protected]> Cc: [email protected] Cc: [email protected] Cc: Arnd Bergmann <[email protected]> Cc: Heiko Carstens <[email protected]> Cc: Will Deacon <[email protected]> Cc: Catalin Marinas <[email protected]> Cc: Steven Rostedt <[email protected]> Cc: Martin Schwidefsky <[email protected]> Cc: Jessica Yu <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent b34006c commit 1948367

File tree

3 files changed

+18
-42
lines changed

3 files changed

+18
-42
lines changed

include/linux/jump_label.h

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ static inline unsigned long jump_entry_target(const struct jump_entry *entry)
141141

142142
static inline struct static_key *jump_entry_key(const struct jump_entry *entry)
143143
{
144-
long offset = entry->key & ~1L;
144+
long offset = entry->key & ~3L;
145145

146146
return (struct static_key *)((unsigned long)&entry->key + offset);
147147
}
@@ -160,7 +160,7 @@ static inline unsigned long jump_entry_target(const struct jump_entry *entry)
160160

161161
static inline struct static_key *jump_entry_key(const struct jump_entry *entry)
162162
{
163-
return (struct static_key *)((unsigned long)entry->key & ~1UL);
163+
return (struct static_key *)((unsigned long)entry->key & ~3UL);
164164
}
165165

166166
#endif
@@ -172,12 +172,12 @@ static inline bool jump_entry_is_branch(const struct jump_entry *entry)
172172

173173
static inline bool jump_entry_is_init(const struct jump_entry *entry)
174174
{
175-
return entry->code == 0;
175+
return (unsigned long)entry->key & 2UL;
176176
}
177177

178178
static inline void jump_entry_set_init(struct jump_entry *entry)
179179
{
180-
entry->code = 0;
180+
entry->key |= 2;
181181
}
182182

183183
#endif
@@ -213,7 +213,6 @@ extern struct jump_entry __start___jump_table[];
213213
extern struct jump_entry __stop___jump_table[];
214214

215215
extern void jump_label_init(void);
216-
extern void jump_label_invalidate_initmem(void);
217216
extern void jump_label_lock(void);
218217
extern void jump_label_unlock(void);
219218
extern void arch_jump_label_transform(struct jump_entry *entry,
@@ -261,8 +260,6 @@ static __always_inline void jump_label_init(void)
261260
static_key_initialized = true;
262261
}
263262

264-
static inline void jump_label_invalidate_initmem(void) {}
265-
266263
static __always_inline bool static_key_false(struct static_key *key)
267264
{
268265
if (unlikely(static_key_count(key) > 0))

init/main.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1064,7 +1064,6 @@ static int __ref kernel_init(void *unused)
10641064
/* need to finish all async __init code before freeing the memory */
10651065
async_synchronize_full();
10661066
ftrace_free_init_mem();
1067-
jump_label_invalidate_initmem();
10681067
free_initmem();
10691068
mark_readonly();
10701069

kernel/jump_label.c

Lines changed: 14 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -373,14 +373,15 @@ static enum jump_label_type jump_label_type(struct jump_entry *entry)
373373

374374
static void __jump_label_update(struct static_key *key,
375375
struct jump_entry *entry,
376-
struct jump_entry *stop)
376+
struct jump_entry *stop,
377+
bool init)
377378
{
378379
for (; (entry < stop) && (jump_entry_key(entry) == key); entry++) {
379380
/*
380381
* An entry->code of 0 indicates an entry which has been
381382
* disabled because it was in an init text area.
382383
*/
383-
if (!jump_entry_is_init(entry)) {
384+
if (init || !jump_entry_is_init(entry)) {
384385
if (kernel_text_address(jump_entry_code(entry)))
385386
arch_jump_label_transform(entry, jump_label_type(entry));
386387
else
@@ -420,6 +421,9 @@ void __init jump_label_init(void)
420421
if (jump_label_type(iter) == JUMP_LABEL_NOP)
421422
arch_jump_label_transform_static(iter, JUMP_LABEL_NOP);
422423

424+
if (init_section_contains((void *)jump_entry_code(iter), 1))
425+
jump_entry_set_init(iter);
426+
423427
iterk = jump_entry_key(iter);
424428
if (iterk == key)
425429
continue;
@@ -432,19 +436,6 @@ void __init jump_label_init(void)
432436
cpus_read_unlock();
433437
}
434438

435-
/* Disable any jump label entries in __init/__exit code */
436-
void __init jump_label_invalidate_initmem(void)
437-
{
438-
struct jump_entry *iter_start = __start___jump_table;
439-
struct jump_entry *iter_stop = __stop___jump_table;
440-
struct jump_entry *iter;
441-
442-
for (iter = iter_start; iter < iter_stop; iter++) {
443-
if (init_section_contains((void *)jump_entry_code(iter), 1))
444-
jump_entry_set_init(iter);
445-
}
446-
}
447-
448439
#ifdef CONFIG_MODULES
449440

450441
static enum jump_label_type jump_label_init_type(struct jump_entry *entry)
@@ -524,7 +515,8 @@ static void __jump_label_mod_update(struct static_key *key)
524515
stop = __stop___jump_table;
525516
else
526517
stop = m->jump_entries + m->num_jump_entries;
527-
__jump_label_update(key, mod->entries, stop);
518+
__jump_label_update(key, mod->entries, stop,
519+
m->state == MODULE_STATE_COMING);
528520
}
529521
}
530522

@@ -570,6 +562,9 @@ static int jump_label_add_module(struct module *mod)
570562
for (iter = iter_start; iter < iter_stop; iter++) {
571563
struct static_key *iterk;
572564

565+
if (within_module_init(jump_entry_code(iter), mod))
566+
jump_entry_set_init(iter);
567+
573568
iterk = jump_entry_key(iter);
574569
if (iterk == key)
575570
continue;
@@ -605,7 +600,7 @@ static int jump_label_add_module(struct module *mod)
605600

606601
/* Only update if we've changed from our initial state */
607602
if (jump_label_type(iter) != jump_label_init_type(iter))
608-
__jump_label_update(key, iter, iter_stop);
603+
__jump_label_update(key, iter, iter_stop, true);
609604
}
610605

611606
return 0;
@@ -661,19 +656,6 @@ static void jump_label_del_module(struct module *mod)
661656
}
662657
}
663658

664-
/* Disable any jump label entries in module init code */
665-
static void jump_label_invalidate_module_init(struct module *mod)
666-
{
667-
struct jump_entry *iter_start = mod->jump_entries;
668-
struct jump_entry *iter_stop = iter_start + mod->num_jump_entries;
669-
struct jump_entry *iter;
670-
671-
for (iter = iter_start; iter < iter_stop; iter++) {
672-
if (within_module_init(jump_entry_code(iter), mod))
673-
jump_entry_set_init(iter);
674-
}
675-
}
676-
677659
static int
678660
jump_label_module_notify(struct notifier_block *self, unsigned long val,
679661
void *data)
@@ -695,9 +677,6 @@ jump_label_module_notify(struct notifier_block *self, unsigned long val,
695677
case MODULE_STATE_GOING:
696678
jump_label_del_module(mod);
697679
break;
698-
case MODULE_STATE_LIVE:
699-
jump_label_invalidate_module_init(mod);
700-
break;
701680
}
702681

703682
jump_label_unlock();
@@ -767,7 +746,8 @@ static void jump_label_update(struct static_key *key)
767746
entry = static_key_entries(key);
768747
/* if there are no users, entry can be NULL */
769748
if (entry)
770-
__jump_label_update(key, entry, stop);
749+
__jump_label_update(key, entry, stop,
750+
system_state < SYSTEM_RUNNING);
771751
}
772752

773753
#ifdef CONFIG_STATIC_KEYS_SELFTEST

0 commit comments

Comments
 (0)