The module_kallsyms_on_each_symbol function iterates over symbols of all modules. To implement BTF ID set processing in each module's BTF parsing routine, we need a variant that can iterate over a single module's symbols. To implement this, extract the single module functionality out of module_kallsyms_on_each_symbol, and rename the old function to module_kallsyms_on_each_symbol_all. Then, the new module_kallsyms_on_each_symbol which iterates over a single module's symbols uses this extracted helper with appropriate locking. Next commit will make use of it to implement BTF ID set concatentation per hook and type. Also, since we'll be using kallsyms_on_each_symbol for vmlinux BTF parsing, remove its dependency on CONFIG_LIVEPATCH. Cc: Luis Chamberlain <mcgrof@xxxxxxxxxx> Cc: Jessica Yu <jeyu@xxxxxxxxxx> Cc: Josh Poimboeuf <jpoimboe@xxxxxxxxxx> Cc: Jiri Kosina <jikos@xxxxxxxxxx> Cc: Miroslav Benes <mbenes@xxxxxxx> Cc: Petr Mladek <pmladek@xxxxxxxx> Cc: Joe Lawrence <joe.lawrence@xxxxxxxxxx> Cc: live-patching@xxxxxxxxxxxxxxx Signed-off-by: Kumar Kartikeya Dwivedi <memxor@xxxxxxxxx> --- include/linux/kallsyms.h | 11 ++++++- include/linux/module.h | 37 +++++++++++++++++++++++- kernel/kallsyms.c | 4 +-- kernel/livepatch/core.c | 2 +- kernel/module.c | 62 ++++++++++++++++++++++++++++++---------- 5 files changed, 95 insertions(+), 21 deletions(-) diff --git a/include/linux/kallsyms.h b/include/linux/kallsyms.h index 4176c7eca7b5..89ed3eb2e185 100644 --- a/include/linux/kallsyms.h +++ b/include/linux/kallsyms.h @@ -65,11 +65,12 @@ static inline void *dereference_symbol_descriptor(void *ptr) return ptr; } +#ifdef CONFIG_KALLSYMS + int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *, unsigned long), void *data); -#ifdef CONFIG_KALLSYMS /* Lookup the address for a symbol. Returns 0 if not found. */ unsigned long kallsyms_lookup_name(const char *name); @@ -98,6 +99,14 @@ extern bool kallsyms_show_value(const struct cred *cred); #else /* !CONFIG_KALLSYMS */ +static inline int kallsyms_on_each_symbol(int (*fn)(void *, const char *, + struct module *, + unsigned long), + void *data) +{ + return 0; +} + static inline unsigned long kallsyms_lookup_name(const char *name) { return 0; diff --git a/include/linux/module.h b/include/linux/module.h index c9f1200b2312..e982aca57883 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -867,8 +867,43 @@ static inline bool module_sig_ok(struct module *module) } #endif /* CONFIG_MODULE_SIG */ -int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, +#if defined(CONFIG_MODULES) && defined(CONFIG_KALLSYMS) + +#ifdef CONFIG_LIVEPATCH + +int module_kallsyms_on_each_symbol_all(int (*fn)(void *, const char *, + struct module *, + unsigned long), + void *data); + +#else /* !CONFIG_LIVEPATCH */ + +static inline int module_kallsyms_on_each_symbol_all(int (*fn)(void *, const char *, + struct module *, + unsigned long), + void *data) +{ + return 0; +} + +#endif /* CONFIG_LIVEPATCH */ + +int module_kallsyms_on_each_symbol(struct module *mod, + int (*fn)(void *, const char *, struct module *, unsigned long), void *data); +#else /* !(CONFIG_MODULES && CONFIG_KALLSYMS) */ + +static inline int module_kallsyms_on_each_symbol(struct module *mod, + int (*fn)(void *, const char *, + struct module *, + unsigned long), + void *data) +{ + return 0; +} + +#endif /* CONFIG_MODULES && CONFIG_KALLSYMS */ + #endif /* _LINUX_MODULE_H */ diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index 3011bc33a5ba..da40f48f071e 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -224,10 +224,9 @@ unsigned long kallsyms_lookup_name(const char *name) return module_kallsyms_lookup_name(name); } -#ifdef CONFIG_LIVEPATCH /* * Iterate over all symbols in vmlinux. For symbols from modules use - * module_kallsyms_on_each_symbol instead. + * module_kallsyms_on_each_symbol_all instead. */ int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *, unsigned long), @@ -246,7 +245,6 @@ int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *, } return 0; } -#endif /* CONFIG_LIVEPATCH */ static unsigned long get_symbol_pos(unsigned long addr, unsigned long *symbolsize, diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index 335d988bd811..3756071658fd 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c @@ -165,7 +165,7 @@ static int klp_find_object_symbol(const char *objname, const char *name, }; if (objname) - module_kallsyms_on_each_symbol(klp_find_callback, &args); + module_kallsyms_on_each_symbol_all(klp_find_callback, &args); else kallsyms_on_each_symbol(klp_find_callback, &args); diff --git a/kernel/module.c b/kernel/module.c index 84a9141a5e15..88a24dd8f4bd 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -4473,13 +4473,54 @@ unsigned long module_kallsyms_lookup_name(const char *name) return ret; } -#ifdef CONFIG_LIVEPATCH -int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, +static int __module_kallsyms_on_each_symbol(struct mod_kallsyms *kallsyms, + struct module *mod, + int (*fn)(void *, const char *, + struct module *, unsigned long), + void *data) +{ + unsigned long i; + int ret = 0; + + for (i = 0; i < kallsyms->num_symtab; i++) { + const Elf_Sym *sym = &kallsyms->symtab[i]; + + if (sym->st_shndx == SHN_UNDEF) + continue; + + ret = fn(data, kallsyms_symbol_name(kallsyms, i), + mod, kallsyms_symbol_value(sym)); + if (ret != 0) + break; + } + + return ret; +} + +int module_kallsyms_on_each_symbol(struct module *mod, + int (*fn)(void *, const char *, struct module *, unsigned long), void *data) +{ + struct mod_kallsyms *kallsyms; + int ret = 0; + + mutex_lock(&module_mutex); + /* We hold module_mutex: no need for rcu_dereference_sched */ + kallsyms = mod->kallsyms; + if (mod->state != MODULE_STATE_UNFORMED) + ret = __module_kallsyms_on_each_symbol(kallsyms, mod, fn, data); + mutex_unlock(&module_mutex); + + return ret; +} + +#ifdef CONFIG_LIVEPATCH +int module_kallsyms_on_each_symbol_all(int (*fn)(void *, const char *, + struct module *, unsigned long), + void *data) { struct module *mod; - unsigned int i; int ret = 0; mutex_lock(&module_mutex); @@ -4489,19 +4530,10 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, if (mod->state == MODULE_STATE_UNFORMED) continue; - for (i = 0; i < kallsyms->num_symtab; i++) { - const Elf_Sym *sym = &kallsyms->symtab[i]; - - if (sym->st_shndx == SHN_UNDEF) - continue; - - ret = fn(data, kallsyms_symbol_name(kallsyms, i), - mod, kallsyms_symbol_value(sym)); - if (ret != 0) - goto out; - } + ret = __module_kallsyms_on_each_symbol(kallsyms, mod, fn, data); + if (ret != 0) + break; } -out: mutex_unlock(&module_mutex); return ret; } -- 2.34.1