From: Greg Kroah-Hartman Date: Sun, 13 Mar 2016 04:54:04 +0000 (-0800) Subject: 3.10-stable patches X-Git-Tag: v4.4.6~6 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=091c62ea2b3be7fbc80da83be3d74777ebd4b5d3;p=thirdparty%2Fkernel%2Fstable-queue.git 3.10-stable patches added patches: modules-fix-longstanding-proc-kallsyms-vs-module-insertion-race.patch --- diff --git a/queue-3.10/modules-fix-longstanding-proc-kallsyms-vs-module-insertion-race.patch b/queue-3.10/modules-fix-longstanding-proc-kallsyms-vs-module-insertion-race.patch new file mode 100644 index 00000000000..3190d0680b0 --- /dev/null +++ b/queue-3.10/modules-fix-longstanding-proc-kallsyms-vs-module-insertion-race.patch @@ -0,0 +1,305 @@ +From 8244062ef1e54502ef55f54cced659913f244c3e Mon Sep 17 00:00:00 2001 +From: Rusty Russell +Date: Wed, 3 Feb 2016 16:55:26 +1030 +Subject: modules: fix longstanding /proc/kallsyms vs module insertion race. + +From: Rusty Russell + +commit 8244062ef1e54502ef55f54cced659913f244c3e upstream. + +For CONFIG_KALLSYMS, we keep two symbol tables and two string tables. +There's one full copy, marked SHF_ALLOC and laid out at the end of the +module's init section. There's also a cut-down version that only +contains core symbols and strings, and lives in the module's core +section. + +After module init (and before we free the module memory), we switch +the mod->symtab, mod->num_symtab and mod->strtab to point to the core +versions. We do this under the module_mutex. + +However, kallsyms doesn't take the module_mutex: it uses +preempt_disable() and rcu tricks to walk through the modules, because +it's used in the oops path. It's also used in /proc/kallsyms. +There's nothing atomic about the change of these variables, so we can +get the old (larger!) num_symtab and the new symtab pointer; in fact +this is what I saw when trying to reproduce. + +By grouping these variables together, we can use a +carefully-dereferenced pointer to ensure we always get one or the +other (the free of the module init section is already done in an RCU +callback, so that's safe). We allocate the init one at the end of the +module init section, and keep the core one inside the struct module +itself (it could also have been allocated at the end of the module +core, but that's probably overkill). + +[ Rebased for 4.4-stable and older, because the following changes aren't + in the older trees: + - e0224418516b4d8a6c2160574bac18447c354ef0: adds arg to is_core_symbol + - 7523e4dc5057e157212b4741abd6256e03404cf1: module_init/module_core/init_size/core_size + become init_layout.base/core_layout.base/init_layout.size/core_layout.size. + + Original commit: 8244062ef1e54502ef55f54cced659913f244c3e +] + +Reported-by: Weilong Chen +Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=111541 +Signed-off-by: Rusty Russell +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/module.h | 17 +++---- + kernel/module.c | 111 ++++++++++++++++++++++++++++++------------------- + 2 files changed, 78 insertions(+), 50 deletions(-) + +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -220,6 +220,12 @@ struct module_ref { + unsigned long decs; + } __attribute((aligned(2 * sizeof(unsigned long)))); + ++struct mod_kallsyms { ++ Elf_Sym *symtab; ++ unsigned int num_symtab; ++ char *strtab; ++}; ++ + struct module + { + enum module_state state; +@@ -308,14 +314,9 @@ struct module + #endif + + #ifdef CONFIG_KALLSYMS +- /* +- * We keep the symbol and string tables for kallsyms. +- * The core_* fields below are temporary, loader-only (they +- * could really be discarded after module init). +- */ +- Elf_Sym *symtab, *core_symtab; +- unsigned int num_symtab, core_num_syms; +- char *strtab, *core_strtab; ++ /* Protected by RCU and/or module_mutex: use rcu_dereference() */ ++ struct mod_kallsyms *kallsyms; ++ struct mod_kallsyms core_kallsyms; + + /* Section attributes */ + struct module_sect_attrs *sect_attrs; +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -179,6 +179,9 @@ struct load_info { + struct _ddebug *debug; + unsigned int num_debug; + bool sig_ok; ++#ifdef CONFIG_KALLSYMS ++ unsigned long mod_kallsyms_init_off; ++#endif + struct { + unsigned int sym, str, mod, vers, info, pcpu; + } index; +@@ -2346,8 +2349,20 @@ static void layout_symtab(struct module + strsect->sh_entsize = get_offset(mod, &mod->init_size, strsect, + info->index.str) | INIT_OFFSET_MASK; + pr_debug("\t%s\n", info->secstrings + strsect->sh_name); ++ ++ /* We'll tack temporary mod_kallsyms on the end. */ ++ mod->init_size = ALIGN(mod->init_size, ++ __alignof__(struct mod_kallsyms)); ++ info->mod_kallsyms_init_off = mod->init_size; ++ mod->init_size += sizeof(struct mod_kallsyms); ++ mod->init_size = debug_align(mod->init_size); + } + ++/* ++ * We use the full symtab and strtab which layout_symtab arranged to ++ * be appended to the init section. Later we switch to the cut-down ++ * core-only ones. ++ */ + static void add_kallsyms(struct module *mod, const struct load_info *info) + { + unsigned int i, ndst; +@@ -2356,28 +2371,33 @@ static void add_kallsyms(struct module * + char *s; + Elf_Shdr *symsec = &info->sechdrs[info->index.sym]; + +- mod->symtab = (void *)symsec->sh_addr; +- mod->num_symtab = symsec->sh_size / sizeof(Elf_Sym); ++ /* Set up to point into init section. */ ++ mod->kallsyms = mod->module_init + info->mod_kallsyms_init_off; ++ ++ mod->kallsyms->symtab = (void *)symsec->sh_addr; ++ mod->kallsyms->num_symtab = symsec->sh_size / sizeof(Elf_Sym); + /* Make sure we get permanent strtab: don't use info->strtab. */ +- mod->strtab = (void *)info->sechdrs[info->index.str].sh_addr; ++ mod->kallsyms->strtab = (void *)info->sechdrs[info->index.str].sh_addr; + + /* Set types up while we still have access to sections. */ +- for (i = 0; i < mod->num_symtab; i++) +- mod->symtab[i].st_info = elf_type(&mod->symtab[i], info); +- +- mod->core_symtab = dst = mod->module_core + info->symoffs; +- mod->core_strtab = s = mod->module_core + info->stroffs; +- src = mod->symtab; +- for (ndst = i = 0; i < mod->num_symtab; i++) { ++ for (i = 0; i < mod->kallsyms->num_symtab; i++) ++ mod->kallsyms->symtab[i].st_info ++ = elf_type(&mod->kallsyms->symtab[i], info); ++ ++ /* Now populate the cut down core kallsyms for after init. */ ++ mod->core_kallsyms.symtab = dst = mod->module_core + info->symoffs; ++ mod->core_kallsyms.strtab = s = mod->module_core + info->stroffs; ++ src = mod->kallsyms->symtab; ++ for (ndst = i = 0; i < mod->kallsyms->num_symtab; i++) { + if (i == 0 || + is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum)) { + dst[ndst] = src[i]; +- dst[ndst++].st_name = s - mod->core_strtab; +- s += strlcpy(s, &mod->strtab[src[i].st_name], ++ dst[ndst++].st_name = s - mod->core_kallsyms.strtab; ++ s += strlcpy(s, &mod->kallsyms->strtab[src[i].st_name], + KSYM_NAME_LEN) + 1; + } + } +- mod->core_num_syms = ndst; ++ mod->core_kallsyms.num_symtab = ndst; + } + #else + static inline void layout_symtab(struct module *mod, struct load_info *info) +@@ -3117,9 +3137,8 @@ static int do_init_module(struct module + module_put(mod); + trim_init_extable(mod); + #ifdef CONFIG_KALLSYMS +- mod->num_symtab = mod->core_num_syms; +- mod->symtab = mod->core_symtab; +- mod->strtab = mod->core_strtab; ++ /* Switch to core kallsyms now init is done: kallsyms may be walking! */ ++ rcu_assign_pointer(mod->kallsyms, &mod->core_kallsyms); + #endif + unset_module_init_ro_nx(mod); + module_free(mod, mod->module_init); +@@ -3398,9 +3417,9 @@ static inline int is_arm_mapping_symbol( + && (str[2] == '\0' || str[2] == '.'); + } + +-static const char *symname(struct module *mod, unsigned int symnum) ++static const char *symname(struct mod_kallsyms *kallsyms, unsigned int symnum) + { +- return mod->strtab + mod->symtab[symnum].st_name; ++ return kallsyms->strtab + kallsyms->symtab[symnum].st_name; + } + + static const char *get_ksymbol(struct module *mod, +@@ -3410,6 +3429,7 @@ static const char *get_ksymbol(struct mo + { + unsigned int i, best = 0; + unsigned long nextval; ++ struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms); + + /* At worse, next value is at end of module */ + if (within_module_init(addr, mod)) +@@ -3419,32 +3439,32 @@ static const char *get_ksymbol(struct mo + + /* Scan for closest preceding symbol, and next symbol. (ELF + starts real symbols at 1). */ +- for (i = 1; i < mod->num_symtab; i++) { +- if (mod->symtab[i].st_shndx == SHN_UNDEF) ++ for (i = 1; i < kallsyms->num_symtab; i++) { ++ if (kallsyms->symtab[i].st_shndx == SHN_UNDEF) + continue; + + /* We ignore unnamed symbols: they're uninformative + * and inserted at a whim. */ +- if (*symname(mod, i) == '\0' +- || is_arm_mapping_symbol(symname(mod, i))) ++ if (*symname(kallsyms, i) == '\0' ++ || is_arm_mapping_symbol(symname(kallsyms, i))) + continue; + +- if (mod->symtab[i].st_value <= addr +- && mod->symtab[i].st_value > mod->symtab[best].st_value) ++ if (kallsyms->symtab[i].st_value <= addr ++ && kallsyms->symtab[i].st_value > kallsyms->symtab[best].st_value) + best = i; +- if (mod->symtab[i].st_value > addr +- && mod->symtab[i].st_value < nextval) +- nextval = mod->symtab[i].st_value; ++ if (kallsyms->symtab[i].st_value > addr ++ && kallsyms->symtab[i].st_value < nextval) ++ nextval = kallsyms->symtab[i].st_value; + } + + if (!best) + return NULL; + + if (size) +- *size = nextval - mod->symtab[best].st_value; ++ *size = nextval - kallsyms->symtab[best].st_value; + if (offset) +- *offset = addr - mod->symtab[best].st_value; +- return symname(mod, best); ++ *offset = addr - kallsyms->symtab[best].st_value; ++ return symname(kallsyms, best); + } + + /* For kallsyms to ask for address resolution. NULL means not found. Careful +@@ -3540,18 +3560,21 @@ int module_get_kallsym(unsigned int symn + + preempt_disable(); + list_for_each_entry_rcu(mod, &modules, list) { ++ struct mod_kallsyms *kallsyms; ++ + if (mod->state == MODULE_STATE_UNFORMED) + continue; +- if (symnum < mod->num_symtab) { +- *value = mod->symtab[symnum].st_value; +- *type = mod->symtab[symnum].st_info; +- strlcpy(name, symname(mod, symnum), KSYM_NAME_LEN); ++ kallsyms = rcu_dereference_sched(mod->kallsyms); ++ if (symnum < kallsyms->num_symtab) { ++ *value = kallsyms->symtab[symnum].st_value; ++ *type = kallsyms->symtab[symnum].st_info; ++ strlcpy(name, symname(kallsyms, symnum), KSYM_NAME_LEN); + strlcpy(module_name, mod->name, MODULE_NAME_LEN); + *exported = is_exported(name, *value, mod); + preempt_enable(); + return 0; + } +- symnum -= mod->num_symtab; ++ symnum -= kallsyms->num_symtab; + } + preempt_enable(); + return -ERANGE; +@@ -3560,11 +3583,12 @@ int module_get_kallsym(unsigned int symn + static unsigned long mod_find_symname(struct module *mod, const char *name) + { + unsigned int i; ++ struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms); + +- for (i = 0; i < mod->num_symtab; i++) +- if (strcmp(name, symname(mod, i)) == 0 && +- mod->symtab[i].st_info != 'U') +- return mod->symtab[i].st_value; ++ for (i = 0; i < kallsyms->num_symtab; i++) ++ if (strcmp(name, symname(kallsyms, i)) == 0 && ++ kallsyms->symtab[i].st_info != 'U') ++ return kallsyms->symtab[i].st_value; + return 0; + } + +@@ -3603,11 +3627,14 @@ int module_kallsyms_on_each_symbol(int ( + int ret; + + list_for_each_entry(mod, &modules, list) { ++ /* We hold module_mutex: no need for rcu_dereference_sched */ ++ struct mod_kallsyms *kallsyms = mod->kallsyms; ++ + if (mod->state == MODULE_STATE_UNFORMED) + continue; +- for (i = 0; i < mod->num_symtab; i++) { +- ret = fn(data, symname(mod, i), +- mod, mod->symtab[i].st_value); ++ for (i = 0; i < kallsyms->num_symtab; i++) { ++ ret = fn(data, symname(kallsyms, i), ++ mod, kallsyms->symtab[i].st_value); + if (ret != 0) + return ret; + } diff --git a/queue-3.10/series b/queue-3.10/series index ee1138df5aa..db73240c870 100644 --- a/queue-3.10/series +++ b/queue-3.10/series @@ -15,3 +15,4 @@ efi-make-our-variable-validation-list-include-the-guid.patch efi-make-efivarfs-entries-immutable-by-default.patch efi-add-pstore-variables-to-the-deletion-whitelist.patch lib-ucs2_string-correct-ucs2-utf8-conversion.patch +modules-fix-longstanding-proc-kallsyms-vs-module-insertion-race.patch