diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-02-09 19:40:59 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-02-09 19:40:59 -0500 |
commit | 2178cbc68f3602dc0b5949b9be2c8383ad3d93ef (patch) | |
tree | 0ce16c588dfa2c4ba665f1a5265026a11fafa826 | |
parent | 7cf91adc0d38eb6cc8517ae45126ca7440177e61 (diff) | |
parent | 8244062ef1e54502ef55f54cced659913f244c3e (diff) |
Merge tag 'fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux
Pull module fixes from Rusty Russell:
"Fix for async_probe module param added in 4.3 (clearly not widely used
yet), and a much more interesting kallsyms race which has been around
approximately forever. This fix is more invasive, and will require
some care in backporting, but I hated all the bandaids I could think
of, so...
There are some more coming, which are only for breakages introduced
this cycle (livepatch), but wanted these in now"
* tag 'fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux:
modules: fix longstanding /proc/kallsyms vs module insertion race.
module: wrapper for symbol name.
modules: fix modparam async_probe request
-rw-r--r-- | include/linux/module.h | 19 | ||||
-rw-r--r-- | kernel/module.c | 120 |
2 files changed, 85 insertions, 54 deletions
diff --git a/include/linux/module.h b/include/linux/module.h index 4560d8f1545d..2bb0c3085706 100644 --- a/include/linux/module.h +++ b/include/linux/module.h | |||
@@ -324,6 +324,12 @@ struct module_layout { | |||
324 | #define __module_layout_align | 324 | #define __module_layout_align |
325 | #endif | 325 | #endif |
326 | 326 | ||
327 | struct mod_kallsyms { | ||
328 | Elf_Sym *symtab; | ||
329 | unsigned int num_symtab; | ||
330 | char *strtab; | ||
331 | }; | ||
332 | |||
327 | struct module { | 333 | struct module { |
328 | enum module_state state; | 334 | enum module_state state; |
329 | 335 | ||
@@ -405,15 +411,10 @@ struct module { | |||
405 | #endif | 411 | #endif |
406 | 412 | ||
407 | #ifdef CONFIG_KALLSYMS | 413 | #ifdef CONFIG_KALLSYMS |
408 | /* | 414 | /* Protected by RCU and/or module_mutex: use rcu_dereference() */ |
409 | * We keep the symbol and string tables for kallsyms. | 415 | struct mod_kallsyms *kallsyms; |
410 | * The core_* fields below are temporary, loader-only (they | 416 | struct mod_kallsyms core_kallsyms; |
411 | * could really be discarded after module init). | 417 | |
412 | */ | ||
413 | Elf_Sym *symtab, *core_symtab; | ||
414 | unsigned int num_symtab, core_num_syms; | ||
415 | char *strtab, *core_strtab; | ||
416 | |||
417 | /* Section attributes */ | 418 | /* Section attributes */ |
418 | struct module_sect_attrs *sect_attrs; | 419 | struct module_sect_attrs *sect_attrs; |
419 | 420 | ||
diff --git a/kernel/module.c b/kernel/module.c index 8358f4697c0c..9537da37ce87 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -303,6 +303,9 @@ struct load_info { | |||
303 | struct _ddebug *debug; | 303 | struct _ddebug *debug; |
304 | unsigned int num_debug; | 304 | unsigned int num_debug; |
305 | bool sig_ok; | 305 | bool sig_ok; |
306 | #ifdef CONFIG_KALLSYMS | ||
307 | unsigned long mod_kallsyms_init_off; | ||
308 | #endif | ||
306 | struct { | 309 | struct { |
307 | unsigned int sym, str, mod, vers, info, pcpu; | 310 | unsigned int sym, str, mod, vers, info, pcpu; |
308 | } index; | 311 | } index; |
@@ -2480,10 +2483,21 @@ static void layout_symtab(struct module *mod, struct load_info *info) | |||
2480 | strsect->sh_flags |= SHF_ALLOC; | 2483 | strsect->sh_flags |= SHF_ALLOC; |
2481 | strsect->sh_entsize = get_offset(mod, &mod->init_layout.size, strsect, | 2484 | strsect->sh_entsize = get_offset(mod, &mod->init_layout.size, strsect, |
2482 | info->index.str) | INIT_OFFSET_MASK; | 2485 | info->index.str) | INIT_OFFSET_MASK; |
2483 | mod->init_layout.size = debug_align(mod->init_layout.size); | ||
2484 | pr_debug("\t%s\n", info->secstrings + strsect->sh_name); | 2486 | pr_debug("\t%s\n", info->secstrings + strsect->sh_name); |
2487 | |||
2488 | /* We'll tack temporary mod_kallsyms on the end. */ | ||
2489 | mod->init_layout.size = ALIGN(mod->init_layout.size, | ||
2490 | __alignof__(struct mod_kallsyms)); | ||
2491 | info->mod_kallsyms_init_off = mod->init_layout.size; | ||
2492 | mod->init_layout.size += sizeof(struct mod_kallsyms); | ||
2493 | mod->init_layout.size = debug_align(mod->init_layout.size); | ||
2485 | } | 2494 | } |
2486 | 2495 | ||
2496 | /* | ||
2497 | * We use the full symtab and strtab which layout_symtab arranged to | ||
2498 | * be appended to the init section. Later we switch to the cut-down | ||
2499 | * core-only ones. | ||
2500 | */ | ||
2487 | static void add_kallsyms(struct module *mod, const struct load_info *info) | 2501 | static void add_kallsyms(struct module *mod, const struct load_info *info) |
2488 | { | 2502 | { |
2489 | unsigned int i, ndst; | 2503 | unsigned int i, ndst; |
@@ -2492,29 +2506,34 @@ static void add_kallsyms(struct module *mod, const struct load_info *info) | |||
2492 | char *s; | 2506 | char *s; |
2493 | Elf_Shdr *symsec = &info->sechdrs[info->index.sym]; | 2507 | Elf_Shdr *symsec = &info->sechdrs[info->index.sym]; |
2494 | 2508 | ||
2495 | mod->symtab = (void *)symsec->sh_addr; | 2509 | /* Set up to point into init section. */ |
2496 | mod->num_symtab = symsec->sh_size / sizeof(Elf_Sym); | 2510 | mod->kallsyms = mod->init_layout.base + info->mod_kallsyms_init_off; |
2511 | |||
2512 | mod->kallsyms->symtab = (void *)symsec->sh_addr; | ||
2513 | mod->kallsyms->num_symtab = symsec->sh_size / sizeof(Elf_Sym); | ||
2497 | /* Make sure we get permanent strtab: don't use info->strtab. */ | 2514 | /* Make sure we get permanent strtab: don't use info->strtab. */ |
2498 | mod->strtab = (void *)info->sechdrs[info->index.str].sh_addr; | 2515 | mod->kallsyms->strtab = (void *)info->sechdrs[info->index.str].sh_addr; |
2499 | 2516 | ||
2500 | /* Set types up while we still have access to sections. */ | 2517 | /* Set types up while we still have access to sections. */ |
2501 | for (i = 0; i < mod->num_symtab; i++) | 2518 | for (i = 0; i < mod->kallsyms->num_symtab; i++) |
2502 | mod->symtab[i].st_info = elf_type(&mod->symtab[i], info); | 2519 | mod->kallsyms->symtab[i].st_info |
2503 | 2520 | = elf_type(&mod->kallsyms->symtab[i], info); | |
2504 | mod->core_symtab = dst = mod->core_layout.base + info->symoffs; | 2521 | |
2505 | mod->core_strtab = s = mod->core_layout.base + info->stroffs; | 2522 | /* Now populate the cut down core kallsyms for after init. */ |
2506 | src = mod->symtab; | 2523 | mod->core_kallsyms.symtab = dst = mod->core_layout.base + info->symoffs; |
2507 | for (ndst = i = 0; i < mod->num_symtab; i++) { | 2524 | mod->core_kallsyms.strtab = s = mod->core_layout.base + info->stroffs; |
2525 | src = mod->kallsyms->symtab; | ||
2526 | for (ndst = i = 0; i < mod->kallsyms->num_symtab; i++) { | ||
2508 | if (i == 0 || | 2527 | if (i == 0 || |
2509 | is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum, | 2528 | is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum, |
2510 | info->index.pcpu)) { | 2529 | info->index.pcpu)) { |
2511 | dst[ndst] = src[i]; | 2530 | dst[ndst] = src[i]; |
2512 | dst[ndst++].st_name = s - mod->core_strtab; | 2531 | dst[ndst++].st_name = s - mod->core_kallsyms.strtab; |
2513 | s += strlcpy(s, &mod->strtab[src[i].st_name], | 2532 | s += strlcpy(s, &mod->kallsyms->strtab[src[i].st_name], |
2514 | KSYM_NAME_LEN) + 1; | 2533 | KSYM_NAME_LEN) + 1; |
2515 | } | 2534 | } |
2516 | } | 2535 | } |
2517 | mod->core_num_syms = ndst; | 2536 | mod->core_kallsyms.num_symtab = ndst; |
2518 | } | 2537 | } |
2519 | #else | 2538 | #else |
2520 | static inline void layout_symtab(struct module *mod, struct load_info *info) | 2539 | static inline void layout_symtab(struct module *mod, struct load_info *info) |
@@ -3263,9 +3282,8 @@ static noinline int do_init_module(struct module *mod) | |||
3263 | module_put(mod); | 3282 | module_put(mod); |
3264 | trim_init_extable(mod); | 3283 | trim_init_extable(mod); |
3265 | #ifdef CONFIG_KALLSYMS | 3284 | #ifdef CONFIG_KALLSYMS |
3266 | mod->num_symtab = mod->core_num_syms; | 3285 | /* Switch to core kallsyms now init is done: kallsyms may be walking! */ |
3267 | mod->symtab = mod->core_symtab; | 3286 | rcu_assign_pointer(mod->kallsyms, &mod->core_kallsyms); |
3268 | mod->strtab = mod->core_strtab; | ||
3269 | #endif | 3287 | #endif |
3270 | mod_tree_remove_init(mod); | 3288 | mod_tree_remove_init(mod); |
3271 | disable_ro_nx(&mod->init_layout); | 3289 | disable_ro_nx(&mod->init_layout); |
@@ -3496,7 +3514,7 @@ static int load_module(struct load_info *info, const char __user *uargs, | |||
3496 | 3514 | ||
3497 | /* Module is ready to execute: parsing args may do that. */ | 3515 | /* Module is ready to execute: parsing args may do that. */ |
3498 | after_dashes = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, | 3516 | after_dashes = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, |
3499 | -32768, 32767, NULL, | 3517 | -32768, 32767, mod, |
3500 | unknown_module_param_cb); | 3518 | unknown_module_param_cb); |
3501 | if (IS_ERR(after_dashes)) { | 3519 | if (IS_ERR(after_dashes)) { |
3502 | err = PTR_ERR(after_dashes); | 3520 | err = PTR_ERR(after_dashes); |
@@ -3627,6 +3645,11 @@ static inline int is_arm_mapping_symbol(const char *str) | |||
3627 | && (str[2] == '\0' || str[2] == '.'); | 3645 | && (str[2] == '\0' || str[2] == '.'); |
3628 | } | 3646 | } |
3629 | 3647 | ||
3648 | static const char *symname(struct mod_kallsyms *kallsyms, unsigned int symnum) | ||
3649 | { | ||
3650 | return kallsyms->strtab + kallsyms->symtab[symnum].st_name; | ||
3651 | } | ||
3652 | |||
3630 | static const char *get_ksymbol(struct module *mod, | 3653 | static const char *get_ksymbol(struct module *mod, |
3631 | unsigned long addr, | 3654 | unsigned long addr, |
3632 | unsigned long *size, | 3655 | unsigned long *size, |
@@ -3634,6 +3657,7 @@ static const char *get_ksymbol(struct module *mod, | |||
3634 | { | 3657 | { |
3635 | unsigned int i, best = 0; | 3658 | unsigned int i, best = 0; |
3636 | unsigned long nextval; | 3659 | unsigned long nextval; |
3660 | struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms); | ||
3637 | 3661 | ||
3638 | /* At worse, next value is at end of module */ | 3662 | /* At worse, next value is at end of module */ |
3639 | if (within_module_init(addr, mod)) | 3663 | if (within_module_init(addr, mod)) |
@@ -3643,32 +3667,32 @@ static const char *get_ksymbol(struct module *mod, | |||
3643 | 3667 | ||
3644 | /* Scan for closest preceding symbol, and next symbol. (ELF | 3668 | /* Scan for closest preceding symbol, and next symbol. (ELF |
3645 | starts real symbols at 1). */ | 3669 | starts real symbols at 1). */ |
3646 | for (i = 1; i < mod->num_symtab; i++) { | 3670 | for (i = 1; i < kallsyms->num_symtab; i++) { |
3647 | if (mod->symtab[i].st_shndx == SHN_UNDEF) | 3671 | if (kallsyms->symtab[i].st_shndx == SHN_UNDEF) |
3648 | continue; | 3672 | continue; |
3649 | 3673 | ||
3650 | /* We ignore unnamed symbols: they're uninformative | 3674 | /* We ignore unnamed symbols: they're uninformative |
3651 | * and inserted at a whim. */ | 3675 | * and inserted at a whim. */ |
3652 | if (mod->symtab[i].st_value <= addr | 3676 | if (*symname(kallsyms, i) == '\0' |
3653 | && mod->symtab[i].st_value > mod->symtab[best].st_value | 3677 | || is_arm_mapping_symbol(symname(kallsyms, i))) |
3654 | && *(mod->strtab + mod->symtab[i].st_name) != '\0' | 3678 | continue; |
3655 | && !is_arm_mapping_symbol(mod->strtab + mod->symtab[i].st_name)) | 3679 | |
3680 | if (kallsyms->symtab[i].st_value <= addr | ||
3681 | && kallsyms->symtab[i].st_value > kallsyms->symtab[best].st_value) | ||
3656 | best = i; | 3682 | best = i; |
3657 | if (mod->symtab[i].st_value > addr | 3683 | if (kallsyms->symtab[i].st_value > addr |
3658 | && mod->symtab[i].st_value < nextval | 3684 | && kallsyms->symtab[i].st_value < nextval) |
3659 | && *(mod->strtab + mod->symtab[i].st_name) != '\0' | 3685 | nextval = kallsyms->symtab[i].st_value; |
3660 | && !is_arm_mapping_symbol(mod->strtab + mod->symtab[i].st_name)) | ||
3661 | nextval = mod->symtab[i].st_value; | ||
3662 | } | 3686 | } |
3663 | 3687 | ||
3664 | if (!best) | 3688 | if (!best) |
3665 | return NULL; | 3689 | return NULL; |
3666 | 3690 | ||
3667 | if (size) | 3691 | if (size) |
3668 | *size = nextval - mod->symtab[best].st_value; | 3692 | *size = nextval - kallsyms->symtab[best].st_value; |
3669 | if (offset) | 3693 | if (offset) |
3670 | *offset = addr - mod->symtab[best].st_value; | 3694 | *offset = addr - kallsyms->symtab[best].st_value; |
3671 | return mod->strtab + mod->symtab[best].st_name; | 3695 | return symname(kallsyms, best); |
3672 | } | 3696 | } |
3673 | 3697 | ||
3674 | /* For kallsyms to ask for address resolution. NULL means not found. Careful | 3698 | /* For kallsyms to ask for address resolution. NULL means not found. Careful |
@@ -3758,19 +3782,21 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, | |||
3758 | 3782 | ||
3759 | preempt_disable(); | 3783 | preempt_disable(); |
3760 | list_for_each_entry_rcu(mod, &modules, list) { | 3784 | list_for_each_entry_rcu(mod, &modules, list) { |
3785 | struct mod_kallsyms *kallsyms; | ||
3786 | |||
3761 | if (mod->state == MODULE_STATE_UNFORMED) | 3787 | if (mod->state == MODULE_STATE_UNFORMED) |
3762 | continue; | 3788 | continue; |
3763 | if (symnum < mod->num_symtab) { | 3789 | kallsyms = rcu_dereference_sched(mod->kallsyms); |
3764 | *value = mod->symtab[symnum].st_value; | 3790 | if (symnum < kallsyms->num_symtab) { |
3765 | *type = mod->symtab[symnum].st_info; | 3791 | *value = kallsyms->symtab[symnum].st_value; |
3766 | strlcpy(name, mod->strtab + mod->symtab[symnum].st_name, | 3792 | *type = kallsyms->symtab[symnum].st_info; |
3767 | KSYM_NAME_LEN); | 3793 | strlcpy(name, symname(kallsyms, symnum), KSYM_NAME_LEN); |
3768 | strlcpy(module_name, mod->name, MODULE_NAME_LEN); | 3794 | strlcpy(module_name, mod->name, MODULE_NAME_LEN); |
3769 | *exported = is_exported(name, *value, mod); | 3795 | *exported = is_exported(name, *value, mod); |
3770 | preempt_enable(); | 3796 | preempt_enable(); |
3771 | return 0; | 3797 | return 0; |
3772 | } | 3798 | } |
3773 | symnum -= mod->num_symtab; | 3799 | symnum -= kallsyms->num_symtab; |
3774 | } | 3800 | } |
3775 | preempt_enable(); | 3801 | preempt_enable(); |
3776 | return -ERANGE; | 3802 | return -ERANGE; |
@@ -3779,11 +3805,12 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, | |||
3779 | static unsigned long mod_find_symname(struct module *mod, const char *name) | 3805 | static unsigned long mod_find_symname(struct module *mod, const char *name) |
3780 | { | 3806 | { |
3781 | unsigned int i; | 3807 | unsigned int i; |
3808 | struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms); | ||
3782 | 3809 | ||
3783 | for (i = 0; i < mod->num_symtab; i++) | 3810 | for (i = 0; i < kallsyms->num_symtab; i++) |
3784 | if (strcmp(name, mod->strtab+mod->symtab[i].st_name) == 0 && | 3811 | if (strcmp(name, symname(kallsyms, i)) == 0 && |
3785 | mod->symtab[i].st_info != 'U') | 3812 | kallsyms->symtab[i].st_info != 'U') |
3786 | return mod->symtab[i].st_value; | 3813 | return kallsyms->symtab[i].st_value; |
3787 | return 0; | 3814 | return 0; |
3788 | } | 3815 | } |
3789 | 3816 | ||
@@ -3822,11 +3849,14 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, | |||
3822 | module_assert_mutex(); | 3849 | module_assert_mutex(); |
3823 | 3850 | ||
3824 | list_for_each_entry(mod, &modules, list) { | 3851 | list_for_each_entry(mod, &modules, list) { |
3852 | /* We hold module_mutex: no need for rcu_dereference_sched */ | ||
3853 | struct mod_kallsyms *kallsyms = mod->kallsyms; | ||
3854 | |||
3825 | if (mod->state == MODULE_STATE_UNFORMED) | 3855 | if (mod->state == MODULE_STATE_UNFORMED) |
3826 | continue; | 3856 | continue; |
3827 | for (i = 0; i < mod->num_symtab; i++) { | 3857 | for (i = 0; i < kallsyms->num_symtab; i++) { |
3828 | ret = fn(data, mod->strtab + mod->symtab[i].st_name, | 3858 | ret = fn(data, symname(kallsyms, i), |
3829 | mod, mod->symtab[i].st_value); | 3859 | mod, kallsyms->symtab[i].st_value); |
3830 | if (ret != 0) | 3860 | if (ret != 0) |
3831 | return ret; | 3861 | return ret; |
3832 | } | 3862 | } |