diff options
Diffstat (limited to 'kernel/module.c')
| -rw-r--r-- | kernel/module.c | 452 |
1 files changed, 159 insertions, 293 deletions
diff --git a/kernel/module.c b/kernel/module.c index 5aad477ddc79..ddfe45ac2fd1 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
| @@ -39,6 +39,7 @@ | |||
| 39 | #include <linux/device.h> | 39 | #include <linux/device.h> |
| 40 | #include <linux/string.h> | 40 | #include <linux/string.h> |
| 41 | #include <linux/sched.h> | 41 | #include <linux/sched.h> |
| 42 | #include <linux/mutex.h> | ||
| 42 | #include <asm/uaccess.h> | 43 | #include <asm/uaccess.h> |
| 43 | #include <asm/semaphore.h> | 44 | #include <asm/semaphore.h> |
| 44 | #include <asm/cacheflush.h> | 45 | #include <asm/cacheflush.h> |
| @@ -60,18 +61,18 @@ | |||
| 60 | static DEFINE_SPINLOCK(modlist_lock); | 61 | static DEFINE_SPINLOCK(modlist_lock); |
| 61 | 62 | ||
| 62 | /* List of modules, protected by module_mutex AND modlist_lock */ | 63 | /* List of modules, protected by module_mutex AND modlist_lock */ |
| 63 | static DECLARE_MUTEX(module_mutex); | 64 | static DEFINE_MUTEX(module_mutex); |
| 64 | static LIST_HEAD(modules); | 65 | static LIST_HEAD(modules); |
| 65 | 66 | ||
| 66 | static DECLARE_MUTEX(notify_mutex); | 67 | static DEFINE_MUTEX(notify_mutex); |
| 67 | static struct notifier_block * module_notify_list; | 68 | static struct notifier_block * module_notify_list; |
| 68 | 69 | ||
| 69 | int register_module_notifier(struct notifier_block * nb) | 70 | int register_module_notifier(struct notifier_block * nb) |
| 70 | { | 71 | { |
| 71 | int err; | 72 | int err; |
| 72 | down(¬ify_mutex); | 73 | mutex_lock(¬ify_mutex); |
| 73 | err = notifier_chain_register(&module_notify_list, nb); | 74 | err = notifier_chain_register(&module_notify_list, nb); |
| 74 | up(¬ify_mutex); | 75 | mutex_unlock(¬ify_mutex); |
| 75 | return err; | 76 | return err; |
| 76 | } | 77 | } |
| 77 | EXPORT_SYMBOL(register_module_notifier); | 78 | EXPORT_SYMBOL(register_module_notifier); |
| @@ -79,9 +80,9 @@ EXPORT_SYMBOL(register_module_notifier); | |||
| 79 | int unregister_module_notifier(struct notifier_block * nb) | 80 | int unregister_module_notifier(struct notifier_block * nb) |
| 80 | { | 81 | { |
| 81 | int err; | 82 | int err; |
| 82 | down(¬ify_mutex); | 83 | mutex_lock(¬ify_mutex); |
| 83 | err = notifier_chain_unregister(&module_notify_list, nb); | 84 | err = notifier_chain_unregister(&module_notify_list, nb); |
| 84 | up(¬ify_mutex); | 85 | mutex_unlock(¬ify_mutex); |
| 85 | return err; | 86 | return err; |
| 86 | } | 87 | } |
| 87 | EXPORT_SYMBOL(unregister_module_notifier); | 88 | EXPORT_SYMBOL(unregister_module_notifier); |
| @@ -126,8 +127,11 @@ extern const struct kernel_symbol __start___ksymtab[]; | |||
| 126 | extern const struct kernel_symbol __stop___ksymtab[]; | 127 | extern const struct kernel_symbol __stop___ksymtab[]; |
| 127 | extern const struct kernel_symbol __start___ksymtab_gpl[]; | 128 | extern const struct kernel_symbol __start___ksymtab_gpl[]; |
| 128 | extern const struct kernel_symbol __stop___ksymtab_gpl[]; | 129 | extern const struct kernel_symbol __stop___ksymtab_gpl[]; |
| 130 | extern const struct kernel_symbol __start___ksymtab_gpl_future[]; | ||
| 131 | extern const struct kernel_symbol __stop___ksymtab_gpl_future[]; | ||
| 129 | extern const unsigned long __start___kcrctab[]; | 132 | extern const unsigned long __start___kcrctab[]; |
| 130 | extern const unsigned long __start___kcrctab_gpl[]; | 133 | extern const unsigned long __start___kcrctab_gpl[]; |
| 134 | extern const unsigned long __start___kcrctab_gpl_future[]; | ||
| 131 | 135 | ||
| 132 | #ifndef CONFIG_MODVERSIONS | 136 | #ifndef CONFIG_MODVERSIONS |
| 133 | #define symversion(base, idx) NULL | 137 | #define symversion(base, idx) NULL |
| @@ -135,6 +139,18 @@ extern const unsigned long __start___kcrctab_gpl[]; | |||
| 135 | #define symversion(base, idx) ((base) ? ((base) + (idx)) : NULL) | 139 | #define symversion(base, idx) ((base) ? ((base) + (idx)) : NULL) |
| 136 | #endif | 140 | #endif |
| 137 | 141 | ||
| 142 | /* lookup symbol in given range of kernel_symbols */ | ||
| 143 | static const struct kernel_symbol *lookup_symbol(const char *name, | ||
| 144 | const struct kernel_symbol *start, | ||
| 145 | const struct kernel_symbol *stop) | ||
| 146 | { | ||
| 147 | const struct kernel_symbol *ks = start; | ||
| 148 | for (; ks < stop; ks++) | ||
| 149 | if (strcmp(ks->name, name) == 0) | ||
| 150 | return ks; | ||
| 151 | return NULL; | ||
| 152 | } | ||
| 153 | |||
| 138 | /* Find a symbol, return value, crc and module which owns it */ | 154 | /* Find a symbol, return value, crc and module which owns it */ |
| 139 | static unsigned long __find_symbol(const char *name, | 155 | static unsigned long __find_symbol(const char *name, |
| 140 | struct module **owner, | 156 | struct module **owner, |
| @@ -142,64 +158,81 @@ static unsigned long __find_symbol(const char *name, | |||
| 142 | int gplok) | 158 | int gplok) |
| 143 | { | 159 | { |
| 144 | struct module *mod; | 160 | struct module *mod; |
| 145 | unsigned int i; | 161 | const struct kernel_symbol *ks; |
| 146 | 162 | ||
| 147 | /* Core kernel first. */ | 163 | /* Core kernel first. */ |
| 148 | *owner = NULL; | 164 | *owner = NULL; |
| 149 | for (i = 0; __start___ksymtab+i < __stop___ksymtab; i++) { | 165 | ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab); |
| 150 | if (strcmp(__start___ksymtab[i].name, name) == 0) { | 166 | if (ks) { |
| 151 | *crc = symversion(__start___kcrctab, i); | 167 | *crc = symversion(__start___kcrctab, (ks - __start___ksymtab)); |
| 152 | return __start___ksymtab[i].value; | 168 | return ks->value; |
| 153 | } | ||
| 154 | } | 169 | } |
| 155 | if (gplok) { | 170 | if (gplok) { |
| 156 | for (i = 0; __start___ksymtab_gpl+i<__stop___ksymtab_gpl; i++) | 171 | ks = lookup_symbol(name, __start___ksymtab_gpl, |
| 157 | if (strcmp(__start___ksymtab_gpl[i].name, name) == 0) { | 172 | __stop___ksymtab_gpl); |
| 158 | *crc = symversion(__start___kcrctab_gpl, i); | 173 | if (ks) { |
| 159 | return __start___ksymtab_gpl[i].value; | 174 | *crc = symversion(__start___kcrctab_gpl, |
| 160 | } | 175 | (ks - __start___ksymtab_gpl)); |
| 176 | return ks->value; | ||
| 177 | } | ||
| 178 | } | ||
| 179 | ks = lookup_symbol(name, __start___ksymtab_gpl_future, | ||
| 180 | __stop___ksymtab_gpl_future); | ||
| 181 | if (ks) { | ||
| 182 | if (!gplok) { | ||
| 183 | printk(KERN_WARNING "Symbol %s is being used " | ||
| 184 | "by a non-GPL module, which will not " | ||
| 185 | "be allowed in the future\n", name); | ||
| 186 | printk(KERN_WARNING "Please see the file " | ||
| 187 | "Documentation/feature-removal-schedule.txt " | ||
| 188 | "in the kernel source tree for more " | ||
| 189 | "details.\n"); | ||
| 190 | } | ||
| 191 | *crc = symversion(__start___kcrctab_gpl_future, | ||
| 192 | (ks - __start___ksymtab_gpl_future)); | ||
| 193 | return ks->value; | ||
| 161 | } | 194 | } |
| 162 | 195 | ||
| 163 | /* Now try modules. */ | 196 | /* Now try modules. */ |
| 164 | list_for_each_entry(mod, &modules, list) { | 197 | list_for_each_entry(mod, &modules, list) { |
| 165 | *owner = mod; | 198 | *owner = mod; |
| 166 | for (i = 0; i < mod->num_syms; i++) | 199 | ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms); |
| 167 | if (strcmp(mod->syms[i].name, name) == 0) { | 200 | if (ks) { |
| 168 | *crc = symversion(mod->crcs, i); | 201 | *crc = symversion(mod->crcs, (ks - mod->syms)); |
| 169 | return mod->syms[i].value; | 202 | return ks->value; |
| 170 | } | 203 | } |
| 171 | 204 | ||
| 172 | if (gplok) { | 205 | if (gplok) { |
| 173 | for (i = 0; i < mod->num_gpl_syms; i++) { | 206 | ks = lookup_symbol(name, mod->gpl_syms, |
| 174 | if (strcmp(mod->gpl_syms[i].name, name) == 0) { | 207 | mod->gpl_syms + mod->num_gpl_syms); |
| 175 | *crc = symversion(mod->gpl_crcs, i); | 208 | if (ks) { |
| 176 | return mod->gpl_syms[i].value; | 209 | *crc = symversion(mod->gpl_crcs, |
| 177 | } | 210 | (ks - mod->gpl_syms)); |
| 211 | return ks->value; | ||
| 178 | } | 212 | } |
| 179 | } | 213 | } |
| 214 | ks = lookup_symbol(name, mod->gpl_future_syms, | ||
| 215 | (mod->gpl_future_syms + | ||
| 216 | mod->num_gpl_future_syms)); | ||
| 217 | if (ks) { | ||
| 218 | if (!gplok) { | ||
| 219 | printk(KERN_WARNING "Symbol %s is being used " | ||
| 220 | "by a non-GPL module, which will not " | ||
| 221 | "be allowed in the future\n", name); | ||
| 222 | printk(KERN_WARNING "Please see the file " | ||
| 223 | "Documentation/feature-removal-schedule.txt " | ||
| 224 | "in the kernel source tree for more " | ||
| 225 | "details.\n"); | ||
| 226 | } | ||
| 227 | *crc = symversion(mod->gpl_future_crcs, | ||
| 228 | (ks - mod->gpl_future_syms)); | ||
| 229 | return ks->value; | ||
| 230 | } | ||
| 180 | } | 231 | } |
| 181 | DEBUGP("Failed to find symbol %s\n", name); | 232 | DEBUGP("Failed to find symbol %s\n", name); |
| 182 | return 0; | 233 | return 0; |
| 183 | } | 234 | } |
| 184 | 235 | ||
| 185 | /* Find a symbol in this elf symbol table */ | ||
| 186 | static unsigned long find_local_symbol(Elf_Shdr *sechdrs, | ||
| 187 | unsigned int symindex, | ||
| 188 | const char *strtab, | ||
| 189 | const char *name) | ||
| 190 | { | ||
| 191 | unsigned int i; | ||
| 192 | Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr; | ||
| 193 | |||
| 194 | /* Search (defined) internal symbols first. */ | ||
| 195 | for (i = 1; i < sechdrs[symindex].sh_size/sizeof(*sym); i++) { | ||
| 196 | if (sym[i].st_shndx != SHN_UNDEF | ||
| 197 | && strcmp(name, strtab + sym[i].st_name) == 0) | ||
| 198 | return sym[i].st_value; | ||
| 199 | } | ||
| 200 | return 0; | ||
| 201 | } | ||
| 202 | |||
| 203 | /* Search for module by name: must hold module_mutex. */ | 236 | /* Search for module by name: must hold module_mutex. */ |
| 204 | static struct module *find_module(const char *name) | 237 | static struct module *find_module(const char *name) |
| 205 | { | 238 | { |
| @@ -379,7 +412,6 @@ static inline void percpu_modcopy(void *pcpudst, const void *src, | |||
| 379 | } | 412 | } |
| 380 | #endif /* CONFIG_SMP */ | 413 | #endif /* CONFIG_SMP */ |
| 381 | 414 | ||
| 382 | #ifdef CONFIG_MODULE_UNLOAD | ||
| 383 | #define MODINFO_ATTR(field) \ | 415 | #define MODINFO_ATTR(field) \ |
| 384 | static void setup_modinfo_##field(struct module *mod, const char *s) \ | 416 | static void setup_modinfo_##field(struct module *mod, const char *s) \ |
| 385 | { \ | 417 | { \ |
| @@ -411,12 +443,7 @@ static struct module_attribute modinfo_##field = { \ | |||
| 411 | MODINFO_ATTR(version); | 443 | MODINFO_ATTR(version); |
| 412 | MODINFO_ATTR(srcversion); | 444 | MODINFO_ATTR(srcversion); |
| 413 | 445 | ||
| 414 | static struct module_attribute *modinfo_attrs[] = { | 446 | #ifdef CONFIG_MODULE_UNLOAD |
| 415 | &modinfo_version, | ||
| 416 | &modinfo_srcversion, | ||
| 417 | NULL, | ||
| 418 | }; | ||
| 419 | |||
| 420 | /* Init the unload section of the module. */ | 447 | /* Init the unload section of the module. */ |
| 421 | static void module_unload_init(struct module *mod) | 448 | static void module_unload_init(struct module *mod) |
| 422 | { | 449 | { |
| @@ -557,7 +584,7 @@ static void free_module(struct module *mod); | |||
| 557 | static void wait_for_zero_refcount(struct module *mod) | 584 | static void wait_for_zero_refcount(struct module *mod) |
| 558 | { | 585 | { |
| 559 | /* Since we might sleep for some time, drop the semaphore first */ | 586 | /* Since we might sleep for some time, drop the semaphore first */ |
| 560 | up(&module_mutex); | 587 | mutex_unlock(&module_mutex); |
| 561 | for (;;) { | 588 | for (;;) { |
| 562 | DEBUGP("Looking at refcount...\n"); | 589 | DEBUGP("Looking at refcount...\n"); |
| 563 | set_current_state(TASK_UNINTERRUPTIBLE); | 590 | set_current_state(TASK_UNINTERRUPTIBLE); |
| @@ -566,7 +593,7 @@ static void wait_for_zero_refcount(struct module *mod) | |||
| 566 | schedule(); | 593 | schedule(); |
| 567 | } | 594 | } |
| 568 | current->state = TASK_RUNNING; | 595 | current->state = TASK_RUNNING; |
| 569 | down(&module_mutex); | 596 | mutex_lock(&module_mutex); |
| 570 | } | 597 | } |
| 571 | 598 | ||
| 572 | asmlinkage long | 599 | asmlinkage long |
| @@ -583,7 +610,7 @@ sys_delete_module(const char __user *name_user, unsigned int flags) | |||
| 583 | return -EFAULT; | 610 | return -EFAULT; |
| 584 | name[MODULE_NAME_LEN-1] = '\0'; | 611 | name[MODULE_NAME_LEN-1] = '\0'; |
| 585 | 612 | ||
| 586 | if (down_interruptible(&module_mutex) != 0) | 613 | if (mutex_lock_interruptible(&module_mutex) != 0) |
| 587 | return -EINTR; | 614 | return -EINTR; |
| 588 | 615 | ||
| 589 | mod = find_module(name); | 616 | mod = find_module(name); |
| @@ -632,14 +659,14 @@ sys_delete_module(const char __user *name_user, unsigned int flags) | |||
| 632 | 659 | ||
| 633 | /* Final destruction now noone is using it. */ | 660 | /* Final destruction now noone is using it. */ |
| 634 | if (mod->exit != NULL) { | 661 | if (mod->exit != NULL) { |
| 635 | up(&module_mutex); | 662 | mutex_unlock(&module_mutex); |
| 636 | mod->exit(); | 663 | mod->exit(); |
| 637 | down(&module_mutex); | 664 | mutex_lock(&module_mutex); |
| 638 | } | 665 | } |
| 639 | free_module(mod); | 666 | free_module(mod); |
| 640 | 667 | ||
| 641 | out: | 668 | out: |
| 642 | up(&module_mutex); | 669 | mutex_unlock(&module_mutex); |
| 643 | return ret; | 670 | return ret; |
| 644 | } | 671 | } |
| 645 | 672 | ||
| @@ -731,138 +758,14 @@ static inline void module_unload_init(struct module *mod) | |||
| 731 | } | 758 | } |
| 732 | #endif /* CONFIG_MODULE_UNLOAD */ | 759 | #endif /* CONFIG_MODULE_UNLOAD */ |
| 733 | 760 | ||
| 734 | #ifdef CONFIG_OBSOLETE_MODPARM | 761 | static struct module_attribute *modinfo_attrs[] = { |
| 735 | /* Bounds checking done below */ | 762 | &modinfo_version, |
| 736 | static int obsparm_copy_string(const char *val, struct kernel_param *kp) | 763 | &modinfo_srcversion, |
| 737 | { | 764 | #ifdef CONFIG_MODULE_UNLOAD |
| 738 | strcpy(kp->arg, val); | 765 | &refcnt, |
| 739 | return 0; | 766 | #endif |
| 740 | } | 767 | NULL, |
| 741 | 768 | }; | |
| 742 | static int set_obsolete(const char *val, struct kernel_param *kp) | ||
| 743 | { | ||
| 744 | unsigned int min, max; | ||
| 745 | unsigned int size, maxsize; | ||
| 746 | int dummy; | ||
| 747 | char *endp; | ||
| 748 | const char *p; | ||
| 749 | struct obsolete_modparm *obsparm = kp->arg; | ||
| 750 | |||
| 751 | if (!val) { | ||
| 752 | printk(KERN_ERR "Parameter %s needs an argument\n", kp->name); | ||
| 753 | return -EINVAL; | ||
| 754 | } | ||
| 755 | |||
| 756 | /* type is: [min[-max]]{b,h,i,l,s} */ | ||
| 757 | p = obsparm->type; | ||
| 758 | min = simple_strtol(p, &endp, 10); | ||
| 759 | if (endp == obsparm->type) | ||
| 760 | min = max = 1; | ||
| 761 | else if (*endp == '-') { | ||
| 762 | p = endp+1; | ||
| 763 | max = simple_strtol(p, &endp, 10); | ||
| 764 | } else | ||
| 765 | max = min; | ||
| 766 | switch (*endp) { | ||
| 767 | case 'b': | ||
| 768 | return param_array(kp->name, val, min, max, obsparm->addr, | ||
| 769 | 1, param_set_byte, &dummy); | ||
| 770 | case 'h': | ||
| 771 | return param_array(kp->name, val, min, max, obsparm->addr, | ||
| 772 | sizeof(short), param_set_short, &dummy); | ||
| 773 | case 'i': | ||
| 774 | return param_array(kp->name, val, min, max, obsparm->addr, | ||
| 775 | sizeof(int), param_set_int, &dummy); | ||
| 776 | case 'l': | ||
| 777 | return param_array(kp->name, val, min, max, obsparm->addr, | ||
| 778 | sizeof(long), param_set_long, &dummy); | ||
| 779 | case 's': | ||
| 780 | return param_array(kp->name, val, min, max, obsparm->addr, | ||
| 781 | sizeof(char *), param_set_charp, &dummy); | ||
| 782 | |||
| 783 | case 'c': | ||
| 784 | /* Undocumented: 1-5c50 means 1-5 strings of up to 49 chars, | ||
| 785 | and the decl is "char xxx[5][50];" */ | ||
| 786 | p = endp+1; | ||
| 787 | maxsize = simple_strtol(p, &endp, 10); | ||
| 788 | /* We check lengths here (yes, this is a hack). */ | ||
| 789 | p = val; | ||
| 790 | while (p[size = strcspn(p, ",")]) { | ||
| 791 | if (size >= maxsize) | ||
| 792 | goto oversize; | ||
| 793 | p += size+1; | ||
| 794 | } | ||
| 795 | if (size >= maxsize) | ||
| 796 | goto oversize; | ||
| 797 | return param_array(kp->name, val, min, max, obsparm->addr, | ||
| 798 | maxsize, obsparm_copy_string, &dummy); | ||
| 799 | } | ||
| 800 | printk(KERN_ERR "Unknown obsolete parameter type %s\n", obsparm->type); | ||
| 801 | return -EINVAL; | ||
| 802 | oversize: | ||
| 803 | printk(KERN_ERR | ||
| 804 | "Parameter %s doesn't fit in %u chars.\n", kp->name, maxsize); | ||
| 805 | return -EINVAL; | ||
| 806 | } | ||
| 807 | |||
| 808 | static int obsolete_params(const char *name, | ||
| 809 | char *args, | ||
| 810 | struct obsolete_modparm obsparm[], | ||
| 811 | unsigned int num, | ||
| 812 | Elf_Shdr *sechdrs, | ||
| 813 | unsigned int symindex, | ||
| 814 | const char *strtab) | ||
| 815 | { | ||
| 816 | struct kernel_param *kp; | ||
| 817 | unsigned int i; | ||
| 818 | int ret; | ||
| 819 | |||
| 820 | kp = kmalloc(sizeof(kp[0]) * num, GFP_KERNEL); | ||
| 821 | if (!kp) | ||
| 822 | return -ENOMEM; | ||
| 823 | |||
| 824 | for (i = 0; i < num; i++) { | ||
| 825 | char sym_name[128 + sizeof(MODULE_SYMBOL_PREFIX)]; | ||
| 826 | |||
| 827 | snprintf(sym_name, sizeof(sym_name), "%s%s", | ||
| 828 | MODULE_SYMBOL_PREFIX, obsparm[i].name); | ||
| 829 | |||
| 830 | kp[i].name = obsparm[i].name; | ||
| 831 | kp[i].perm = 000; | ||
| 832 | kp[i].set = set_obsolete; | ||
| 833 | kp[i].get = NULL; | ||
| 834 | obsparm[i].addr | ||
| 835 | = (void *)find_local_symbol(sechdrs, symindex, strtab, | ||
| 836 | sym_name); | ||
| 837 | if (!obsparm[i].addr) { | ||
| 838 | printk("%s: falsely claims to have parameter %s\n", | ||
| 839 | name, obsparm[i].name); | ||
| 840 | ret = -EINVAL; | ||
| 841 | goto out; | ||
| 842 | } | ||
| 843 | kp[i].arg = &obsparm[i]; | ||
| 844 | } | ||
| 845 | |||
| 846 | ret = parse_args(name, args, kp, num, NULL); | ||
| 847 | out: | ||
| 848 | kfree(kp); | ||
| 849 | return ret; | ||
| 850 | } | ||
| 851 | #else | ||
| 852 | static int obsolete_params(const char *name, | ||
| 853 | char *args, | ||
| 854 | struct obsolete_modparm obsparm[], | ||
| 855 | unsigned int num, | ||
| 856 | Elf_Shdr *sechdrs, | ||
| 857 | unsigned int symindex, | ||
| 858 | const char *strtab) | ||
| 859 | { | ||
| 860 | if (num != 0) | ||
| 861 | printk(KERN_WARNING "%s: Ignoring obsolete parameters\n", | ||
| 862 | name); | ||
| 863 | return 0; | ||
| 864 | } | ||
| 865 | #endif /* CONFIG_OBSOLETE_MODPARM */ | ||
| 866 | 769 | ||
| 867 | static const char vermagic[] = VERMAGIC_STRING; | 770 | static const char vermagic[] = VERMAGIC_STRING; |
| 868 | 771 | ||
| @@ -1056,37 +959,28 @@ static inline void remove_sect_attrs(struct module *mod) | |||
| 1056 | } | 959 | } |
| 1057 | #endif /* CONFIG_KALLSYMS */ | 960 | #endif /* CONFIG_KALLSYMS */ |
| 1058 | 961 | ||
| 1059 | |||
| 1060 | #ifdef CONFIG_MODULE_UNLOAD | ||
| 1061 | static inline int module_add_refcnt_attr(struct module *mod) | ||
| 1062 | { | ||
| 1063 | return sysfs_create_file(&mod->mkobj.kobj, &refcnt.attr); | ||
| 1064 | } | ||
| 1065 | static void module_remove_refcnt_attr(struct module *mod) | ||
| 1066 | { | ||
| 1067 | return sysfs_remove_file(&mod->mkobj.kobj, &refcnt.attr); | ||
| 1068 | } | ||
| 1069 | #else | ||
| 1070 | static inline int module_add_refcnt_attr(struct module *mod) | ||
| 1071 | { | ||
| 1072 | return 0; | ||
| 1073 | } | ||
| 1074 | static void module_remove_refcnt_attr(struct module *mod) | ||
| 1075 | { | ||
| 1076 | } | ||
| 1077 | #endif | ||
| 1078 | |||
| 1079 | #ifdef CONFIG_MODULE_UNLOAD | ||
| 1080 | static int module_add_modinfo_attrs(struct module *mod) | 962 | static int module_add_modinfo_attrs(struct module *mod) |
| 1081 | { | 963 | { |
| 1082 | struct module_attribute *attr; | 964 | struct module_attribute *attr; |
| 965 | struct module_attribute *temp_attr; | ||
| 1083 | int error = 0; | 966 | int error = 0; |
| 1084 | int i; | 967 | int i; |
| 1085 | 968 | ||
| 969 | mod->modinfo_attrs = kzalloc((sizeof(struct module_attribute) * | ||
| 970 | (ARRAY_SIZE(modinfo_attrs) + 1)), | ||
| 971 | GFP_KERNEL); | ||
| 972 | if (!mod->modinfo_attrs) | ||
| 973 | return -ENOMEM; | ||
| 974 | |||
| 975 | temp_attr = mod->modinfo_attrs; | ||
| 1086 | for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) { | 976 | for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) { |
| 1087 | if (!attr->test || | 977 | if (!attr->test || |
| 1088 | (attr->test && attr->test(mod))) | 978 | (attr->test && attr->test(mod))) { |
| 1089 | error = sysfs_create_file(&mod->mkobj.kobj,&attr->attr); | 979 | memcpy(temp_attr, attr, sizeof(*temp_attr)); |
| 980 | temp_attr->attr.owner = mod; | ||
| 981 | error = sysfs_create_file(&mod->mkobj.kobj,&temp_attr->attr); | ||
| 982 | ++temp_attr; | ||
| 983 | } | ||
| 1090 | } | 984 | } |
| 1091 | return error; | 985 | return error; |
| 1092 | } | 986 | } |
| @@ -1096,12 +990,16 @@ static void module_remove_modinfo_attrs(struct module *mod) | |||
| 1096 | struct module_attribute *attr; | 990 | struct module_attribute *attr; |
| 1097 | int i; | 991 | int i; |
| 1098 | 992 | ||
| 1099 | for (i = 0; (attr = modinfo_attrs[i]); i++) { | 993 | for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) { |
| 994 | /* pick a field to test for end of list */ | ||
| 995 | if (!attr->attr.name) | ||
| 996 | break; | ||
| 1100 | sysfs_remove_file(&mod->mkobj.kobj,&attr->attr); | 997 | sysfs_remove_file(&mod->mkobj.kobj,&attr->attr); |
| 1101 | attr->free(mod); | 998 | if (attr->free) |
| 999 | attr->free(mod); | ||
| 1102 | } | 1000 | } |
| 1001 | kfree(mod->modinfo_attrs); | ||
| 1103 | } | 1002 | } |
| 1104 | #endif | ||
| 1105 | 1003 | ||
| 1106 | static int mod_sysfs_setup(struct module *mod, | 1004 | static int mod_sysfs_setup(struct module *mod, |
| 1107 | struct kernel_param *kparam, | 1005 | struct kernel_param *kparam, |
| @@ -1119,19 +1017,13 @@ static int mod_sysfs_setup(struct module *mod, | |||
| 1119 | if (err) | 1017 | if (err) |
| 1120 | goto out; | 1018 | goto out; |
| 1121 | 1019 | ||
| 1122 | err = module_add_refcnt_attr(mod); | ||
| 1123 | if (err) | ||
| 1124 | goto out_unreg; | ||
| 1125 | |||
| 1126 | err = module_param_sysfs_setup(mod, kparam, num_params); | 1020 | err = module_param_sysfs_setup(mod, kparam, num_params); |
| 1127 | if (err) | 1021 | if (err) |
| 1128 | goto out_unreg; | 1022 | goto out_unreg; |
| 1129 | 1023 | ||
| 1130 | #ifdef CONFIG_MODULE_UNLOAD | ||
| 1131 | err = module_add_modinfo_attrs(mod); | 1024 | err = module_add_modinfo_attrs(mod); |
| 1132 | if (err) | 1025 | if (err) |
| 1133 | goto out_unreg; | 1026 | goto out_unreg; |
| 1134 | #endif | ||
| 1135 | 1027 | ||
| 1136 | return 0; | 1028 | return 0; |
| 1137 | 1029 | ||
| @@ -1143,10 +1035,7 @@ out: | |||
| 1143 | 1035 | ||
| 1144 | static void mod_kobject_remove(struct module *mod) | 1036 | static void mod_kobject_remove(struct module *mod) |
| 1145 | { | 1037 | { |
| 1146 | #ifdef CONFIG_MODULE_UNLOAD | ||
| 1147 | module_remove_modinfo_attrs(mod); | 1038 | module_remove_modinfo_attrs(mod); |
| 1148 | #endif | ||
| 1149 | module_remove_refcnt_attr(mod); | ||
| 1150 | module_param_sysfs_remove(mod); | 1039 | module_param_sysfs_remove(mod); |
| 1151 | 1040 | ||
| 1152 | kobject_unregister(&mod->mkobj.kobj); | 1041 | kobject_unregister(&mod->mkobj.kobj); |
| @@ -1424,7 +1313,6 @@ static char *get_modinfo(Elf_Shdr *sechdrs, | |||
| 1424 | return NULL; | 1313 | return NULL; |
| 1425 | } | 1314 | } |
| 1426 | 1315 | ||
| 1427 | #ifdef CONFIG_MODULE_UNLOAD | ||
| 1428 | static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs, | 1316 | static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs, |
| 1429 | unsigned int infoindex) | 1317 | unsigned int infoindex) |
| 1430 | { | 1318 | { |
| @@ -1439,23 +1327,17 @@ static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs, | |||
| 1439 | attr->attr.name)); | 1327 | attr->attr.name)); |
| 1440 | } | 1328 | } |
| 1441 | } | 1329 | } |
| 1442 | #endif | ||
| 1443 | 1330 | ||
| 1444 | #ifdef CONFIG_KALLSYMS | 1331 | #ifdef CONFIG_KALLSYMS |
| 1445 | int is_exported(const char *name, const struct module *mod) | 1332 | int is_exported(const char *name, const struct module *mod) |
| 1446 | { | 1333 | { |
| 1447 | unsigned int i; | 1334 | if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab)) |
| 1448 | 1335 | return 1; | |
| 1449 | if (!mod) { | 1336 | else |
| 1450 | for (i = 0; __start___ksymtab+i < __stop___ksymtab; i++) | 1337 | if (lookup_symbol(name, mod->syms, mod->syms + mod->num_syms)) |
| 1451 | if (strcmp(__start___ksymtab[i].name, name) == 0) | ||
| 1452 | return 1; | ||
| 1453 | return 0; | ||
| 1454 | } | ||
| 1455 | for (i = 0; i < mod->num_syms; i++) | ||
| 1456 | if (strcmp(mod->syms[i].name, name) == 0) | ||
| 1457 | return 1; | 1338 | return 1; |
| 1458 | return 0; | 1339 | else |
| 1340 | return 0; | ||
| 1459 | } | 1341 | } |
| 1460 | 1342 | ||
| 1461 | /* As per nm */ | 1343 | /* As per nm */ |
| @@ -1537,8 +1419,8 @@ static struct module *load_module(void __user *umod, | |||
| 1537 | char *secstrings, *args, *modmagic, *strtab = NULL; | 1419 | char *secstrings, *args, *modmagic, *strtab = NULL; |
| 1538 | unsigned int i, symindex = 0, strindex = 0, setupindex, exindex, | 1420 | unsigned int i, symindex = 0, strindex = 0, setupindex, exindex, |
| 1539 | exportindex, modindex, obsparmindex, infoindex, gplindex, | 1421 | exportindex, modindex, obsparmindex, infoindex, gplindex, |
| 1540 | crcindex, gplcrcindex, versindex, pcpuindex; | 1422 | crcindex, gplcrcindex, versindex, pcpuindex, gplfutureindex, |
| 1541 | long arglen; | 1423 | gplfuturecrcindex; |
| 1542 | struct module *mod; | 1424 | struct module *mod; |
| 1543 | long err = 0; | 1425 | long err = 0; |
| 1544 | void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ | 1426 | void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ |
| @@ -1618,8 +1500,10 @@ static struct module *load_module(void __user *umod, | |||
| 1618 | /* Optional sections */ | 1500 | /* Optional sections */ |
| 1619 | exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab"); | 1501 | exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab"); |
| 1620 | gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl"); | 1502 | gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl"); |
| 1503 | gplfutureindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl_future"); | ||
| 1621 | crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab"); | 1504 | crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab"); |
| 1622 | gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl"); | 1505 | gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl"); |
| 1506 | gplfuturecrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl_future"); | ||
| 1623 | setupindex = find_sec(hdr, sechdrs, secstrings, "__param"); | 1507 | setupindex = find_sec(hdr, sechdrs, secstrings, "__param"); |
| 1624 | exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table"); | 1508 | exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table"); |
| 1625 | obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm"); | 1509 | obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm"); |
| @@ -1655,23 +1539,11 @@ static struct module *load_module(void __user *umod, | |||
| 1655 | } | 1539 | } |
| 1656 | 1540 | ||
| 1657 | /* Now copy in args */ | 1541 | /* Now copy in args */ |
| 1658 | arglen = strlen_user(uargs); | 1542 | args = strndup_user(uargs, ~0UL >> 1); |
| 1659 | if (!arglen) { | 1543 | if (IS_ERR(args)) { |
| 1660 | err = -EFAULT; | 1544 | err = PTR_ERR(args); |
| 1661 | goto free_hdr; | ||
| 1662 | } | ||
| 1663 | args = kmalloc(arglen, GFP_KERNEL); | ||
| 1664 | if (!args) { | ||
| 1665 | err = -ENOMEM; | ||
| 1666 | goto free_hdr; | 1545 | goto free_hdr; |
| 1667 | } | 1546 | } |
| 1668 | if (copy_from_user(args, uargs, arglen) != 0) { | ||
| 1669 | err = -EFAULT; | ||
| 1670 | goto free_mod; | ||
| 1671 | } | ||
| 1672 | |||
| 1673 | /* Userspace could have altered the string after the strlen_user() */ | ||
| 1674 | args[arglen - 1] = '\0'; | ||
| 1675 | 1547 | ||
| 1676 | if (find_module(mod->name)) { | 1548 | if (find_module(mod->name)) { |
| 1677 | err = -EEXIST; | 1549 | err = -EEXIST; |
| @@ -1755,10 +1627,8 @@ static struct module *load_module(void __user *umod, | |||
| 1755 | if (strcmp(mod->name, "driverloader") == 0) | 1627 | if (strcmp(mod->name, "driverloader") == 0) |
| 1756 | add_taint(TAINT_PROPRIETARY_MODULE); | 1628 | add_taint(TAINT_PROPRIETARY_MODULE); |
| 1757 | 1629 | ||
| 1758 | #ifdef CONFIG_MODULE_UNLOAD | ||
| 1759 | /* Set up MODINFO_ATTR fields */ | 1630 | /* Set up MODINFO_ATTR fields */ |
| 1760 | setup_modinfo(mod, sechdrs, infoindex); | 1631 | setup_modinfo(mod, sechdrs, infoindex); |
| 1761 | #endif | ||
| 1762 | 1632 | ||
| 1763 | /* Fix up syms, so that st_value is a pointer to location. */ | 1633 | /* Fix up syms, so that st_value is a pointer to location. */ |
| 1764 | err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex, | 1634 | err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex, |
| @@ -1775,10 +1645,16 @@ static struct module *load_module(void __user *umod, | |||
| 1775 | mod->gpl_syms = (void *)sechdrs[gplindex].sh_addr; | 1645 | mod->gpl_syms = (void *)sechdrs[gplindex].sh_addr; |
| 1776 | if (gplcrcindex) | 1646 | if (gplcrcindex) |
| 1777 | mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr; | 1647 | mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr; |
| 1648 | mod->num_gpl_future_syms = sechdrs[gplfutureindex].sh_size / | ||
| 1649 | sizeof(*mod->gpl_future_syms); | ||
| 1650 | mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr; | ||
| 1651 | if (gplfuturecrcindex) | ||
| 1652 | mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr; | ||
| 1778 | 1653 | ||
| 1779 | #ifdef CONFIG_MODVERSIONS | 1654 | #ifdef CONFIG_MODVERSIONS |
| 1780 | if ((mod->num_syms && !crcindex) || | 1655 | if ((mod->num_syms && !crcindex) || |
| 1781 | (mod->num_gpl_syms && !gplcrcindex)) { | 1656 | (mod->num_gpl_syms && !gplcrcindex) || |
| 1657 | (mod->num_gpl_future_syms && !gplfuturecrcindex)) { | ||
| 1782 | printk(KERN_WARNING "%s: No versions for exported symbols." | 1658 | printk(KERN_WARNING "%s: No versions for exported symbols." |
| 1783 | " Tainting kernel.\n", mod->name); | 1659 | " Tainting kernel.\n", mod->name); |
| 1784 | add_taint(TAINT_FORCED_MODULE); | 1660 | add_taint(TAINT_FORCED_MODULE); |
| @@ -1847,27 +1723,17 @@ static struct module *load_module(void __user *umod, | |||
| 1847 | set_fs(old_fs); | 1723 | set_fs(old_fs); |
| 1848 | 1724 | ||
| 1849 | mod->args = args; | 1725 | mod->args = args; |
| 1850 | if (obsparmindex) { | 1726 | if (obsparmindex) |
| 1851 | err = obsolete_params(mod->name, mod->args, | 1727 | printk(KERN_WARNING "%s: Ignoring obsolete parameters\n", |
| 1852 | (struct obsolete_modparm *) | 1728 | mod->name); |
| 1853 | sechdrs[obsparmindex].sh_addr, | 1729 | |
| 1854 | sechdrs[obsparmindex].sh_size | 1730 | /* Size of section 0 is 0, so this works well if no params */ |
| 1855 | / sizeof(struct obsolete_modparm), | 1731 | err = parse_args(mod->name, mod->args, |
| 1856 | sechdrs, symindex, | 1732 | (struct kernel_param *) |
| 1857 | (char *)sechdrs[strindex].sh_addr); | 1733 | sechdrs[setupindex].sh_addr, |
| 1858 | if (setupindex) | 1734 | sechdrs[setupindex].sh_size |
| 1859 | printk(KERN_WARNING "%s: Ignoring new-style " | 1735 | / sizeof(struct kernel_param), |
| 1860 | "parameters in presence of obsolete ones\n", | 1736 | NULL); |
| 1861 | mod->name); | ||
| 1862 | } else { | ||
| 1863 | /* Size of section 0 is 0, so this works well if no params */ | ||
| 1864 | err = parse_args(mod->name, mod->args, | ||
| 1865 | (struct kernel_param *) | ||
| 1866 | sechdrs[setupindex].sh_addr, | ||
| 1867 | sechdrs[setupindex].sh_size | ||
| 1868 | / sizeof(struct kernel_param), | ||
| 1869 | NULL); | ||
| 1870 | } | ||
| 1871 | if (err < 0) | 1737 | if (err < 0) |
| 1872 | goto arch_cleanup; | 1738 | goto arch_cleanup; |
| 1873 | 1739 | ||
| @@ -1933,13 +1799,13 @@ sys_init_module(void __user *umod, | |||
| 1933 | return -EPERM; | 1799 | return -EPERM; |
| 1934 | 1800 | ||
| 1935 | /* Only one module load at a time, please */ | 1801 | /* Only one module load at a time, please */ |
| 1936 | if (down_interruptible(&module_mutex) != 0) | 1802 | if (mutex_lock_interruptible(&module_mutex) != 0) |
| 1937 | return -EINTR; | 1803 | return -EINTR; |
| 1938 | 1804 | ||
| 1939 | /* Do all the hard work */ | 1805 | /* Do all the hard work */ |
| 1940 | mod = load_module(umod, len, uargs); | 1806 | mod = load_module(umod, len, uargs); |
| 1941 | if (IS_ERR(mod)) { | 1807 | if (IS_ERR(mod)) { |
| 1942 | up(&module_mutex); | 1808 | mutex_unlock(&module_mutex); |
| 1943 | return PTR_ERR(mod); | 1809 | return PTR_ERR(mod); |
| 1944 | } | 1810 | } |
| 1945 | 1811 | ||
| @@ -1948,11 +1814,11 @@ sys_init_module(void __user *umod, | |||
| 1948 | stop_machine_run(__link_module, mod, NR_CPUS); | 1814 | stop_machine_run(__link_module, mod, NR_CPUS); |
| 1949 | 1815 | ||
| 1950 | /* Drop lock so they can recurse */ | 1816 | /* Drop lock so they can recurse */ |
| 1951 | up(&module_mutex); | 1817 | mutex_unlock(&module_mutex); |
| 1952 | 1818 | ||
| 1953 | down(¬ify_mutex); | 1819 | mutex_lock(¬ify_mutex); |
| 1954 | notifier_call_chain(&module_notify_list, MODULE_STATE_COMING, mod); | 1820 | notifier_call_chain(&module_notify_list, MODULE_STATE_COMING, mod); |
| 1955 | up(¬ify_mutex); | 1821 | mutex_unlock(¬ify_mutex); |
| 1956 | 1822 | ||
| 1957 | /* Start the module */ | 1823 | /* Start the module */ |
| 1958 | if (mod->init != NULL) | 1824 | if (mod->init != NULL) |
| @@ -1967,15 +1833,15 @@ sys_init_module(void __user *umod, | |||
| 1967 | mod->name); | 1833 | mod->name); |
| 1968 | else { | 1834 | else { |
| 1969 | module_put(mod); | 1835 | module_put(mod); |
| 1970 | down(&module_mutex); | 1836 | mutex_lock(&module_mutex); |
| 1971 | free_module(mod); | 1837 | free_module(mod); |
| 1972 | up(&module_mutex); | 1838 | mutex_unlock(&module_mutex); |
| 1973 | } | 1839 | } |
| 1974 | return ret; | 1840 | return ret; |
| 1975 | } | 1841 | } |
| 1976 | 1842 | ||
| 1977 | /* Now it's a first class citizen! */ | 1843 | /* Now it's a first class citizen! */ |
| 1978 | down(&module_mutex); | 1844 | mutex_lock(&module_mutex); |
| 1979 | mod->state = MODULE_STATE_LIVE; | 1845 | mod->state = MODULE_STATE_LIVE; |
| 1980 | /* Drop initial reference. */ | 1846 | /* Drop initial reference. */ |
| 1981 | module_put(mod); | 1847 | module_put(mod); |
| @@ -1983,7 +1849,7 @@ sys_init_module(void __user *umod, | |||
| 1983 | mod->module_init = NULL; | 1849 | mod->module_init = NULL; |
| 1984 | mod->init_size = 0; | 1850 | mod->init_size = 0; |
| 1985 | mod->init_text_size = 0; | 1851 | mod->init_text_size = 0; |
| 1986 | up(&module_mutex); | 1852 | mutex_unlock(&module_mutex); |
| 1987 | 1853 | ||
| 1988 | return 0; | 1854 | return 0; |
| 1989 | } | 1855 | } |
| @@ -2073,7 +1939,7 @@ struct module *module_get_kallsym(unsigned int symnum, | |||
| 2073 | { | 1939 | { |
| 2074 | struct module *mod; | 1940 | struct module *mod; |
| 2075 | 1941 | ||
| 2076 | down(&module_mutex); | 1942 | mutex_lock(&module_mutex); |
| 2077 | list_for_each_entry(mod, &modules, list) { | 1943 | list_for_each_entry(mod, &modules, list) { |
| 2078 | if (symnum < mod->num_symtab) { | 1944 | if (symnum < mod->num_symtab) { |
| 2079 | *value = mod->symtab[symnum].st_value; | 1945 | *value = mod->symtab[symnum].st_value; |
| @@ -2081,12 +1947,12 @@ struct module *module_get_kallsym(unsigned int symnum, | |||
| 2081 | strncpy(namebuf, | 1947 | strncpy(namebuf, |
| 2082 | mod->strtab + mod->symtab[symnum].st_name, | 1948 | mod->strtab + mod->symtab[symnum].st_name, |
| 2083 | 127); | 1949 | 127); |
| 2084 | up(&module_mutex); | 1950 | mutex_unlock(&module_mutex); |
| 2085 | return mod; | 1951 | return mod; |
| 2086 | } | 1952 | } |
| 2087 | symnum -= mod->num_symtab; | 1953 | symnum -= mod->num_symtab; |
| 2088 | } | 1954 | } |
| 2089 | up(&module_mutex); | 1955 | mutex_unlock(&module_mutex); |
| 2090 | return NULL; | 1956 | return NULL; |
| 2091 | } | 1957 | } |
| 2092 | 1958 | ||
| @@ -2129,7 +1995,7 @@ static void *m_start(struct seq_file *m, loff_t *pos) | |||
| 2129 | struct list_head *i; | 1995 | struct list_head *i; |
| 2130 | loff_t n = 0; | 1996 | loff_t n = 0; |
| 2131 | 1997 | ||
| 2132 | down(&module_mutex); | 1998 | mutex_lock(&module_mutex); |
| 2133 | list_for_each(i, &modules) { | 1999 | list_for_each(i, &modules) { |
| 2134 | if (n++ == *pos) | 2000 | if (n++ == *pos) |
| 2135 | break; | 2001 | break; |
| @@ -2150,7 +2016,7 @@ static void *m_next(struct seq_file *m, void *p, loff_t *pos) | |||
| 2150 | 2016 | ||
| 2151 | static void m_stop(struct seq_file *m, void *p) | 2017 | static void m_stop(struct seq_file *m, void *p) |
| 2152 | { | 2018 | { |
| 2153 | up(&module_mutex); | 2019 | mutex_unlock(&module_mutex); |
| 2154 | } | 2020 | } |
| 2155 | 2021 | ||
| 2156 | static int m_show(struct seq_file *m, void *p) | 2022 | static int m_show(struct seq_file *m, void *p) |
