diff options
author | Mathias Krause <minipli@googlemail.com> | 2013-07-02 02:05:11 -0400 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2013-07-02 02:08:18 -0400 |
commit | 4f6de4d51f4a3ab06a85e91e708cc89a513ef30c (patch) | |
tree | 2cf8819fc71e7ec6fef2fc2487954aabc6b8a730 /kernel/module.c | |
parent | 06df44ee41442d83be061c5fd1b1de4f5fc6fbbf (diff) |
module: don't modify argument of module_kallsyms_lookup_name()
If we pass a pointer to a const string in the form "module:symbol"
module_kallsyms_lookup_name() will try to split the string at the colon,
i.e., will try to modify r/o data. That will, in fact, fail on a kernel
with enabled CONFIG_DEBUG_RODATA.
Avoid modifying the passed string in module_kallsyms_lookup_name(),
modify find_module_all() instead to pass it the module name length.
Signed-off-by: Mathias Krause <minipli@googlemail.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'kernel/module.c')
-rw-r--r-- | kernel/module.c | 15 |
1 files changed, 7 insertions, 8 deletions
diff --git a/kernel/module.c b/kernel/module.c index b049939177f6..a1951aba7a03 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -455,7 +455,7 @@ const struct kernel_symbol *find_symbol(const char *name, | |||
455 | EXPORT_SYMBOL_GPL(find_symbol); | 455 | EXPORT_SYMBOL_GPL(find_symbol); |
456 | 456 | ||
457 | /* Search for module by name: must hold module_mutex. */ | 457 | /* Search for module by name: must hold module_mutex. */ |
458 | static struct module *find_module_all(const char *name, | 458 | static struct module *find_module_all(const char *name, size_t len, |
459 | bool even_unformed) | 459 | bool even_unformed) |
460 | { | 460 | { |
461 | struct module *mod; | 461 | struct module *mod; |
@@ -463,7 +463,7 @@ static struct module *find_module_all(const char *name, | |||
463 | list_for_each_entry(mod, &modules, list) { | 463 | list_for_each_entry(mod, &modules, list) { |
464 | if (!even_unformed && mod->state == MODULE_STATE_UNFORMED) | 464 | if (!even_unformed && mod->state == MODULE_STATE_UNFORMED) |
465 | continue; | 465 | continue; |
466 | if (strcmp(mod->name, name) == 0) | 466 | if (strlen(mod->name) == len && !memcmp(mod->name, name, len)) |
467 | return mod; | 467 | return mod; |
468 | } | 468 | } |
469 | return NULL; | 469 | return NULL; |
@@ -471,7 +471,7 @@ static struct module *find_module_all(const char *name, | |||
471 | 471 | ||
472 | struct module *find_module(const char *name) | 472 | struct module *find_module(const char *name) |
473 | { | 473 | { |
474 | return find_module_all(name, false); | 474 | return find_module_all(name, strlen(name), false); |
475 | } | 475 | } |
476 | EXPORT_SYMBOL_GPL(find_module); | 476 | EXPORT_SYMBOL_GPL(find_module); |
477 | 477 | ||
@@ -3027,7 +3027,7 @@ static bool finished_loading(const char *name) | |||
3027 | bool ret; | 3027 | bool ret; |
3028 | 3028 | ||
3029 | mutex_lock(&module_mutex); | 3029 | mutex_lock(&module_mutex); |
3030 | mod = find_module_all(name, true); | 3030 | mod = find_module_all(name, strlen(name), true); |
3031 | ret = !mod || mod->state == MODULE_STATE_LIVE | 3031 | ret = !mod || mod->state == MODULE_STATE_LIVE |
3032 | || mod->state == MODULE_STATE_GOING; | 3032 | || mod->state == MODULE_STATE_GOING; |
3033 | mutex_unlock(&module_mutex); | 3033 | mutex_unlock(&module_mutex); |
@@ -3165,7 +3165,8 @@ static int add_unformed_module(struct module *mod) | |||
3165 | 3165 | ||
3166 | again: | 3166 | again: |
3167 | mutex_lock(&module_mutex); | 3167 | mutex_lock(&module_mutex); |
3168 | if ((old = find_module_all(mod->name, true)) != NULL) { | 3168 | old = find_module_all(mod->name, strlen(mod->name), true); |
3169 | if (old != NULL) { | ||
3169 | if (old->state == MODULE_STATE_COMING | 3170 | if (old->state == MODULE_STATE_COMING |
3170 | || old->state == MODULE_STATE_UNFORMED) { | 3171 | || old->state == MODULE_STATE_UNFORMED) { |
3171 | /* Wait in case it fails to load. */ | 3172 | /* Wait in case it fails to load. */ |
@@ -3576,10 +3577,8 @@ unsigned long module_kallsyms_lookup_name(const char *name) | |||
3576 | /* Don't lock: we're in enough trouble already. */ | 3577 | /* Don't lock: we're in enough trouble already. */ |
3577 | preempt_disable(); | 3578 | preempt_disable(); |
3578 | if ((colon = strchr(name, ':')) != NULL) { | 3579 | if ((colon = strchr(name, ':')) != NULL) { |
3579 | *colon = '\0'; | 3580 | if ((mod = find_module_all(name, colon - name, false)) != NULL) |
3580 | if ((mod = find_module(name)) != NULL) | ||
3581 | ret = mod_find_symname(mod, colon+1); | 3581 | ret = mod_find_symname(mod, colon+1); |
3582 | *colon = ':'; | ||
3583 | } else { | 3582 | } else { |
3584 | list_for_each_entry_rcu(mod, &modules, list) { | 3583 | list_for_each_entry_rcu(mod, &modules, list) { |
3585 | if (mod->state == MODULE_STATE_UNFORMED) | 3584 | if (mod->state == MODULE_STATE_UNFORMED) |