aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2010-06-05 13:17:37 -0400
committerRusty Russell <rusty@rustcorp.com.au>2010-06-04 21:47:37 -0400
commitbe593f4ce4eb1bd40e38fdc403371f149f6f12eb (patch)
tree693aee53e2d87a8ae92b6276d2aef766e8154814
parent3bafeb6247042dcbb72b0141ec7c7107de9f0b99 (diff)
module: verify_export_symbols under the lock
It disabled preempt so it was "safe", but nothing stops another module slipping in before this module is added to the global list now we don't hold the lock the whole time. So we check this just after we check for duplicate modules, and just before we put the module in the global list. (find_symbol finds symbols in coming and going modules, too). Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
-rw-r--r--kernel/module.c26
1 files changed, 10 insertions, 16 deletions
diff --git a/kernel/module.c b/kernel/module.c
index 28450047852a..f99558e1945a 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1571,6 +1571,8 @@ EXPORT_SYMBOL_GPL(__symbol_get);
1571/* 1571/*
1572 * Ensure that an exported symbol [global namespace] does not already exist 1572 * Ensure that an exported symbol [global namespace] does not already exist
1573 * in the kernel or in some other module's exported symbol table. 1573 * in the kernel or in some other module's exported symbol table.
1574 *
1575 * You must hold the module_mutex.
1574 */ 1576 */
1575static int verify_export_symbols(struct module *mod) 1577static int verify_export_symbols(struct module *mod)
1576{ 1578{
@@ -1592,14 +1594,7 @@ static int verify_export_symbols(struct module *mod)
1592 1594
1593 for (i = 0; i < ARRAY_SIZE(arr); i++) { 1595 for (i = 0; i < ARRAY_SIZE(arr); i++) {
1594 for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) { 1596 for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) {
1595 const struct kernel_symbol *sym; 1597 if (find_symbol(s->name, &owner, NULL, true, false)) {
1596
1597 /* Stopping preemption makes find_symbol safe. */
1598 preempt_disable();
1599 sym = find_symbol(s->name, &owner, NULL, true, false);
1600 preempt_enable();
1601
1602 if (sym) {
1603 printk(KERN_ERR 1598 printk(KERN_ERR
1604 "%s: exports duplicate symbol %s" 1599 "%s: exports duplicate symbol %s"
1605 " (owned by %s)\n", 1600 " (owned by %s)\n",
@@ -2440,11 +2435,6 @@ static noinline struct module *load_module(void __user *umod,
2440 goto cleanup; 2435 goto cleanup;
2441 } 2436 }
2442 2437
2443 /* Find duplicate symbols */
2444 err = verify_export_symbols(mod);
2445 if (err < 0)
2446 goto cleanup;
2447
2448 /* Set up and sort exception table */ 2438 /* Set up and sort exception table */
2449 mod->extable = section_objs(hdr, sechdrs, secstrings, "__ex_table", 2439 mod->extable = section_objs(hdr, sechdrs, secstrings, "__ex_table",
2450 sizeof(*mod->extable), &mod->num_exentries); 2440 sizeof(*mod->extable), &mod->num_exentries);
@@ -2506,10 +2496,14 @@ static noinline struct module *load_module(void __user *umod,
2506 mutex_lock(&module_mutex); 2496 mutex_lock(&module_mutex);
2507 if (find_module(mod->name)) { 2497 if (find_module(mod->name)) {
2508 err = -EEXIST; 2498 err = -EEXIST;
2509 /* This will also unlock the mutex */ 2499 goto unlock;
2510 goto already_exists;
2511 } 2500 }
2512 2501
2502 /* Find duplicate symbols */
2503 err = verify_export_symbols(mod);
2504 if (err < 0)
2505 goto unlock;
2506
2513 list_add_rcu(&mod->list, &modules); 2507 list_add_rcu(&mod->list, &modules);
2514 mutex_unlock(&module_mutex); 2508 mutex_unlock(&module_mutex);
2515 2509
@@ -2536,7 +2530,7 @@ static noinline struct module *load_module(void __user *umod,
2536 mutex_lock(&module_mutex); 2530 mutex_lock(&module_mutex);
2537 /* Unlink carefully: kallsyms could be walking list. */ 2531 /* Unlink carefully: kallsyms could be walking list. */
2538 list_del_rcu(&mod->list); 2532 list_del_rcu(&mod->list);
2539 already_exists: 2533 unlock:
2540 mutex_unlock(&module_mutex); 2534 mutex_unlock(&module_mutex);
2541 synchronize_sched(); 2535 synchronize_sched();
2542 module_arch_cleanup(mod); 2536 module_arch_cleanup(mod);