diff options
| -rw-r--r-- | include/linux/stop_machine.h | 2 | ||||
| -rw-r--r-- | kernel/kallsyms.c | 16 | ||||
| -rw-r--r-- | kernel/module.c | 33 |
3 files changed, 40 insertions, 11 deletions
diff --git a/include/linux/stop_machine.h b/include/linux/stop_machine.h index 6f43cb53f21b..151a803ed0ed 100644 --- a/include/linux/stop_machine.h +++ b/include/linux/stop_machine.h @@ -8,7 +8,7 @@ #include <linux/cpu.h> #include <asm/system.h> -#ifdef CONFIG_SMP +#if defined(CONFIG_STOP_MACHINE) && defined(CONFIG_SMP) /** * stop_machine_run: freeze the machine on all CPUs and run this function * @fn: the function to run diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index bd765adaacd6..449306f696c5 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -146,13 +146,20 @@ unsigned long kallsyms_lookup_name(const char *name) return module_kallsyms_lookup_name(name); } -/* Lookup an address. modname is set to NULL if it's in the kernel. */ +/* + * Lookup an address + * - modname is set to NULL if it's in the kernel + * - we guarantee that the returned name is valid until we reschedule even if + * it resides in a module + * - we also guarantee that modname will be valid until rescheduled + */ const char *kallsyms_lookup(unsigned long addr, unsigned long *symbolsize, unsigned long *offset, char **modname, char *namebuf) { unsigned long i, low, high, mid; + const char *msym; /* This kernel should never had been booted. */ BUG_ON(!kallsyms_addresses); @@ -204,7 +211,12 @@ const char *kallsyms_lookup(unsigned long addr, return namebuf; } - return module_address_lookup(addr, symbolsize, offset, modname); + /* see if it's in a module */ + msym = module_address_lookup(addr, symbolsize, offset, modname); + if (msym) + return strncpy(namebuf, msym, KSYM_NAME_LEN); + + return NULL; } /* Replace "%s" in format with address, or returns -errno. */ diff --git a/kernel/module.c b/kernel/module.c index ce427b675b98..2dbfa0773faf 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -472,7 +472,7 @@ struct stopref }; /* Whole machine is stopped with interrupts off when this runs. */ -static inline int __try_stop_module(void *_sref) +static int __try_stop_module(void *_sref) { struct stopref *sref = _sref; @@ -1072,14 +1072,22 @@ static void mod_kobject_remove(struct module *mod) kobject_unregister(&mod->mkobj.kobj); } +/* + * unlink the module with the whole machine is stopped with interrupts off + * - this defends against kallsyms not taking locks + */ +static int __unlink_module(void *_mod) +{ + struct module *mod = _mod; + list_del(&mod->list); + return 0; +} + /* Free a module, remove from lists, etc (must hold module mutex). */ static void free_module(struct module *mod) { /* Delete from various lists */ - spin_lock_irq(&modlist_lock); - list_del(&mod->list); - spin_unlock_irq(&modlist_lock); - + stop_machine_run(__unlink_module, mod, NR_CPUS); remove_sect_attrs(mod); mod_kobject_remove(mod); @@ -1732,6 +1740,17 @@ static struct module *load_module(void __user *umod, goto free_hdr; } +/* + * link the module with the whole machine is stopped with interrupts off + * - this defends against kallsyms not taking locks + */ +static int __link_module(void *_mod) +{ + struct module *mod = _mod; + list_add(&mod->list, &modules); + return 0; +} + /* This is where the real work happens */ asmlinkage long sys_init_module(void __user *umod, @@ -1766,9 +1785,7 @@ sys_init_module(void __user *umod, /* Now sew it into the lists. They won't access us, since strong_try_module_get() will fail. */ - spin_lock_irq(&modlist_lock); - list_add(&mod->list, &modules); - spin_unlock_irq(&modlist_lock); + stop_machine_run(__link_module, mod, NR_CPUS); /* Drop lock so they can recurse */ up(&module_mutex); |
