diff options
Diffstat (limited to 'kernel/module.c')
| -rw-r--r-- | kernel/module.c | 363 |
1 files changed, 200 insertions, 163 deletions
diff --git a/kernel/module.c b/kernel/module.c index 8d6cccc6c3cf..8e4528c9909f 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
| @@ -164,131 +164,140 @@ static const struct kernel_symbol *lookup_symbol(const char *name, | |||
| 164 | return NULL; | 164 | return NULL; |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | static void printk_unused_warning(const char *name) | 167 | static bool always_ok(bool gplok, bool warn, const char *name) |
| 168 | { | 168 | { |
| 169 | printk(KERN_WARNING "Symbol %s is marked as UNUSED, " | 169 | return true; |
| 170 | "however this module is using it.\n", name); | ||
| 171 | printk(KERN_WARNING "This symbol will go away in the future.\n"); | ||
| 172 | printk(KERN_WARNING "Please evalute if this is the right api to use, " | ||
| 173 | "and if it really is, submit a report the linux kernel " | ||
| 174 | "mailinglist together with submitting your code for " | ||
| 175 | "inclusion.\n"); | ||
| 176 | } | 170 | } |
| 177 | 171 | ||
| 178 | /* Find a symbol, return value, crc and module which owns it */ | 172 | static bool printk_unused_warning(bool gplok, bool warn, const char *name) |
| 179 | static unsigned long __find_symbol(const char *name, | ||
| 180 | struct module **owner, | ||
| 181 | const unsigned long **crc, | ||
| 182 | int gplok) | ||
| 183 | { | 173 | { |
| 184 | struct module *mod; | 174 | if (warn) { |
| 185 | const struct kernel_symbol *ks; | 175 | printk(KERN_WARNING "Symbol %s is marked as UNUSED, " |
| 186 | 176 | "however this module is using it.\n", name); | |
| 187 | /* Core kernel first. */ | 177 | printk(KERN_WARNING |
| 188 | *owner = NULL; | 178 | "This symbol will go away in the future.\n"); |
| 189 | ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab); | 179 | printk(KERN_WARNING |
| 190 | if (ks) { | 180 | "Please evalute if this is the right api to use and if " |
| 191 | *crc = symversion(__start___kcrctab, (ks - __start___ksymtab)); | 181 | "it really is, submit a report the linux kernel " |
| 192 | return ks->value; | 182 | "mailinglist together with submitting your code for " |
| 193 | } | 183 | "inclusion.\n"); |
| 194 | if (gplok) { | ||
| 195 | ks = lookup_symbol(name, __start___ksymtab_gpl, | ||
| 196 | __stop___ksymtab_gpl); | ||
| 197 | if (ks) { | ||
| 198 | *crc = symversion(__start___kcrctab_gpl, | ||
| 199 | (ks - __start___ksymtab_gpl)); | ||
| 200 | return ks->value; | ||
| 201 | } | ||
| 202 | } | 184 | } |
| 203 | ks = lookup_symbol(name, __start___ksymtab_gpl_future, | 185 | return true; |
| 204 | __stop___ksymtab_gpl_future); | 186 | } |
| 205 | if (ks) { | 187 | |
| 206 | if (!gplok) { | 188 | static bool gpl_only_unused_warning(bool gplok, bool warn, const char *name) |
| 207 | printk(KERN_WARNING "Symbol %s is being used " | 189 | { |
| 208 | "by a non-GPL module, which will not " | 190 | if (!gplok) |
| 209 | "be allowed in the future\n", name); | 191 | return false; |
| 210 | printk(KERN_WARNING "Please see the file " | 192 | return printk_unused_warning(gplok, warn, name); |
| 211 | "Documentation/feature-removal-schedule.txt " | 193 | } |
| 212 | "in the kernel source tree for more " | 194 | |
| 213 | "details.\n"); | 195 | static bool gpl_only(bool gplok, bool warn, const char *name) |
| 214 | } | 196 | { |
| 215 | *crc = symversion(__start___kcrctab_gpl_future, | 197 | return gplok; |
| 216 | (ks - __start___ksymtab_gpl_future)); | 198 | } |
| 217 | return ks->value; | 199 | |
| 200 | static bool warn_if_not_gpl(bool gplok, bool warn, const char *name) | ||
| 201 | { | ||
| 202 | if (!gplok && warn) { | ||
| 203 | printk(KERN_WARNING "Symbol %s is being used " | ||
| 204 | "by a non-GPL module, which will not " | ||
| 205 | "be allowed in the future\n", name); | ||
| 206 | printk(KERN_WARNING "Please see the file " | ||
| 207 | "Documentation/feature-removal-schedule.txt " | ||
| 208 | "in the kernel source tree for more details.\n"); | ||
| 218 | } | 209 | } |
| 210 | return true; | ||
| 211 | } | ||
| 219 | 212 | ||
| 220 | ks = lookup_symbol(name, __start___ksymtab_unused, | 213 | struct symsearch { |
| 221 | __stop___ksymtab_unused); | 214 | const struct kernel_symbol *start, *stop; |
| 222 | if (ks) { | 215 | const unsigned long *crcs; |
| 223 | printk_unused_warning(name); | 216 | bool (*check)(bool gplok, bool warn, const char *name); |
| 224 | *crc = symversion(__start___kcrctab_unused, | 217 | }; |
| 225 | (ks - __start___ksymtab_unused)); | 218 | |
| 226 | return ks->value; | 219 | /* Look through this array of symbol tables for a symbol match which |
| 220 | * passes the check function. */ | ||
| 221 | static const struct kernel_symbol *search_symarrays(const struct symsearch *arr, | ||
| 222 | unsigned int num, | ||
| 223 | const char *name, | ||
| 224 | bool gplok, | ||
| 225 | bool warn, | ||
| 226 | const unsigned long **crc) | ||
| 227 | { | ||
| 228 | unsigned int i; | ||
| 229 | const struct kernel_symbol *ks; | ||
| 230 | |||
| 231 | for (i = 0; i < num; i++) { | ||
| 232 | ks = lookup_symbol(name, arr[i].start, arr[i].stop); | ||
| 233 | if (!ks || !arr[i].check(gplok, warn, name)) | ||
| 234 | continue; | ||
| 235 | |||
| 236 | if (crc) | ||
| 237 | *crc = symversion(arr[i].crcs, ks - arr[i].start); | ||
| 238 | return ks; | ||
| 227 | } | 239 | } |
| 240 | return NULL; | ||
| 241 | } | ||
| 228 | 242 | ||
| 229 | if (gplok) | 243 | /* Find a symbol, return value, (optional) crc and (optional) module |
| 230 | ks = lookup_symbol(name, __start___ksymtab_unused_gpl, | 244 | * which owns it */ |
| 231 | __stop___ksymtab_unused_gpl); | 245 | static unsigned long find_symbol(const char *name, |
| 246 | struct module **owner, | ||
| 247 | const unsigned long **crc, | ||
| 248 | bool gplok, | ||
| 249 | bool warn) | ||
| 250 | { | ||
| 251 | struct module *mod; | ||
| 252 | const struct kernel_symbol *ks; | ||
| 253 | const struct symsearch arr[] = { | ||
| 254 | { __start___ksymtab, __stop___ksymtab, __start___kcrctab, | ||
| 255 | always_ok }, | ||
| 256 | { __start___ksymtab_gpl, __stop___ksymtab_gpl, | ||
| 257 | __start___kcrctab_gpl, gpl_only }, | ||
| 258 | { __start___ksymtab_gpl_future, __stop___ksymtab_gpl_future, | ||
| 259 | __start___kcrctab_gpl_future, warn_if_not_gpl }, | ||
| 260 | { __start___ksymtab_unused, __stop___ksymtab_unused, | ||
| 261 | __start___kcrctab_unused, printk_unused_warning }, | ||
| 262 | { __start___ksymtab_unused_gpl, __stop___ksymtab_unused_gpl, | ||
| 263 | __start___kcrctab_unused_gpl, gpl_only_unused_warning }, | ||
| 264 | }; | ||
| 265 | |||
| 266 | /* Core kernel first. */ | ||
| 267 | ks = search_symarrays(arr, ARRAY_SIZE(arr), name, gplok, warn, crc); | ||
| 232 | if (ks) { | 268 | if (ks) { |
| 233 | printk_unused_warning(name); | 269 | if (owner) |
| 234 | *crc = symversion(__start___kcrctab_unused_gpl, | 270 | *owner = NULL; |
| 235 | (ks - __start___ksymtab_unused_gpl)); | ||
| 236 | return ks->value; | 271 | return ks->value; |
| 237 | } | 272 | } |
| 238 | 273 | ||
| 239 | /* Now try modules. */ | 274 | /* Now try modules. */ |
| 240 | list_for_each_entry(mod, &modules, list) { | 275 | list_for_each_entry(mod, &modules, list) { |
| 241 | *owner = mod; | 276 | struct symsearch arr[] = { |
| 242 | ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms); | 277 | { mod->syms, mod->syms + mod->num_syms, mod->crcs, |
| 278 | always_ok }, | ||
| 279 | { mod->gpl_syms, mod->gpl_syms + mod->num_gpl_syms, | ||
| 280 | mod->gpl_crcs, gpl_only }, | ||
| 281 | { mod->gpl_future_syms, | ||
| 282 | mod->gpl_future_syms + mod->num_gpl_future_syms, | ||
| 283 | mod->gpl_future_crcs, warn_if_not_gpl }, | ||
| 284 | { mod->unused_syms, | ||
| 285 | mod->unused_syms + mod->num_unused_syms, | ||
| 286 | mod->unused_crcs, printk_unused_warning }, | ||
| 287 | { mod->unused_gpl_syms, | ||
| 288 | mod->unused_gpl_syms + mod->num_unused_gpl_syms, | ||
| 289 | mod->unused_gpl_crcs, gpl_only_unused_warning }, | ||
| 290 | }; | ||
| 291 | |||
| 292 | ks = search_symarrays(arr, ARRAY_SIZE(arr), | ||
| 293 | name, gplok, warn, crc); | ||
| 243 | if (ks) { | 294 | if (ks) { |
| 244 | *crc = symversion(mod->crcs, (ks - mod->syms)); | 295 | if (owner) |
| 245 | return ks->value; | 296 | *owner = mod; |
| 246 | } | ||
| 247 | |||
| 248 | if (gplok) { | ||
| 249 | ks = lookup_symbol(name, mod->gpl_syms, | ||
| 250 | mod->gpl_syms + mod->num_gpl_syms); | ||
| 251 | if (ks) { | ||
| 252 | *crc = symversion(mod->gpl_crcs, | ||
| 253 | (ks - mod->gpl_syms)); | ||
| 254 | return ks->value; | ||
| 255 | } | ||
| 256 | } | ||
| 257 | ks = lookup_symbol(name, mod->unused_syms, mod->unused_syms + mod->num_unused_syms); | ||
| 258 | if (ks) { | ||
| 259 | printk_unused_warning(name); | ||
| 260 | *crc = symversion(mod->unused_crcs, (ks - mod->unused_syms)); | ||
| 261 | return ks->value; | ||
| 262 | } | ||
| 263 | |||
| 264 | if (gplok) { | ||
| 265 | ks = lookup_symbol(name, mod->unused_gpl_syms, | ||
| 266 | mod->unused_gpl_syms + mod->num_unused_gpl_syms); | ||
| 267 | if (ks) { | ||
| 268 | printk_unused_warning(name); | ||
| 269 | *crc = symversion(mod->unused_gpl_crcs, | ||
| 270 | (ks - mod->unused_gpl_syms)); | ||
| 271 | return ks->value; | ||
| 272 | } | ||
| 273 | } | ||
| 274 | ks = lookup_symbol(name, mod->gpl_future_syms, | ||
| 275 | (mod->gpl_future_syms + | ||
| 276 | mod->num_gpl_future_syms)); | ||
| 277 | if (ks) { | ||
| 278 | if (!gplok) { | ||
| 279 | printk(KERN_WARNING "Symbol %s is being used " | ||
| 280 | "by a non-GPL module, which will not " | ||
| 281 | "be allowed in the future\n", name); | ||
| 282 | printk(KERN_WARNING "Please see the file " | ||
| 283 | "Documentation/feature-removal-schedule.txt " | ||
| 284 | "in the kernel source tree for more " | ||
| 285 | "details.\n"); | ||
| 286 | } | ||
| 287 | *crc = symversion(mod->gpl_future_crcs, | ||
| 288 | (ks - mod->gpl_future_syms)); | ||
| 289 | return ks->value; | 297 | return ks->value; |
| 290 | } | 298 | } |
| 291 | } | 299 | } |
| 300 | |||
| 292 | DEBUGP("Failed to find symbol %s\n", name); | 301 | DEBUGP("Failed to find symbol %s\n", name); |
| 293 | return -ENOENT; | 302 | return -ENOENT; |
| 294 | } | 303 | } |
| @@ -736,12 +745,13 @@ sys_delete_module(const char __user *name_user, unsigned int flags) | |||
| 736 | if (!forced && module_refcount(mod) != 0) | 745 | if (!forced && module_refcount(mod) != 0) |
| 737 | wait_for_zero_refcount(mod); | 746 | wait_for_zero_refcount(mod); |
| 738 | 747 | ||
| 748 | mutex_unlock(&module_mutex); | ||
| 739 | /* Final destruction now noone is using it. */ | 749 | /* Final destruction now noone is using it. */ |
| 740 | if (mod->exit != NULL) { | 750 | if (mod->exit != NULL) |
| 741 | mutex_unlock(&module_mutex); | ||
| 742 | mod->exit(); | 751 | mod->exit(); |
| 743 | mutex_lock(&module_mutex); | 752 | blocking_notifier_call_chain(&module_notify_list, |
| 744 | } | 753 | MODULE_STATE_GOING, mod); |
| 754 | mutex_lock(&module_mutex); | ||
| 745 | /* Store the name of the last unloaded module for diagnostic purposes */ | 755 | /* Store the name of the last unloaded module for diagnostic purposes */ |
| 746 | strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module)); | 756 | strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module)); |
| 747 | free_module(mod); | 757 | free_module(mod); |
| @@ -777,10 +787,9 @@ static void print_unload_info(struct seq_file *m, struct module *mod) | |||
| 777 | void __symbol_put(const char *symbol) | 787 | void __symbol_put(const char *symbol) |
| 778 | { | 788 | { |
| 779 | struct module *owner; | 789 | struct module *owner; |
| 780 | const unsigned long *crc; | ||
| 781 | 790 | ||
| 782 | preempt_disable(); | 791 | preempt_disable(); |
| 783 | if (IS_ERR_VALUE(__find_symbol(symbol, &owner, &crc, 1))) | 792 | if (IS_ERR_VALUE(find_symbol(symbol, &owner, NULL, true, false))) |
| 784 | BUG(); | 793 | BUG(); |
| 785 | module_put(owner); | 794 | module_put(owner); |
| 786 | preempt_enable(); | 795 | preempt_enable(); |
| @@ -881,6 +890,19 @@ static struct module_attribute *modinfo_attrs[] = { | |||
| 881 | 890 | ||
| 882 | static const char vermagic[] = VERMAGIC_STRING; | 891 | static const char vermagic[] = VERMAGIC_STRING; |
| 883 | 892 | ||
| 893 | static int try_to_force_load(struct module *mod, const char *symname) | ||
| 894 | { | ||
| 895 | #ifdef CONFIG_MODULE_FORCE_LOAD | ||
| 896 | if (!(tainted & TAINT_FORCED_MODULE)) | ||
| 897 | printk("%s: no version for \"%s\" found: kernel tainted.\n", | ||
| 898 | mod->name, symname); | ||
| 899 | add_taint_module(mod, TAINT_FORCED_MODULE); | ||
| 900 | return 0; | ||
| 901 | #else | ||
| 902 | return -ENOEXEC; | ||
| 903 | #endif | ||
| 904 | } | ||
| 905 | |||
| 884 | #ifdef CONFIG_MODVERSIONS | 906 | #ifdef CONFIG_MODVERSIONS |
| 885 | static int check_version(Elf_Shdr *sechdrs, | 907 | static int check_version(Elf_Shdr *sechdrs, |
| 886 | unsigned int versindex, | 908 | unsigned int versindex, |
| @@ -905,18 +927,18 @@ static int check_version(Elf_Shdr *sechdrs, | |||
| 905 | 927 | ||
| 906 | if (versions[i].crc == *crc) | 928 | if (versions[i].crc == *crc) |
| 907 | return 1; | 929 | return 1; |
| 908 | printk("%s: disagrees about version of symbol %s\n", | ||
| 909 | mod->name, symname); | ||
| 910 | DEBUGP("Found checksum %lX vs module %lX\n", | 930 | DEBUGP("Found checksum %lX vs module %lX\n", |
| 911 | *crc, versions[i].crc); | 931 | *crc, versions[i].crc); |
| 912 | return 0; | 932 | goto bad_version; |
| 913 | } | 933 | } |
| 914 | /* Not in module's version table. OK, but that taints the kernel. */ | 934 | |
| 915 | if (!(tainted & TAINT_FORCED_MODULE)) | 935 | if (!try_to_force_load(mod, symname)) |
| 916 | printk("%s: no version for \"%s\" found: kernel tainted.\n", | 936 | return 1; |
| 917 | mod->name, symname); | 937 | |
| 918 | add_taint_module(mod, TAINT_FORCED_MODULE); | 938 | bad_version: |
| 919 | return 1; | 939 | printk("%s: disagrees about version of symbol %s\n", |
| 940 | mod->name, symname); | ||
| 941 | return 0; | ||
| 920 | } | 942 | } |
| 921 | 943 | ||
| 922 | static inline int check_modstruct_version(Elf_Shdr *sechdrs, | 944 | static inline int check_modstruct_version(Elf_Shdr *sechdrs, |
| @@ -924,13 +946,10 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs, | |||
| 924 | struct module *mod) | 946 | struct module *mod) |
| 925 | { | 947 | { |
| 926 | const unsigned long *crc; | 948 | const unsigned long *crc; |
| 927 | struct module *owner; | ||
| 928 | 949 | ||
| 929 | if (IS_ERR_VALUE(__find_symbol("struct_module", | 950 | if (IS_ERR_VALUE(find_symbol("struct_module", NULL, &crc, true, false))) |
| 930 | &owner, &crc, 1))) | ||
| 931 | BUG(); | 951 | BUG(); |
| 932 | return check_version(sechdrs, versindex, "struct_module", mod, | 952 | return check_version(sechdrs, versindex, "struct_module", mod, crc); |
| 933 | crc); | ||
| 934 | } | 953 | } |
| 935 | 954 | ||
| 936 | /* First part is kernel version, which we ignore. */ | 955 | /* First part is kernel version, which we ignore. */ |
| @@ -974,8 +993,8 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs, | |||
| 974 | unsigned long ret; | 993 | unsigned long ret; |
| 975 | const unsigned long *crc; | 994 | const unsigned long *crc; |
| 976 | 995 | ||
| 977 | ret = __find_symbol(name, &owner, &crc, | 996 | ret = find_symbol(name, &owner, &crc, |
| 978 | !(mod->taints & TAINT_PROPRIETARY_MODULE)); | 997 | !(mod->taints & TAINT_PROPRIETARY_MODULE), true); |
| 979 | if (!IS_ERR_VALUE(ret)) { | 998 | if (!IS_ERR_VALUE(ret)) { |
| 980 | /* use_module can fail due to OOM, | 999 | /* use_module can fail due to OOM, |
| 981 | or module initialization or unloading */ | 1000 | or module initialization or unloading */ |
| @@ -991,6 +1010,20 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs, | |||
| 991 | * J. Corbet <corbet@lwn.net> | 1010 | * J. Corbet <corbet@lwn.net> |
| 992 | */ | 1011 | */ |
| 993 | #if defined(CONFIG_KALLSYMS) && defined(CONFIG_SYSFS) | 1012 | #if defined(CONFIG_KALLSYMS) && defined(CONFIG_SYSFS) |
| 1013 | struct module_sect_attr | ||
| 1014 | { | ||
| 1015 | struct module_attribute mattr; | ||
| 1016 | char *name; | ||
| 1017 | unsigned long address; | ||
| 1018 | }; | ||
| 1019 | |||
| 1020 | struct module_sect_attrs | ||
| 1021 | { | ||
| 1022 | struct attribute_group grp; | ||
| 1023 | unsigned int nsections; | ||
| 1024 | struct module_sect_attr attrs[0]; | ||
| 1025 | }; | ||
| 1026 | |||
| 994 | static ssize_t module_sect_show(struct module_attribute *mattr, | 1027 | static ssize_t module_sect_show(struct module_attribute *mattr, |
| 995 | struct module *mod, char *buf) | 1028 | struct module *mod, char *buf) |
| 996 | { | 1029 | { |
| @@ -1001,7 +1034,7 @@ static ssize_t module_sect_show(struct module_attribute *mattr, | |||
| 1001 | 1034 | ||
| 1002 | static void free_sect_attrs(struct module_sect_attrs *sect_attrs) | 1035 | static void free_sect_attrs(struct module_sect_attrs *sect_attrs) |
| 1003 | { | 1036 | { |
| 1004 | int section; | 1037 | unsigned int section; |
| 1005 | 1038 | ||
| 1006 | for (section = 0; section < sect_attrs->nsections; section++) | 1039 | for (section = 0; section < sect_attrs->nsections; section++) |
| 1007 | kfree(sect_attrs->attrs[section].name); | 1040 | kfree(sect_attrs->attrs[section].name); |
| @@ -1362,10 +1395,9 @@ void *__symbol_get(const char *symbol) | |||
| 1362 | { | 1395 | { |
| 1363 | struct module *owner; | 1396 | struct module *owner; |
| 1364 | unsigned long value; | 1397 | unsigned long value; |
| 1365 | const unsigned long *crc; | ||
| 1366 | 1398 | ||
| 1367 | preempt_disable(); | 1399 | preempt_disable(); |
| 1368 | value = __find_symbol(symbol, &owner, &crc, 1); | 1400 | value = find_symbol(symbol, &owner, NULL, true, true); |
| 1369 | if (IS_ERR_VALUE(value)) | 1401 | if (IS_ERR_VALUE(value)) |
| 1370 | value = 0; | 1402 | value = 0; |
| 1371 | else if (strong_try_module_get(owner)) | 1403 | else if (strong_try_module_get(owner)) |
| @@ -1382,33 +1414,33 @@ EXPORT_SYMBOL_GPL(__symbol_get); | |||
| 1382 | */ | 1414 | */ |
| 1383 | static int verify_export_symbols(struct module *mod) | 1415 | static int verify_export_symbols(struct module *mod) |
| 1384 | { | 1416 | { |
| 1385 | const char *name = NULL; | 1417 | unsigned int i; |
| 1386 | unsigned long i, ret = 0; | ||
| 1387 | struct module *owner; | 1418 | struct module *owner; |
| 1388 | const unsigned long *crc; | 1419 | const struct kernel_symbol *s; |
| 1389 | 1420 | struct { | |
| 1390 | for (i = 0; i < mod->num_syms; i++) | 1421 | const struct kernel_symbol *sym; |
| 1391 | if (!IS_ERR_VALUE(__find_symbol(mod->syms[i].name, | 1422 | unsigned int num; |
| 1392 | &owner, &crc, 1))) { | 1423 | } arr[] = { |
| 1393 | name = mod->syms[i].name; | 1424 | { mod->syms, mod->num_syms }, |
| 1394 | ret = -ENOEXEC; | 1425 | { mod->gpl_syms, mod->num_gpl_syms }, |
| 1395 | goto dup; | 1426 | { mod->gpl_future_syms, mod->num_gpl_future_syms }, |
| 1396 | } | 1427 | { mod->unused_syms, mod->num_unused_syms }, |
| 1428 | { mod->unused_gpl_syms, mod->num_unused_gpl_syms }, | ||
| 1429 | }; | ||
| 1397 | 1430 | ||
| 1398 | for (i = 0; i < mod->num_gpl_syms; i++) | 1431 | for (i = 0; i < ARRAY_SIZE(arr); i++) { |
| 1399 | if (!IS_ERR_VALUE(__find_symbol(mod->gpl_syms[i].name, | 1432 | for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) { |
| 1400 | &owner, &crc, 1))) { | 1433 | if (!IS_ERR_VALUE(find_symbol(s->name, &owner, |
| 1401 | name = mod->gpl_syms[i].name; | 1434 | NULL, true, false))) { |
| 1402 | ret = -ENOEXEC; | 1435 | printk(KERN_ERR |
| 1403 | goto dup; | 1436 | "%s: exports duplicate symbol %s" |
| 1437 | " (owned by %s)\n", | ||
| 1438 | mod->name, s->name, module_name(owner)); | ||
| 1439 | return -ENOEXEC; | ||
| 1440 | } | ||
| 1404 | } | 1441 | } |
| 1405 | 1442 | } | |
| 1406 | dup: | 1443 | return 0; |
| 1407 | if (ret) | ||
| 1408 | printk(KERN_ERR "%s: exports duplicate symbol %s (owned by %s)\n", | ||
| 1409 | mod->name, name, module_name(owner)); | ||
| 1410 | |||
| 1411 | return ret; | ||
| 1412 | } | 1444 | } |
| 1413 | 1445 | ||
| 1414 | /* Change all symbols so that st_value encodes the pointer directly. */ | 1446 | /* Change all symbols so that st_value encodes the pointer directly. */ |
| @@ -1814,8 +1846,9 @@ static struct module *load_module(void __user *umod, | |||
| 1814 | unwindex = find_sec(hdr, sechdrs, secstrings, ARCH_UNWIND_SECTION_NAME); | 1846 | unwindex = find_sec(hdr, sechdrs, secstrings, ARCH_UNWIND_SECTION_NAME); |
| 1815 | #endif | 1847 | #endif |
| 1816 | 1848 | ||
| 1817 | /* Don't keep modinfo section */ | 1849 | /* Don't keep modinfo and version sections. */ |
| 1818 | sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC; | 1850 | sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC; |
| 1851 | sechdrs[versindex].sh_flags &= ~(unsigned long)SHF_ALLOC; | ||
| 1819 | #ifdef CONFIG_KALLSYMS | 1852 | #ifdef CONFIG_KALLSYMS |
| 1820 | /* Keep symbol and string tables for decoding later. */ | 1853 | /* Keep symbol and string tables for decoding later. */ |
| 1821 | sechdrs[symindex].sh_flags |= SHF_ALLOC; | 1854 | sechdrs[symindex].sh_flags |= SHF_ALLOC; |
| @@ -1833,9 +1866,9 @@ static struct module *load_module(void __user *umod, | |||
| 1833 | modmagic = get_modinfo(sechdrs, infoindex, "vermagic"); | 1866 | modmagic = get_modinfo(sechdrs, infoindex, "vermagic"); |
| 1834 | /* This is allowed: modprobe --force will invalidate it. */ | 1867 | /* This is allowed: modprobe --force will invalidate it. */ |
| 1835 | if (!modmagic) { | 1868 | if (!modmagic) { |
| 1836 | add_taint_module(mod, TAINT_FORCED_MODULE); | 1869 | err = try_to_force_load(mod, "magic"); |
| 1837 | printk(KERN_WARNING "%s: no version magic, tainting kernel.\n", | 1870 | if (err) |
| 1838 | mod->name); | 1871 | goto free_hdr; |
| 1839 | } else if (!same_magic(modmagic, vermagic)) { | 1872 | } else if (!same_magic(modmagic, vermagic)) { |
| 1840 | printk(KERN_ERR "%s: version magic '%s' should be '%s'\n", | 1873 | printk(KERN_ERR "%s: version magic '%s' should be '%s'\n", |
| 1841 | mod->name, modmagic, vermagic); | 1874 | mod->name, modmagic, vermagic); |
| @@ -1977,7 +2010,8 @@ static struct module *load_module(void __user *umod, | |||
| 1977 | mod->unused_crcs = (void *)sechdrs[unusedcrcindex].sh_addr; | 2010 | mod->unused_crcs = (void *)sechdrs[unusedcrcindex].sh_addr; |
| 1978 | mod->unused_gpl_syms = (void *)sechdrs[unusedgplindex].sh_addr; | 2011 | mod->unused_gpl_syms = (void *)sechdrs[unusedgplindex].sh_addr; |
| 1979 | if (unusedgplcrcindex) | 2012 | if (unusedgplcrcindex) |
| 1980 | mod->unused_crcs = (void *)sechdrs[unusedgplcrcindex].sh_addr; | 2013 | mod->unused_gpl_crcs |
| 2014 | = (void *)sechdrs[unusedgplcrcindex].sh_addr; | ||
| 1981 | 2015 | ||
| 1982 | #ifdef CONFIG_MODVERSIONS | 2016 | #ifdef CONFIG_MODVERSIONS |
| 1983 | if ((mod->num_syms && !crcindex) || | 2017 | if ((mod->num_syms && !crcindex) || |
| @@ -1985,9 +2019,10 @@ static struct module *load_module(void __user *umod, | |||
| 1985 | (mod->num_gpl_future_syms && !gplfuturecrcindex) || | 2019 | (mod->num_gpl_future_syms && !gplfuturecrcindex) || |
| 1986 | (mod->num_unused_syms && !unusedcrcindex) || | 2020 | (mod->num_unused_syms && !unusedcrcindex) || |
| 1987 | (mod->num_unused_gpl_syms && !unusedgplcrcindex)) { | 2021 | (mod->num_unused_gpl_syms && !unusedgplcrcindex)) { |
| 1988 | printk(KERN_WARNING "%s: No versions for exported symbols." | 2022 | printk(KERN_WARNING "%s: No versions for exported symbols.\n", mod->name); |
| 1989 | " Tainting kernel.\n", mod->name); | 2023 | err = try_to_force_load(mod, "nocrc"); |
| 1990 | add_taint_module(mod, TAINT_FORCED_MODULE); | 2024 | if (err) |
| 2025 | goto cleanup; | ||
| 1991 | } | 2026 | } |
| 1992 | #endif | 2027 | #endif |
| 1993 | markersindex = find_sec(hdr, sechdrs, secstrings, "__markers"); | 2028 | markersindex = find_sec(hdr, sechdrs, secstrings, "__markers"); |
| @@ -2171,6 +2206,8 @@ sys_init_module(void __user *umod, | |||
| 2171 | mod->state = MODULE_STATE_GOING; | 2206 | mod->state = MODULE_STATE_GOING; |
| 2172 | synchronize_sched(); | 2207 | synchronize_sched(); |
| 2173 | module_put(mod); | 2208 | module_put(mod); |
| 2209 | blocking_notifier_call_chain(&module_notify_list, | ||
| 2210 | MODULE_STATE_GOING, mod); | ||
| 2174 | mutex_lock(&module_mutex); | 2211 | mutex_lock(&module_mutex); |
| 2175 | free_module(mod); | 2212 | free_module(mod); |
| 2176 | mutex_unlock(&module_mutex); | 2213 | mutex_unlock(&module_mutex); |
