X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=kernel%2Fmodule.c;fp=kernel%2Fmodule.c;h=5aad477ddc79c94567c02e9ee704f1eb71fa1b66;hb=64ba3f394c830ec48a1c31b53dcae312c56f1604;hp=f9a59874edddc39bb4e6e18564a5b27cd7bbf56b;hpb=be1e6109ac94a859551f8e1774eb9a8469fe055c;p=linux-2.6.git diff --git a/kernel/module.c b/kernel/module.c index f9a59874e..5aad477dd 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1,4 +1,4 @@ -/* +/* Rewritten by Rusty Russell, on the backs of many others... Copyright (C) 2002 Richard Henderson Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM. @@ -16,6 +16,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include #include #include @@ -38,13 +39,9 @@ #include #include #include -#include -#include #include #include #include -#include -#include "module-verify.h" #if 0 #define DEBUGP printk @@ -63,20 +60,29 @@ static DEFINE_SPINLOCK(modlist_lock); /* List of modules, protected by module_mutex AND modlist_lock */ -static DEFINE_MUTEX(module_mutex); +static DECLARE_MUTEX(module_mutex); static LIST_HEAD(modules); -static BLOCKING_NOTIFIER_HEAD(module_notify_list); +static DECLARE_MUTEX(notify_mutex); +static struct notifier_block * module_notify_list; int register_module_notifier(struct notifier_block * nb) { - return blocking_notifier_chain_register(&module_notify_list, nb); + int err; + down(¬ify_mutex); + err = notifier_chain_register(&module_notify_list, nb); + up(¬ify_mutex); + return err; } EXPORT_SYMBOL(register_module_notifier); int unregister_module_notifier(struct notifier_block * nb) { - return blocking_notifier_chain_unregister(&module_notify_list, nb); + int err; + down(¬ify_mutex); + err = notifier_chain_unregister(&module_notify_list, nb); + up(¬ify_mutex); + return err; } EXPORT_SYMBOL(unregister_module_notifier); @@ -120,49 +126,15 @@ extern const struct kernel_symbol __start___ksymtab[]; extern const struct kernel_symbol __stop___ksymtab[]; extern const struct kernel_symbol __start___ksymtab_gpl[]; extern const struct kernel_symbol __stop___ksymtab_gpl[]; -extern const struct kernel_symbol __start___ksymtab_gpl_future[]; -extern const struct kernel_symbol __stop___ksymtab_gpl_future[]; -extern const struct kernel_symbol __start___ksymtab_unused[]; -extern const struct kernel_symbol __stop___ksymtab_unused[]; -extern const struct kernel_symbol __start___ksymtab_unused_gpl[]; -extern const struct kernel_symbol __stop___ksymtab_unused_gpl[]; -extern const struct kernel_symbol __start___ksymtab_gpl_future[]; -extern const struct kernel_symbol __stop___ksymtab_gpl_future[]; extern const unsigned long __start___kcrctab[]; extern const unsigned long __start___kcrctab_gpl[]; -extern const unsigned long __start___kcrctab_gpl_future[]; -extern const unsigned long __start___kcrctab_unused[]; -extern const unsigned long __start___kcrctab_unused_gpl[]; #ifndef CONFIG_MODVERSIONS #define symversion(base, idx) NULL #else -#define symversion(base, idx) ((base != NULL) ? ((base) + (idx)) : NULL) +#define symversion(base, idx) ((base) ? ((base) + (idx)) : NULL) #endif -/* lookup symbol in given range of kernel_symbols */ -static const struct kernel_symbol *lookup_symbol(const char *name, - const struct kernel_symbol *start, - const struct kernel_symbol *stop) -{ - const struct kernel_symbol *ks = start; - for (; ks < stop; ks++) - if (strcmp(ks->name, name) == 0) - return ks; - return NULL; -} - -static void printk_unused_warning(const char *name) -{ - printk(KERN_WARNING "Symbol %s is marked as UNUSED, " - "however this module is using it.\n", name); - printk(KERN_WARNING "This symbol will go away in the future.\n"); - printk(KERN_WARNING "Please evalute if this is the right api to use, " - "and if it really is, submit a report the linux kernel " - "mailinglist together with submitting your code for " - "inclusion.\n"); -} - /* Find a symbol, return value, crc and module which owns it */ static unsigned long __find_symbol(const char *name, struct module **owner, @@ -170,117 +142,64 @@ static unsigned long __find_symbol(const char *name, int gplok) { struct module *mod; - const struct kernel_symbol *ks; + unsigned int i; /* Core kernel first. */ *owner = NULL; - ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab); - if (ks) { - *crc = symversion(__start___kcrctab, (ks - __start___ksymtab)); - return ks->value; - } - if (gplok) { - ks = lookup_symbol(name, __start___ksymtab_gpl, - __stop___ksymtab_gpl); - if (ks) { - *crc = symversion(__start___kcrctab_gpl, - (ks - __start___ksymtab_gpl)); - return ks->value; - } - } - ks = lookup_symbol(name, __start___ksymtab_gpl_future, - __stop___ksymtab_gpl_future); - if (ks) { - if (!gplok) { - printk(KERN_WARNING "Symbol %s is being used " - "by a non-GPL module, which will not " - "be allowed in the future\n", name); - printk(KERN_WARNING "Please see the file " - "Documentation/feature-removal-schedule.txt " - "in the kernel source tree for more " - "details.\n"); + for (i = 0; __start___ksymtab+i < __stop___ksymtab; i++) { + if (strcmp(__start___ksymtab[i].name, name) == 0) { + *crc = symversion(__start___kcrctab, i); + return __start___ksymtab[i].value; } - *crc = symversion(__start___kcrctab_gpl_future, - (ks - __start___ksymtab_gpl_future)); - return ks->value; } - - ks = lookup_symbol(name, __start___ksymtab_unused, - __stop___ksymtab_unused); - if (ks) { - printk_unused_warning(name); - *crc = symversion(__start___kcrctab_unused, - (ks - __start___ksymtab_unused)); - return ks->value; - } - - if (gplok) - ks = lookup_symbol(name, __start___ksymtab_unused_gpl, - __stop___ksymtab_unused_gpl); - if (ks) { - printk_unused_warning(name); - *crc = symversion(__start___kcrctab_unused_gpl, - (ks - __start___ksymtab_unused_gpl)); - return ks->value; + if (gplok) { + for (i = 0; __start___ksymtab_gpl+i<__stop___ksymtab_gpl; i++) + if (strcmp(__start___ksymtab_gpl[i].name, name) == 0) { + *crc = symversion(__start___kcrctab_gpl, i); + return __start___ksymtab_gpl[i].value; + } } /* Now try modules. */ list_for_each_entry(mod, &modules, list) { *owner = mod; - ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms); - if (ks) { - *crc = symversion(mod->crcs, (ks - mod->syms)); - return ks->value; - } - - if (gplok) { - ks = lookup_symbol(name, mod->gpl_syms, - mod->gpl_syms + mod->num_gpl_syms); - if (ks) { - *crc = symversion(mod->gpl_crcs, - (ks - mod->gpl_syms)); - return ks->value; + for (i = 0; i < mod->num_syms; i++) + if (strcmp(mod->syms[i].name, name) == 0) { + *crc = symversion(mod->crcs, i); + return mod->syms[i].value; } - } - ks = lookup_symbol(name, mod->unused_syms, mod->unused_syms + mod->num_unused_syms); - if (ks) { - printk_unused_warning(name); - *crc = symversion(mod->unused_crcs, (ks - mod->unused_syms)); - return ks->value; - } if (gplok) { - ks = lookup_symbol(name, mod->unused_gpl_syms, - mod->unused_gpl_syms + mod->num_unused_gpl_syms); - if (ks) { - printk_unused_warning(name); - *crc = symversion(mod->unused_gpl_crcs, - (ks - mod->unused_gpl_syms)); - return ks->value; + for (i = 0; i < mod->num_gpl_syms; i++) { + if (strcmp(mod->gpl_syms[i].name, name) == 0) { + *crc = symversion(mod->gpl_crcs, i); + return mod->gpl_syms[i].value; + } } } - ks = lookup_symbol(name, mod->gpl_future_syms, - (mod->gpl_future_syms + - mod->num_gpl_future_syms)); - if (ks) { - if (!gplok) { - printk(KERN_WARNING "Symbol %s is being used " - "by a non-GPL module, which will not " - "be allowed in the future\n", name); - printk(KERN_WARNING "Please see the file " - "Documentation/feature-removal-schedule.txt " - "in the kernel source tree for more " - "details.\n"); - } - *crc = symversion(mod->gpl_future_crcs, - (ks - mod->gpl_future_syms)); - return ks->value; - } } DEBUGP("Failed to find symbol %s\n", name); return 0; } +/* Find a symbol in this elf symbol table */ +static unsigned long find_local_symbol(Elf_Shdr *sechdrs, + unsigned int symindex, + const char *strtab, + const char *name) +{ + unsigned int i; + Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr; + + /* Search (defined) internal symbols first. */ + for (i = 1; i < sechdrs[symindex].sh_size/sizeof(*sym); i++) { + if (sym[i].st_shndx != SHN_UNDEF + && strcmp(name, strtab + sym[i].st_name) == 0) + return sym[i].st_value; + } + return 0; +} + /* Search for module by name: must hold module_mutex. */ static struct module *find_module(const char *name) { @@ -460,6 +379,7 @@ static inline void percpu_modcopy(void *pcpudst, const void *src, } #endif /* CONFIG_SMP */ +#ifdef CONFIG_MODULE_UNLOAD #define MODINFO_ATTR(field) \ static void setup_modinfo_##field(struct module *mod, const char *s) \ { \ @@ -491,7 +411,12 @@ static struct module_attribute modinfo_##field = { \ MODINFO_ATTR(version); MODINFO_ATTR(srcversion); -#ifdef CONFIG_MODULE_UNLOAD +static struct module_attribute *modinfo_attrs[] = { + &modinfo_version, + &modinfo_srcversion, + NULL, +}; + /* Init the unload section of the module. */ static void module_unload_init(struct module *mod) { @@ -632,7 +557,7 @@ static void free_module(struct module *mod); static void wait_for_zero_refcount(struct module *mod) { /* Since we might sleep for some time, drop the semaphore first */ - mutex_unlock(&module_mutex); + up(&module_mutex); for (;;) { DEBUGP("Looking at refcount...\n"); set_current_state(TASK_UNINTERRUPTIBLE); @@ -641,7 +566,7 @@ static void wait_for_zero_refcount(struct module *mod) schedule(); } current->state = TASK_RUNNING; - mutex_lock(&module_mutex); + down(&module_mutex); } asmlinkage long @@ -658,7 +583,7 @@ sys_delete_module(const char __user *name_user, unsigned int flags) return -EFAULT; name[MODULE_NAME_LEN-1] = '\0'; - if (mutex_lock_interruptible(&module_mutex) != 0) + if (down_interruptible(&module_mutex) != 0) return -EINTR; mod = find_module(name); @@ -707,14 +632,14 @@ sys_delete_module(const char __user *name_user, unsigned int flags) /* Final destruction now noone is using it. */ if (mod->exit != NULL) { - mutex_unlock(&module_mutex); + up(&module_mutex); mod->exit(); - mutex_lock(&module_mutex); + down(&module_mutex); } free_module(mod); out: - mutex_unlock(&module_mutex); + up(&module_mutex); return ret; } @@ -762,14 +687,14 @@ EXPORT_SYMBOL(__symbol_put); void symbol_put_addr(void *addr) { - struct module *modaddr; - - if (core_kernel_text((unsigned long)addr)) - return; + unsigned long flags; - if (!(modaddr = module_text_address((unsigned long)addr))) + spin_lock_irqsave(&modlist_lock, flags); + if (!kernel_text_address((unsigned long)addr)) BUG(); - module_put(modaddr); + + module_put(module_text_address((unsigned long)addr)); + spin_unlock_irqrestore(&modlist_lock, flags); } EXPORT_SYMBOL_GPL(symbol_put_addr); @@ -806,14 +731,138 @@ static inline void module_unload_init(struct module *mod) } #endif /* CONFIG_MODULE_UNLOAD */ -static struct module_attribute *modinfo_attrs[] = { - &modinfo_version, - &modinfo_srcversion, -#ifdef CONFIG_MODULE_UNLOAD - &refcnt, -#endif - NULL, -}; +#ifdef CONFIG_OBSOLETE_MODPARM +/* Bounds checking done below */ +static int obsparm_copy_string(const char *val, struct kernel_param *kp) +{ + strcpy(kp->arg, val); + return 0; +} + +static int set_obsolete(const char *val, struct kernel_param *kp) +{ + unsigned int min, max; + unsigned int size, maxsize; + int dummy; + char *endp; + const char *p; + struct obsolete_modparm *obsparm = kp->arg; + + if (!val) { + printk(KERN_ERR "Parameter %s needs an argument\n", kp->name); + return -EINVAL; + } + + /* type is: [min[-max]]{b,h,i,l,s} */ + p = obsparm->type; + min = simple_strtol(p, &endp, 10); + if (endp == obsparm->type) + min = max = 1; + else if (*endp == '-') { + p = endp+1; + max = simple_strtol(p, &endp, 10); + } else + max = min; + switch (*endp) { + case 'b': + return param_array(kp->name, val, min, max, obsparm->addr, + 1, param_set_byte, &dummy); + case 'h': + return param_array(kp->name, val, min, max, obsparm->addr, + sizeof(short), param_set_short, &dummy); + case 'i': + return param_array(kp->name, val, min, max, obsparm->addr, + sizeof(int), param_set_int, &dummy); + case 'l': + return param_array(kp->name, val, min, max, obsparm->addr, + sizeof(long), param_set_long, &dummy); + case 's': + return param_array(kp->name, val, min, max, obsparm->addr, + sizeof(char *), param_set_charp, &dummy); + + case 'c': + /* Undocumented: 1-5c50 means 1-5 strings of up to 49 chars, + and the decl is "char xxx[5][50];" */ + p = endp+1; + maxsize = simple_strtol(p, &endp, 10); + /* We check lengths here (yes, this is a hack). */ + p = val; + while (p[size = strcspn(p, ",")]) { + if (size >= maxsize) + goto oversize; + p += size+1; + } + if (size >= maxsize) + goto oversize; + return param_array(kp->name, val, min, max, obsparm->addr, + maxsize, obsparm_copy_string, &dummy); + } + printk(KERN_ERR "Unknown obsolete parameter type %s\n", obsparm->type); + return -EINVAL; + oversize: + printk(KERN_ERR + "Parameter %s doesn't fit in %u chars.\n", kp->name, maxsize); + return -EINVAL; +} + +static int obsolete_params(const char *name, + char *args, + struct obsolete_modparm obsparm[], + unsigned int num, + Elf_Shdr *sechdrs, + unsigned int symindex, + const char *strtab) +{ + struct kernel_param *kp; + unsigned int i; + int ret; + + kp = kmalloc(sizeof(kp[0]) * num, GFP_KERNEL); + if (!kp) + return -ENOMEM; + + for (i = 0; i < num; i++) { + char sym_name[128 + sizeof(MODULE_SYMBOL_PREFIX)]; + + snprintf(sym_name, sizeof(sym_name), "%s%s", + MODULE_SYMBOL_PREFIX, obsparm[i].name); + + kp[i].name = obsparm[i].name; + kp[i].perm = 000; + kp[i].set = set_obsolete; + kp[i].get = NULL; + obsparm[i].addr + = (void *)find_local_symbol(sechdrs, symindex, strtab, + sym_name); + if (!obsparm[i].addr) { + printk("%s: falsely claims to have parameter %s\n", + name, obsparm[i].name); + ret = -EINVAL; + goto out; + } + kp[i].arg = &obsparm[i]; + } + + ret = parse_args(name, args, kp, num, NULL); + out: + kfree(kp); + return ret; +} +#else +static int obsolete_params(const char *name, + char *args, + struct obsolete_modparm obsparm[], + unsigned int num, + Elf_Shdr *sechdrs, + unsigned int symindex, + const char *strtab) +{ + if (num != 0) + printk(KERN_WARNING "%s: Ignoring obsolete parameters\n", + name); + return 0; +} +#endif /* CONFIG_OBSOLETE_MODPARM */ static const char vermagic[] = VERMAGIC_STRING; @@ -1007,28 +1056,37 @@ static inline void remove_sect_attrs(struct module *mod) } #endif /* CONFIG_KALLSYMS */ + +#ifdef CONFIG_MODULE_UNLOAD +static inline int module_add_refcnt_attr(struct module *mod) +{ + return sysfs_create_file(&mod->mkobj.kobj, &refcnt.attr); +} +static void module_remove_refcnt_attr(struct module *mod) +{ + return sysfs_remove_file(&mod->mkobj.kobj, &refcnt.attr); +} +#else +static inline int module_add_refcnt_attr(struct module *mod) +{ + return 0; +} +static void module_remove_refcnt_attr(struct module *mod) +{ +} +#endif + +#ifdef CONFIG_MODULE_UNLOAD static int module_add_modinfo_attrs(struct module *mod) { struct module_attribute *attr; - struct module_attribute *temp_attr; int error = 0; int i; - mod->modinfo_attrs = kzalloc((sizeof(struct module_attribute) * - (ARRAY_SIZE(modinfo_attrs) + 1)), - GFP_KERNEL); - if (!mod->modinfo_attrs) - return -ENOMEM; - - temp_attr = mod->modinfo_attrs; for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) { if (!attr->test || - (attr->test && attr->test(mod))) { - memcpy(temp_attr, attr, sizeof(*temp_attr)); - temp_attr->attr.owner = mod; - error = sysfs_create_file(&mod->mkobj.kobj,&temp_attr->attr); - ++temp_attr; - } + (attr->test && attr->test(mod))) + error = sysfs_create_file(&mod->mkobj.kobj,&attr->attr); } return error; } @@ -1038,16 +1096,12 @@ static void module_remove_modinfo_attrs(struct module *mod) struct module_attribute *attr; int i; - for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) { - /* pick a field to test for end of list */ - if (!attr->attr.name) - break; + for (i = 0; (attr = modinfo_attrs[i]); i++) { sysfs_remove_file(&mod->mkobj.kobj,&attr->attr); - if (attr->free) - attr->free(mod); + attr->free(mod); } - kfree(mod->modinfo_attrs); } +#endif static int mod_sysfs_setup(struct module *mod, struct kernel_param *kparam, @@ -1055,12 +1109,6 @@ static int mod_sysfs_setup(struct module *mod, { int err; - if (!module_subsys.kset.subsys) { - printk(KERN_ERR "%s: module_subsys not initialized\n", - mod->name); - err = -EINVAL; - goto out; - } memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj)); err = kobject_set_name(&mod->mkobj.kobj, "%s", mod->name); if (err) @@ -1071,13 +1119,19 @@ static int mod_sysfs_setup(struct module *mod, if (err) goto out; + err = module_add_refcnt_attr(mod); + if (err) + goto out_unreg; + err = module_param_sysfs_setup(mod, kparam, num_params); if (err) goto out_unreg; +#ifdef CONFIG_MODULE_UNLOAD err = module_add_modinfo_attrs(mod); if (err) goto out_unreg; +#endif return 0; @@ -1089,7 +1143,10 @@ out: static void mod_kobject_remove(struct module *mod) { +#ifdef CONFIG_MODULE_UNLOAD module_remove_modinfo_attrs(mod); +#endif + module_remove_refcnt_attr(mod); module_param_sysfs_remove(mod); kobject_unregister(&mod->mkobj.kobj); @@ -1114,8 +1171,6 @@ static void free_module(struct module *mod) remove_sect_attrs(mod); mod_kobject_remove(mod); - unwind_remove_table(mod->unwind_info, 0); - /* Arch-specific cleanup. */ module_arch_cleanup(mod); @@ -1128,9 +1183,6 @@ static void free_module(struct module *mod) if (mod->percpu) percpu_modfree(mod->percpu); - /* Free lock-classes: */ - lockdep_free_key_range(mod->module_core, mod->core_size); - /* Finally, free the core (containing the module structure) */ module_free(mod, mod->module_core); } @@ -1316,6 +1368,15 @@ static void layout_sections(struct module *mod, } } +static inline int license_is_gpl_compatible(const char *license) +{ + return (strcmp(license, "GPL") == 0 + || strcmp(license, "GPL v2") == 0 + || strcmp(license, "GPL and additional rights") == 0 + || strcmp(license, "Dual BSD/GPL") == 0 + || strcmp(license, "Dual MPL/GPL") == 0); +} + static void set_license(struct module *mod, const char *license) { if (!license) @@ -1363,6 +1424,7 @@ static char *get_modinfo(Elf_Shdr *sechdrs, return NULL; } +#ifdef CONFIG_MODULE_UNLOAD static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs, unsigned int infoindex) { @@ -1377,17 +1439,23 @@ static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs, attr->attr.name)); } } +#endif #ifdef CONFIG_KALLSYMS int is_exported(const char *name, const struct module *mod) { - if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab)) - return 1; - else - if (mod && lookup_symbol(name, mod->syms, mod->syms + mod->num_syms)) + unsigned int i; + + if (!mod) { + for (i = 0; __start___ksymtab+i < __stop___ksymtab; i++) + if (strcmp(__start___ksymtab[i].name, name) == 0) + return 1; + return 0; + } + for (i = 0; i < mod->num_syms; i++) + if (strcmp(mod->syms[i].name, name) == 0) return 1; - else - return 0; + return 0; } /* As per nm */ @@ -1467,33 +1535,15 @@ static struct module *load_module(void __user *umod, Elf_Ehdr *hdr; Elf_Shdr *sechdrs; char *secstrings, *args, *modmagic, *strtab = NULL; - unsigned int i; - unsigned int symindex = 0; - unsigned int strindex = 0; - unsigned int setupindex; - unsigned int exindex; - unsigned int exportindex; - unsigned int modindex; - unsigned int obsparmindex; - unsigned int infoindex; - unsigned int gplindex; - unsigned int crcindex; - unsigned int gplcrcindex; - unsigned int versindex; - unsigned int pcpuindex; - unsigned int gplfutureindex; - unsigned int gplfuturecrcindex; - unsigned int unwindex = 0; - unsigned int unusedindex; - unsigned int unusedcrcindex; - unsigned int unusedgplindex; - unsigned int unusedgplcrcindex; + unsigned int i, symindex = 0, strindex = 0, setupindex, exindex, + exportindex, modindex, obsparmindex, infoindex, gplindex, + crcindex, gplcrcindex, versindex, pcpuindex; + long arglen; struct module *mod; long err = 0; void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ struct exception_table_entry *extable; mm_segment_t old_fs; - int gpgsig_ok; DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n", umod, len, uargs); @@ -1519,13 +1569,8 @@ static struct module *load_module(void __user *umod, goto free_hdr; } - /* verify the module (validates ELF and checks signature) */ - gpgsig_ok = 0; - err = module_verify(hdr, len); - if (err < 0) - goto free_hdr; - if (err == 1) - gpgsig_ok = 1; + if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr)) + goto truncated; /* Convenience variables */ sechdrs = (void *)hdr + hdr->e_shoff; @@ -1562,7 +1607,6 @@ static struct module *load_module(void __user *umod, goto free_hdr; } mod = (void *)sechdrs[modindex].sh_addr; - mod->gpgsig_ok = gpgsig_ok; if (symindex == 0) { printk(KERN_WARNING "%s: module has no symbols (stripped?)\n", @@ -1574,23 +1618,14 @@ static struct module *load_module(void __user *umod, /* Optional sections */ exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab"); gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl"); - gplfutureindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl_future"); - unusedindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused"); - unusedgplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused_gpl"); crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab"); gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl"); - gplfuturecrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl_future"); - unusedcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused"); - unusedgplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused_gpl"); setupindex = find_sec(hdr, sechdrs, secstrings, "__param"); exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table"); obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm"); versindex = find_sec(hdr, sechdrs, secstrings, "__versions"); infoindex = find_sec(hdr, sechdrs, secstrings, ".modinfo"); pcpuindex = find_pcpusec(hdr, sechdrs, secstrings); -#ifdef ARCH_UNWIND_SECTION_NAME - unwindex = find_sec(hdr, sechdrs, secstrings, ARCH_UNWIND_SECTION_NAME); -#endif /* Don't keep modinfo section */ sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC; @@ -1599,8 +1634,6 @@ static struct module *load_module(void __user *umod, sechdrs[symindex].sh_flags |= SHF_ALLOC; sechdrs[strindex].sh_flags |= SHF_ALLOC; #endif - if (unwindex) - sechdrs[unwindex].sh_flags |= SHF_ALLOC; /* Check module struct version now, before we try to use module. */ if (!check_modstruct_version(sechdrs, versindex, mod)) { @@ -1622,11 +1655,23 @@ static struct module *load_module(void __user *umod, } /* Now copy in args */ - args = strndup_user(uargs, ~0UL >> 1); - if (IS_ERR(args)) { - err = PTR_ERR(args); + arglen = strlen_user(uargs); + if (!arglen) { + err = -EFAULT; goto free_hdr; } + args = kmalloc(arglen, GFP_KERNEL); + if (!args) { + err = -ENOMEM; + goto free_hdr; + } + if (copy_from_user(args, uargs, arglen) != 0) { + err = -EFAULT; + goto free_mod; + } + + /* Userspace could have altered the string after the strlen_user() */ + args[arglen - 1] = '\0'; if (find_module(mod->name)) { err = -EEXIST; @@ -1710,8 +1755,10 @@ static struct module *load_module(void __user *umod, if (strcmp(mod->name, "driverloader") == 0) add_taint(TAINT_PROPRIETARY_MODULE); +#ifdef CONFIG_MODULE_UNLOAD /* Set up MODINFO_ATTR fields */ setup_modinfo(mod, sechdrs, infoindex); +#endif /* Fix up syms, so that st_value is a pointer to location. */ err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex, @@ -1728,29 +1775,10 @@ static struct module *load_module(void __user *umod, mod->gpl_syms = (void *)sechdrs[gplindex].sh_addr; if (gplcrcindex) mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr; - mod->num_gpl_future_syms = sechdrs[gplfutureindex].sh_size / - sizeof(*mod->gpl_future_syms); - mod->num_unused_syms = sechdrs[unusedindex].sh_size / - sizeof(*mod->unused_syms); - mod->num_unused_gpl_syms = sechdrs[unusedgplindex].sh_size / - sizeof(*mod->unused_gpl_syms); - mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr; - if (gplfuturecrcindex) - mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr; - - mod->unused_syms = (void *)sechdrs[unusedindex].sh_addr; - if (unusedcrcindex) - mod->unused_crcs = (void *)sechdrs[unusedcrcindex].sh_addr; - mod->unused_gpl_syms = (void *)sechdrs[unusedgplindex].sh_addr; - if (unusedgplcrcindex) - mod->unused_crcs = (void *)sechdrs[unusedgplcrcindex].sh_addr; #ifdef CONFIG_MODVERSIONS if ((mod->num_syms && !crcindex) || - (mod->num_gpl_syms && !gplcrcindex) || - (mod->num_gpl_future_syms && !gplfuturecrcindex) || - (mod->num_unused_syms && !unusedcrcindex) || - (mod->num_unused_gpl_syms && !unusedgplcrcindex)) { + (mod->num_gpl_syms && !gplcrcindex)) { printk(KERN_WARNING "%s: No versions for exported symbols." " Tainting kernel.\n", mod->name); add_taint(TAINT_FORCED_MODULE); @@ -1819,17 +1847,27 @@ static struct module *load_module(void __user *umod, set_fs(old_fs); mod->args = args; - if (obsparmindex) - printk(KERN_WARNING "%s: Ignoring obsolete parameters\n", - mod->name); - - /* Size of section 0 is 0, so this works well if no params */ - err = parse_args(mod->name, mod->args, - (struct kernel_param *) - sechdrs[setupindex].sh_addr, - sechdrs[setupindex].sh_size - / sizeof(struct kernel_param), - NULL); + if (obsparmindex) { + err = obsolete_params(mod->name, mod->args, + (struct obsolete_modparm *) + sechdrs[obsparmindex].sh_addr, + sechdrs[obsparmindex].sh_size + / sizeof(struct obsolete_modparm), + sechdrs, symindex, + (char *)sechdrs[strindex].sh_addr); + if (setupindex) + printk(KERN_WARNING "%s: Ignoring new-style " + "parameters in presence of obsolete ones\n", + mod->name); + } else { + /* Size of section 0 is 0, so this works well if no params */ + err = parse_args(mod->name, mod->args, + (struct kernel_param *) + sechdrs[setupindex].sh_addr, + sechdrs[setupindex].sh_size + / sizeof(struct kernel_param), + NULL); + } if (err < 0) goto arch_cleanup; @@ -1842,11 +1880,6 @@ static struct module *load_module(void __user *umod, goto arch_cleanup; add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs); - /* Size of section 0 is 0, so this works well if no unwind info. */ - mod->unwind_info = unwind_add_table(mod, - (void *)sechdrs[unwindex].sh_addr, - sechdrs[unwindex].sh_size); - /* Get rid of temporary copy */ vfree(hdr); @@ -1900,13 +1933,13 @@ sys_init_module(void __user *umod, return -EPERM; /* Only one module load at a time, please */ - if (mutex_lock_interruptible(&module_mutex) != 0) + if (down_interruptible(&module_mutex) != 0) return -EINTR; /* Do all the hard work */ mod = load_module(umod, len, uargs); if (IS_ERR(mod)) { - mutex_unlock(&module_mutex); + up(&module_mutex); return PTR_ERR(mod); } @@ -1915,10 +1948,11 @@ sys_init_module(void __user *umod, stop_machine_run(__link_module, mod, NR_CPUS); /* Drop lock so they can recurse */ - mutex_unlock(&module_mutex); + up(&module_mutex); - blocking_notifier_call_chain(&module_notify_list, - MODULE_STATE_COMING, mod); + down(¬ify_mutex); + notifier_call_chain(&module_notify_list, MODULE_STATE_COMING, mod); + up(¬ify_mutex); /* Start the module */ if (mod->init != NULL) @@ -1933,24 +1967,23 @@ sys_init_module(void __user *umod, mod->name); else { module_put(mod); - mutex_lock(&module_mutex); + down(&module_mutex); free_module(mod); - mutex_unlock(&module_mutex); + up(&module_mutex); } return ret; } /* Now it's a first class citizen! */ - mutex_lock(&module_mutex); + down(&module_mutex); mod->state = MODULE_STATE_LIVE; /* Drop initial reference. */ module_put(mod); - unwind_remove_table(mod->unwind_info, 1); module_free(mod, mod->module_init); mod->module_init = NULL; mod->init_size = 0; mod->init_text_size = 0; - mutex_unlock(&module_mutex); + up(&module_mutex); return 0; } @@ -2033,24 +2066,27 @@ const char *module_address_lookup(unsigned long addr, return NULL; } -struct module *module_get_kallsym(unsigned int symnum, unsigned long *value, - char *type, char *name, size_t namelen) +struct module *module_get_kallsym(unsigned int symnum, + unsigned long *value, + char *type, + char namebuf[128]) { struct module *mod; - mutex_lock(&module_mutex); + down(&module_mutex); list_for_each_entry(mod, &modules, list) { if (symnum < mod->num_symtab) { *value = mod->symtab[symnum].st_value; *type = mod->symtab[symnum].st_info; - strlcpy(name, mod->strtab + mod->symtab[symnum].st_name, - namelen); - mutex_unlock(&module_mutex); + strncpy(namebuf, + mod->strtab + mod->symtab[symnum].st_name, + 127); + up(&module_mutex); return mod; } symnum -= mod->num_symtab; } - mutex_unlock(&module_mutex); + up(&module_mutex); return NULL; } @@ -2093,7 +2129,7 @@ static void *m_start(struct seq_file *m, loff_t *pos) struct list_head *i; loff_t n = 0; - mutex_lock(&module_mutex); + down(&module_mutex); list_for_each(i, &modules) { if (n++ == *pos) break; @@ -2114,7 +2150,7 @@ static void *m_next(struct seq_file *m, void *p, loff_t *pos) static void m_stop(struct seq_file *m, void *p) { - mutex_unlock(&module_mutex); + up(&module_mutex); } static int m_show(struct seq_file *m, void *p) @@ -2173,29 +2209,6 @@ const struct exception_table_entry *search_module_extables(unsigned long addr) return e; } -/* - * Is this a valid module address? - */ -int is_module_address(unsigned long addr) -{ - unsigned long flags; - struct module *mod; - - spin_lock_irqsave(&modlist_lock, flags); - - list_for_each_entry(mod, &modules, list) { - if (within(addr, mod->module_core, mod->core_size)) { - spin_unlock_irqrestore(&modlist_lock, flags); - return 1; - } - } - - spin_unlock_irqrestore(&modlist_lock, flags); - - return 0; -} - - /* Is this a valid kernel address? We don't grab the lock: we are oopsing. */ struct module *__module_text_address(unsigned long addr) { @@ -2226,13 +2239,8 @@ void print_modules(void) struct module *mod; printk("Modules linked in:"); - list_for_each_entry(mod, &modules, list) { + list_for_each_entry(mod, &modules, list) printk(" %s", mod->name); -#if CONFIG_MODULE_SIG - if (!mod->gpgsig_ok) - printk("(U)"); -#endif - } printk("\n"); }