Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus
* 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus: Module: check to see if we have a built in module with the same name module: add module taint on ndiswrapper module: fix the module name length in param_sysfs_builtin module: make module_address_lookup safe module: better OOPS and lockdep coverage for loading modules module: Fix gratuitous sprintf in module.c module: wait for dependent modules doing init. module: Don't report discarded init pages as kernel text.
This commit is contained in:
commit
03bc26cfef
|
@ -446,11 +446,14 @@ static inline void __module_get(struct module *module)
|
||||||
__mod ? __mod->name : "kernel"; \
|
__mod ? __mod->name : "kernel"; \
|
||||||
})
|
})
|
||||||
|
|
||||||
/* For kallsyms to ask for address resolution. NULL means not found. */
|
/* For kallsyms to ask for address resolution. namebuf should be at
|
||||||
const char *module_address_lookup(unsigned long addr,
|
* least KSYM_NAME_LEN long: a pointer to namebuf is returned if
|
||||||
unsigned long *symbolsize,
|
* found, otherwise NULL. */
|
||||||
unsigned long *offset,
|
char *module_address_lookup(unsigned long addr,
|
||||||
char **modname);
|
unsigned long *symbolsize,
|
||||||
|
unsigned long *offset,
|
||||||
|
char **modname,
|
||||||
|
char *namebuf);
|
||||||
int lookup_module_symbol_name(unsigned long addr, char *symname);
|
int lookup_module_symbol_name(unsigned long addr, char *symname);
|
||||||
int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name);
|
int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name);
|
||||||
|
|
||||||
|
@ -516,10 +519,11 @@ static inline void module_put(struct module *module)
|
||||||
#define module_name(mod) "kernel"
|
#define module_name(mod) "kernel"
|
||||||
|
|
||||||
/* For kallsyms to ask for address resolution. NULL means not found. */
|
/* For kallsyms to ask for address resolution. NULL means not found. */
|
||||||
static inline const char *module_address_lookup(unsigned long addr,
|
static inline char *module_address_lookup(unsigned long addr,
|
||||||
unsigned long *symbolsize,
|
unsigned long *symbolsize,
|
||||||
unsigned long *offset,
|
unsigned long *offset,
|
||||||
char **modname)
|
char **modname,
|
||||||
|
char *namebuf)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,8 @@ int core_kernel_text(unsigned long addr)
|
||||||
addr <= (unsigned long)_etext)
|
addr <= (unsigned long)_etext)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (addr >= (unsigned long)_sinittext &&
|
if (system_state == SYSTEM_BOOTING &&
|
||||||
|
addr >= (unsigned long)_sinittext &&
|
||||||
addr <= (unsigned long)_einittext)
|
addr <= (unsigned long)_einittext)
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -233,10 +233,11 @@ static unsigned long get_symbol_pos(unsigned long addr,
|
||||||
int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize,
|
int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize,
|
||||||
unsigned long *offset)
|
unsigned long *offset)
|
||||||
{
|
{
|
||||||
|
char namebuf[KSYM_NAME_LEN];
|
||||||
if (is_ksym_addr(addr))
|
if (is_ksym_addr(addr))
|
||||||
return !!get_symbol_pos(addr, symbolsize, offset);
|
return !!get_symbol_pos(addr, symbolsize, offset);
|
||||||
|
|
||||||
return !!module_address_lookup(addr, symbolsize, offset, NULL);
|
return !!module_address_lookup(addr, symbolsize, offset, NULL, namebuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -251,8 +252,6 @@ const char *kallsyms_lookup(unsigned long addr,
|
||||||
unsigned long *offset,
|
unsigned long *offset,
|
||||||
char **modname, char *namebuf)
|
char **modname, char *namebuf)
|
||||||
{
|
{
|
||||||
const char *msym;
|
|
||||||
|
|
||||||
namebuf[KSYM_NAME_LEN - 1] = 0;
|
namebuf[KSYM_NAME_LEN - 1] = 0;
|
||||||
namebuf[0] = 0;
|
namebuf[0] = 0;
|
||||||
|
|
||||||
|
@ -268,10 +267,8 @@ const char *kallsyms_lookup(unsigned long addr,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* see if it's in a module */
|
/* see if it's in a module */
|
||||||
msym = module_address_lookup(addr, symbolsize, offset, modname);
|
return module_address_lookup(addr, symbolsize, offset, modname,
|
||||||
if (msym)
|
namebuf);
|
||||||
return strncpy(namebuf, msym, KSYM_NAME_LEN - 1);
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
102
kernel/module.c
102
kernel/module.c
|
@ -65,6 +65,9 @@
|
||||||
static DEFINE_MUTEX(module_mutex);
|
static DEFINE_MUTEX(module_mutex);
|
||||||
static LIST_HEAD(modules);
|
static LIST_HEAD(modules);
|
||||||
|
|
||||||
|
/* Waiting for a module to finish initializing? */
|
||||||
|
static DECLARE_WAIT_QUEUE_HEAD(module_wq);
|
||||||
|
|
||||||
static BLOCKING_NOTIFIER_HEAD(module_notify_list);
|
static BLOCKING_NOTIFIER_HEAD(module_notify_list);
|
||||||
|
|
||||||
int register_module_notifier(struct notifier_block * nb)
|
int register_module_notifier(struct notifier_block * nb)
|
||||||
|
@ -84,8 +87,11 @@ EXPORT_SYMBOL(unregister_module_notifier);
|
||||||
static inline int strong_try_module_get(struct module *mod)
|
static inline int strong_try_module_get(struct module *mod)
|
||||||
{
|
{
|
||||||
if (mod && mod->state == MODULE_STATE_COMING)
|
if (mod && mod->state == MODULE_STATE_COMING)
|
||||||
|
return -EBUSY;
|
||||||
|
if (try_module_get(mod))
|
||||||
return 0;
|
return 0;
|
||||||
return try_module_get(mod);
|
else
|
||||||
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void add_taint_module(struct module *mod, unsigned flag)
|
static inline void add_taint_module(struct module *mod, unsigned flag)
|
||||||
|
@ -539,11 +545,21 @@ static int already_uses(struct module *a, struct module *b)
|
||||||
static int use_module(struct module *a, struct module *b)
|
static int use_module(struct module *a, struct module *b)
|
||||||
{
|
{
|
||||||
struct module_use *use;
|
struct module_use *use;
|
||||||
int no_warn;
|
int no_warn, err;
|
||||||
|
|
||||||
if (b == NULL || already_uses(a, b)) return 1;
|
if (b == NULL || already_uses(a, b)) return 1;
|
||||||
|
|
||||||
if (!strong_try_module_get(b))
|
/* If we're interrupted or time out, we fail. */
|
||||||
|
if (wait_event_interruptible_timeout(
|
||||||
|
module_wq, (err = strong_try_module_get(b)) != -EBUSY,
|
||||||
|
30 * HZ) <= 0) {
|
||||||
|
printk("%s: gave up waiting for init of module %s.\n",
|
||||||
|
a->name, b->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If strong_try_module_get() returned a different error, we fail. */
|
||||||
|
if (err)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
DEBUGP("Allocating new usage for %s.\n", a->name);
|
DEBUGP("Allocating new usage for %s.\n", a->name);
|
||||||
|
@ -722,7 +738,7 @@ sys_delete_module(const char __user *name_user, unsigned int flags)
|
||||||
mutex_lock(&module_mutex);
|
mutex_lock(&module_mutex);
|
||||||
}
|
}
|
||||||
/* Store the name of the last unloaded module for diagnostic purposes */
|
/* Store the name of the last unloaded module for diagnostic purposes */
|
||||||
sprintf(last_unloaded_module, mod->name);
|
strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module));
|
||||||
free_module(mod);
|
free_module(mod);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -816,7 +832,7 @@ static inline void module_unload_free(struct module *mod)
|
||||||
|
|
||||||
static inline int use_module(struct module *a, struct module *b)
|
static inline int use_module(struct module *a, struct module *b)
|
||||||
{
|
{
|
||||||
return strong_try_module_get(b);
|
return strong_try_module_get(b) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void module_unload_init(struct module *mod)
|
static inline void module_unload_init(struct module *mod)
|
||||||
|
@ -1214,6 +1230,7 @@ void module_remove_modinfo_attrs(struct module *mod)
|
||||||
int mod_sysfs_init(struct module *mod)
|
int mod_sysfs_init(struct module *mod)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
struct kobject *kobj;
|
||||||
|
|
||||||
if (!module_sysfs_initialized) {
|
if (!module_sysfs_initialized) {
|
||||||
printk(KERN_ERR "%s: module sysfs not initialized\n",
|
printk(KERN_ERR "%s: module sysfs not initialized\n",
|
||||||
|
@ -1221,6 +1238,15 @@ int mod_sysfs_init(struct module *mod)
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kobj = kset_find_obj(module_kset, mod->name);
|
||||||
|
if (kobj) {
|
||||||
|
printk(KERN_ERR "%s: module is already loaded\n", mod->name);
|
||||||
|
kobject_put(kobj);
|
||||||
|
err = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
mod->mkobj.mod = mod;
|
mod->mkobj.mod = mod;
|
||||||
|
|
||||||
memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj));
|
memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj));
|
||||||
|
@ -1277,6 +1303,17 @@ static void mod_kobject_remove(struct module *mod)
|
||||||
kobject_put(&mod->mkobj.kobj);
|
kobject_put(&mod->mkobj.kobj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* unlink the module with the whole machine is stopped with interrupts off
|
* unlink the module with the whole machine is stopped with interrupts off
|
||||||
* - this defends against kallsyms not taking locks
|
* - this defends against kallsyms not taking locks
|
||||||
|
@ -1326,7 +1363,7 @@ void *__symbol_get(const char *symbol)
|
||||||
|
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
value = __find_symbol(symbol, &owner, &crc, 1);
|
value = __find_symbol(symbol, &owner, &crc, 1);
|
||||||
if (value && !strong_try_module_get(owner))
|
if (value && strong_try_module_get(owner) != 0)
|
||||||
value = 0;
|
value = 0;
|
||||||
preempt_enable();
|
preempt_enable();
|
||||||
|
|
||||||
|
@ -1889,7 +1926,7 @@ static struct module *load_module(void __user *umod,
|
||||||
set_license(mod, get_modinfo(sechdrs, infoindex, "license"));
|
set_license(mod, get_modinfo(sechdrs, infoindex, "license"));
|
||||||
|
|
||||||
if (strcmp(mod->name, "ndiswrapper") == 0)
|
if (strcmp(mod->name, "ndiswrapper") == 0)
|
||||||
add_taint(TAINT_PROPRIETARY_MODULE);
|
add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
|
||||||
if (strcmp(mod->name, "driverloader") == 0)
|
if (strcmp(mod->name, "driverloader") == 0)
|
||||||
add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
|
add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
|
||||||
|
|
||||||
|
@ -2019,6 +2056,11 @@ static struct module *load_module(void __user *umod,
|
||||||
printk(KERN_WARNING "%s: Ignoring obsolete parameters\n",
|
printk(KERN_WARNING "%s: Ignoring obsolete parameters\n",
|
||||||
mod->name);
|
mod->name);
|
||||||
|
|
||||||
|
/* Now sew it into the lists so we can get lockdep and oops
|
||||||
|
* info during argument parsing. Noone should access us, since
|
||||||
|
* strong_try_module_get() will fail. */
|
||||||
|
stop_machine_run(__link_module, mod, NR_CPUS);
|
||||||
|
|
||||||
/* Size of section 0 is 0, so this works well if no params */
|
/* Size of section 0 is 0, so this works well if no params */
|
||||||
err = parse_args(mod->name, mod->args,
|
err = parse_args(mod->name, mod->args,
|
||||||
(struct kernel_param *)
|
(struct kernel_param *)
|
||||||
|
@ -2027,7 +2069,7 @@ static struct module *load_module(void __user *umod,
|
||||||
/ sizeof(struct kernel_param),
|
/ sizeof(struct kernel_param),
|
||||||
NULL);
|
NULL);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto arch_cleanup;
|
goto unlink;
|
||||||
|
|
||||||
err = mod_sysfs_setup(mod,
|
err = mod_sysfs_setup(mod,
|
||||||
(struct kernel_param *)
|
(struct kernel_param *)
|
||||||
|
@ -2035,7 +2077,7 @@ static struct module *load_module(void __user *umod,
|
||||||
sechdrs[setupindex].sh_size
|
sechdrs[setupindex].sh_size
|
||||||
/ sizeof(struct kernel_param));
|
/ sizeof(struct kernel_param));
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto arch_cleanup;
|
goto unlink;
|
||||||
add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
|
add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
|
||||||
add_notes_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
|
add_notes_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
|
||||||
|
|
||||||
|
@ -2050,7 +2092,8 @@ static struct module *load_module(void __user *umod,
|
||||||
/* Done! */
|
/* Done! */
|
||||||
return mod;
|
return mod;
|
||||||
|
|
||||||
arch_cleanup:
|
unlink:
|
||||||
|
stop_machine_run(__unlink_module, mod, NR_CPUS);
|
||||||
module_arch_cleanup(mod);
|
module_arch_cleanup(mod);
|
||||||
cleanup:
|
cleanup:
|
||||||
kobject_del(&mod->mkobj.kobj);
|
kobject_del(&mod->mkobj.kobj);
|
||||||
|
@ -2075,17 +2118,6 @@ static struct module *load_module(void __user *umod,
|
||||||
goto free_hdr;
|
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 */
|
/* This is where the real work happens */
|
||||||
asmlinkage long
|
asmlinkage long
|
||||||
sys_init_module(void __user *umod,
|
sys_init_module(void __user *umod,
|
||||||
|
@ -2110,10 +2142,6 @@ sys_init_module(void __user *umod,
|
||||||
return PTR_ERR(mod);
|
return PTR_ERR(mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now sew it into the lists. They won't access us, since
|
|
||||||
strong_try_module_get() will fail. */
|
|
||||||
stop_machine_run(__link_module, mod, NR_CPUS);
|
|
||||||
|
|
||||||
/* Drop lock so they can recurse */
|
/* Drop lock so they can recurse */
|
||||||
mutex_unlock(&module_mutex);
|
mutex_unlock(&module_mutex);
|
||||||
|
|
||||||
|
@ -2132,6 +2160,7 @@ sys_init_module(void __user *umod,
|
||||||
mutex_lock(&module_mutex);
|
mutex_lock(&module_mutex);
|
||||||
free_module(mod);
|
free_module(mod);
|
||||||
mutex_unlock(&module_mutex);
|
mutex_unlock(&module_mutex);
|
||||||
|
wake_up(&module_wq);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2146,6 +2175,7 @@ sys_init_module(void __user *umod,
|
||||||
mod->init_size = 0;
|
mod->init_size = 0;
|
||||||
mod->init_text_size = 0;
|
mod->init_text_size = 0;
|
||||||
mutex_unlock(&module_mutex);
|
mutex_unlock(&module_mutex);
|
||||||
|
wake_up(&module_wq);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2210,14 +2240,13 @@ static const char *get_ksymbol(struct module *mod,
|
||||||
return mod->strtab + mod->symtab[best].st_name;
|
return mod->strtab + mod->symtab[best].st_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For kallsyms to ask for address resolution. NULL means not found.
|
/* For kallsyms to ask for address resolution. NULL means not found. Careful
|
||||||
We don't lock, as this is used for oops resolution and races are a
|
* not to lock to avoid deadlock on oopses, simply disable preemption. */
|
||||||
lesser concern. */
|
char *module_address_lookup(unsigned long addr,
|
||||||
/* FIXME: Risky: returns a pointer into a module w/o lock */
|
unsigned long *size,
|
||||||
const char *module_address_lookup(unsigned long addr,
|
unsigned long *offset,
|
||||||
unsigned long *size,
|
char **modname,
|
||||||
unsigned long *offset,
|
char *namebuf)
|
||||||
char **modname)
|
|
||||||
{
|
{
|
||||||
struct module *mod;
|
struct module *mod;
|
||||||
const char *ret = NULL;
|
const char *ret = NULL;
|
||||||
|
@ -2232,8 +2261,13 @@ const char *module_address_lookup(unsigned long addr,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* Make a copy in here where it's safe */
|
||||||
|
if (ret) {
|
||||||
|
strncpy(namebuf, ret, KSYM_NAME_LEN - 1);
|
||||||
|
ret = namebuf;
|
||||||
|
}
|
||||||
preempt_enable();
|
preempt_enable();
|
||||||
return ret;
|
return (char *)ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lookup_module_symbol_name(unsigned long addr, char *symname)
|
int lookup_module_symbol_name(unsigned long addr, char *symname)
|
||||||
|
|
|
@ -376,8 +376,6 @@ int param_get_string(char *buffer, struct kernel_param *kp)
|
||||||
|
|
||||||
extern struct kernel_param __start___param[], __stop___param[];
|
extern struct kernel_param __start___param[], __stop___param[];
|
||||||
|
|
||||||
#define MAX_KBUILD_MODNAME KOBJ_NAME_LEN
|
|
||||||
|
|
||||||
struct param_attribute
|
struct param_attribute
|
||||||
{
|
{
|
||||||
struct module_attribute mattr;
|
struct module_attribute mattr;
|
||||||
|
@ -587,7 +585,7 @@ static void __init param_sysfs_builtin(void)
|
||||||
{
|
{
|
||||||
struct kernel_param *kp, *kp_begin = NULL;
|
struct kernel_param *kp, *kp_begin = NULL;
|
||||||
unsigned int i, name_len, count = 0;
|
unsigned int i, name_len, count = 0;
|
||||||
char modname[MAX_KBUILD_MODNAME + 1] = "";
|
char modname[MODULE_NAME_LEN + 1] = "";
|
||||||
|
|
||||||
for (i=0; i < __stop___param - __start___param; i++) {
|
for (i=0; i < __stop___param - __start___param; i++) {
|
||||||
char *dot;
|
char *dot;
|
||||||
|
@ -595,12 +593,12 @@ static void __init param_sysfs_builtin(void)
|
||||||
|
|
||||||
kp = &__start___param[i];
|
kp = &__start___param[i];
|
||||||
max_name_len =
|
max_name_len =
|
||||||
min_t(size_t, MAX_KBUILD_MODNAME, strlen(kp->name));
|
min_t(size_t, MODULE_NAME_LEN, strlen(kp->name));
|
||||||
|
|
||||||
dot = memchr(kp->name, '.', max_name_len);
|
dot = memchr(kp->name, '.', max_name_len);
|
||||||
if (!dot) {
|
if (!dot) {
|
||||||
DEBUGP("couldn't find period in first %d characters "
|
DEBUGP("couldn't find period in first %d characters "
|
||||||
"of %s\n", MAX_KBUILD_MODNAME, kp->name);
|
"of %s\n", MODULE_NAME_LEN, kp->name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
name_len = dot - kp->name;
|
name_len = dot - kp->name;
|
||||||
|
|
Loading…
Reference in New Issue