aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2009-03-31 15:05:29 -0400
committerRusty Russell <rusty@rustcorp.com.au>2009-03-30 22:35:30 -0400
commite180a6b7759a99a28cbcce3547c4c80822cb6c2a (patch)
treed52b950935f3192d13bdd4ad9377b39bab21325e
parent15f7176eb1cccec0a332541285ee752b935c1c85 (diff)
param: fix charp parameters set via sysfs
Impact: fix crash on reading from /sys/module/.../ieee80211_default_rc_algo The module_param type "charp" simply sets a char * pointer in the module to the parameter in the commandline string: this is why we keep the (mangled) module command line around. But when set via sysfs (as about 11 charp parameters can be) this memory is freed on the way out of the write(). Future reads hit random mem. So we kstrdup instead: we have to check we're not in early commandline parsing, and we have to note when we've used it so we can reliably kfree the parameter when it's next overwritten, and also on module unload. (Thanks to Randy Dunlap for CONFIG_SYSFS=n fixes) Reported-by: Sitsofe Wheeler <sitsofe@yahoo.com> Diagnosed-by: Frederic Weisbecker <fweisbec@gmail.com> Tested-by: Frederic Weisbecker <fweisbec@gmail.com> Tested-by: Christof Schmitt <christof.schmitt@de.ibm.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
-rw-r--r--include/linux/module.h4
-rw-r--r--include/linux/moduleparam.h10
-rw-r--r--kernel/module.c14
-rw-r--r--kernel/params.c26
4 files changed, 47 insertions, 7 deletions
diff --git a/include/linux/module.h b/include/linux/module.h
index 145a75528cc1..08e5e75d6122 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -248,6 +248,10 @@ struct module
248 const unsigned long *crcs; 248 const unsigned long *crcs;
249 unsigned int num_syms; 249 unsigned int num_syms;
250 250
251 /* Kernel parameters. */
252 struct kernel_param *kp;
253 unsigned int num_kp;
254
251 /* GPL-only exported symbols. */ 255 /* GPL-only exported symbols. */
252 unsigned int num_gpl_syms; 256 unsigned int num_gpl_syms;
253 const struct kernel_symbol *gpl_syms; 257 const struct kernel_symbol *gpl_syms;
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h
index e4af3399ef48..a4f0b931846c 100644
--- a/include/linux/moduleparam.h
+++ b/include/linux/moduleparam.h
@@ -138,6 +138,16 @@ extern int parse_args(const char *name,
138 unsigned num, 138 unsigned num,
139 int (*unknown)(char *param, char *val)); 139 int (*unknown)(char *param, char *val));
140 140
141/* Called by module remove. */
142#ifdef CONFIG_SYSFS
143extern void destroy_params(const struct kernel_param *params, unsigned num);
144#else
145static inline void destroy_params(const struct kernel_param *params,
146 unsigned num)
147{
148}
149#endif /* !CONFIG_SYSFS */
150
141/* All the helper functions */ 151/* All the helper functions */
142/* The macros to do compile-time type checking stolen from Jakub 152/* The macros to do compile-time type checking stolen from Jakub
143 Jelinek, who IIRC came up with this idea for the 2.4 module init code. */ 153 Jelinek, who IIRC came up with this idea for the 2.4 module init code. */
diff --git a/kernel/module.c b/kernel/module.c
index f77ac320d0b5..b862fdb6a372 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1491,6 +1491,9 @@ static void free_module(struct module *mod)
1491 /* Module unload stuff */ 1491 /* Module unload stuff */
1492 module_unload_free(mod); 1492 module_unload_free(mod);
1493 1493
1494 /* Free any allocated parameters. */
1495 destroy_params(mod->kp, mod->num_kp);
1496
1494 /* release any pointers to mcount in this module */ 1497 /* release any pointers to mcount in this module */
1495 ftrace_release(mod->module_core, mod->core_size); 1498 ftrace_release(mod->module_core, mod->core_size);
1496 1499
@@ -1898,8 +1901,7 @@ static noinline struct module *load_module(void __user *umod,
1898 unsigned int symindex = 0; 1901 unsigned int symindex = 0;
1899 unsigned int strindex = 0; 1902 unsigned int strindex = 0;
1900 unsigned int modindex, versindex, infoindex, pcpuindex; 1903 unsigned int modindex, versindex, infoindex, pcpuindex;
1901 unsigned int num_kp, num_mcount; 1904 unsigned int num_mcount;
1902 struct kernel_param *kp;
1903 struct module *mod; 1905 struct module *mod;
1904 long err = 0; 1906 long err = 0;
1905 void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ 1907 void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
@@ -2144,8 +2146,8 @@ static noinline struct module *load_module(void __user *umod,
2144 2146
2145 /* Now we've got everything in the final locations, we can 2147 /* Now we've got everything in the final locations, we can
2146 * find optional sections. */ 2148 * find optional sections. */
2147 kp = section_objs(hdr, sechdrs, secstrings, "__param", sizeof(*kp), 2149 mod->kp = section_objs(hdr, sechdrs, secstrings, "__param",
2148 &num_kp); 2150 sizeof(*mod->kp), &mod->num_kp);
2149 mod->syms = section_objs(hdr, sechdrs, secstrings, "__ksymtab", 2151 mod->syms = section_objs(hdr, sechdrs, secstrings, "__ksymtab",
2150 sizeof(*mod->syms), &mod->num_syms); 2152 sizeof(*mod->syms), &mod->num_syms);
2151 mod->crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab"); 2153 mod->crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab");
@@ -2291,11 +2293,11 @@ static noinline struct module *load_module(void __user *umod,
2291 */ 2293 */
2292 list_add_rcu(&mod->list, &modules); 2294 list_add_rcu(&mod->list, &modules);
2293 2295
2294 err = parse_args(mod->name, mod->args, kp, num_kp, NULL); 2296 err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, NULL);
2295 if (err < 0) 2297 if (err < 0)
2296 goto unlink; 2298 goto unlink;
2297 2299
2298 err = mod_sysfs_setup(mod, kp, num_kp); 2300 err = mod_sysfs_setup(mod, mod->kp, mod->num_kp);
2299 if (err < 0) 2301 if (err < 0)
2300 goto unlink; 2302 goto unlink;
2301 add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs); 2303 add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
diff --git a/kernel/params.c b/kernel/params.c
index a1e3025b19a9..de273ec85bd2 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -24,6 +24,9 @@
24#include <linux/err.h> 24#include <linux/err.h>
25#include <linux/slab.h> 25#include <linux/slab.h>
26 26
27/* We abuse the high bits of "perm" to record whether we kmalloc'ed. */
28#define KPARAM_KMALLOCED 0x80000000
29
27#if 0 30#if 0
28#define DEBUGP printk 31#define DEBUGP printk
29#else 32#else
@@ -217,7 +220,19 @@ int param_set_charp(const char *val, struct kernel_param *kp)
217 return -ENOSPC; 220 return -ENOSPC;
218 } 221 }
219 222
220 *(char **)kp->arg = (char *)val; 223 if (kp->perm & KPARAM_KMALLOCED)
224 kfree(*(char **)kp->arg);
225
226 /* This is a hack. We can't need to strdup in early boot, and we
227 * don't need to; this mangled commandline is preserved. */
228 if (slab_is_available()) {
229 kp->perm |= KPARAM_KMALLOCED;
230 *(char **)kp->arg = kstrdup(val, GFP_KERNEL);
231 if (!kp->arg)
232 return -ENOMEM;
233 } else
234 *(const char **)kp->arg = val;
235
221 return 0; 236 return 0;
222} 237}
223 238
@@ -571,6 +586,15 @@ void module_param_sysfs_remove(struct module *mod)
571} 586}
572#endif 587#endif
573 588
589void destroy_params(const struct kernel_param *params, unsigned num)
590{
591 unsigned int i;
592
593 for (i = 0; i < num; i++)
594 if (params[i].perm & KPARAM_KMALLOCED)
595 kfree(*(char **)params[i].arg);
596}
597
574static void __init kernel_add_sysfs_param(const char *name, 598static void __init kernel_add_sysfs_param(const char *name,
575 struct kernel_param *kparam, 599 struct kernel_param *kparam,
576 unsigned int name_skip) 600 unsigned int name_skip)