diff options
| -rw-r--r-- | include/linux/module.h | 19 | ||||
| -rw-r--r-- | kernel/module.c | 319 |
2 files changed, 172 insertions, 166 deletions
diff --git a/include/linux/module.h b/include/linux/module.h index 819c4e889bf1..3e03b1acbc94 100644 --- a/include/linux/module.h +++ b/include/linux/module.h | |||
| @@ -190,7 +190,7 @@ void *__symbol_get_gpl(const char *symbol); | |||
| 190 | extern typeof(sym) sym; \ | 190 | extern typeof(sym) sym; \ |
| 191 | __CRC_SYMBOL(sym, sec) \ | 191 | __CRC_SYMBOL(sym, sec) \ |
| 192 | static const char __kstrtab_##sym[] \ | 192 | static const char __kstrtab_##sym[] \ |
| 193 | __attribute__((section("__ksymtab_strings"))) \ | 193 | __attribute__((section("__ksymtab_strings"), aligned(1))) \ |
| 194 | = MODULE_SYMBOL_PREFIX #sym; \ | 194 | = MODULE_SYMBOL_PREFIX #sym; \ |
| 195 | static const struct kernel_symbol __ksymtab_##sym \ | 195 | static const struct kernel_symbol __ksymtab_##sym \ |
| 196 | __used \ | 196 | __used \ |
| @@ -229,23 +229,6 @@ enum module_state | |||
| 229 | MODULE_STATE_GOING, | 229 | MODULE_STATE_GOING, |
| 230 | }; | 230 | }; |
| 231 | 231 | ||
| 232 | /* Similar stuff for section attributes. */ | ||
| 233 | struct module_sect_attr | ||
| 234 | { | ||
| 235 | struct module_attribute mattr; | ||
| 236 | char *name; | ||
| 237 | unsigned long address; | ||
| 238 | }; | ||
| 239 | |||
| 240 | struct module_sect_attrs | ||
| 241 | { | ||
| 242 | struct attribute_group grp; | ||
| 243 | int nsections; | ||
| 244 | struct module_sect_attr attrs[0]; | ||
| 245 | }; | ||
| 246 | |||
| 247 | struct module_param_attrs; | ||
| 248 | |||
| 249 | struct module | 232 | struct module |
| 250 | { | 233 | { |
| 251 | enum module_state state; | 234 | enum module_state state; |
diff --git a/kernel/module.c b/kernel/module.c index 8d6cccc6c3cf..8674a390a2e8 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 " |
| 183 | "inclusion.\n"); | ||
| 193 | } | 184 | } |
| 194 | if (gplok) { | 185 | return true; |
| 195 | ks = lookup_symbol(name, __start___ksymtab_gpl, | 186 | } |
| 196 | __stop___ksymtab_gpl); | 187 | |
| 197 | if (ks) { | 188 | static bool gpl_only_unused_warning(bool gplok, bool warn, const char *name) |
| 198 | *crc = symversion(__start___kcrctab_gpl, | 189 | { |
| 199 | (ks - __start___ksymtab_gpl)); | 190 | if (!gplok) |
| 200 | return ks->value; | 191 | return false; |
| 201 | } | 192 | return printk_unused_warning(gplok, warn, name); |
| 202 | } | 193 | } |
| 203 | ks = lookup_symbol(name, __start___ksymtab_gpl_future, | 194 | |
| 204 | __stop___ksymtab_gpl_future); | 195 | static bool gpl_only(bool gplok, bool warn, const char *name) |
| 205 | if (ks) { | 196 | { |
| 206 | if (!gplok) { | 197 | return gplok; |
| 207 | printk(KERN_WARNING "Symbol %s is being used " | 198 | } |
| 208 | "by a non-GPL module, which will not " | 199 | |
| 209 | "be allowed in the future\n", name); | 200 | static bool warn_if_not_gpl(bool gplok, bool warn, const char *name) |
| 210 | printk(KERN_WARNING "Please see the file " | 201 | { |
| 211 | "Documentation/feature-removal-schedule.txt " | 202 | if (!gplok && warn) { |
| 212 | "in the kernel source tree for more " | 203 | printk(KERN_WARNING "Symbol %s is being used " |
| 213 | "details.\n"); | 204 | "by a non-GPL module, which will not " |
| 214 | } | 205 | "be allowed in the future\n", name); |
| 215 | *crc = symversion(__start___kcrctab_gpl_future, | 206 | printk(KERN_WARNING "Please see the file " |
| 216 | (ks - __start___ksymtab_gpl_future)); | 207 | "Documentation/feature-removal-schedule.txt " |
| 217 | return ks->value; | 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 | } | ||
| 242 | |||
| 243 | /* Find a symbol, return value, (optional) crc and (optional) module | ||
| 244 | * which owns it */ | ||
| 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 | }; | ||
| 228 | 265 | ||
| 229 | if (gplok) | 266 | /* Core kernel first. */ |
| 230 | ks = lookup_symbol(name, __start___ksymtab_unused_gpl, | 267 | ks = search_symarrays(arr, ARRAY_SIZE(arr), name, gplok, warn, crc); |
| 231 | __stop___ksymtab_unused_gpl); | ||
| 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, |
| 243 | if (ks) { | 278 | always_ok }, |
| 244 | *crc = symversion(mod->crcs, (ks - mod->syms)); | 279 | { mod->gpl_syms, mod->gpl_syms + mod->num_gpl_syms, |
| 245 | return ks->value; | 280 | mod->gpl_crcs, gpl_only }, |
| 246 | } | 281 | { mod->gpl_future_syms, |
| 247 | 282 | mod->gpl_future_syms + mod->num_gpl_future_syms, | |
| 248 | if (gplok) { | 283 | mod->gpl_future_crcs, warn_if_not_gpl }, |
| 249 | ks = lookup_symbol(name, mod->gpl_syms, | 284 | { mod->unused_syms, |
| 250 | mod->gpl_syms + mod->num_gpl_syms); | 285 | mod->unused_syms + mod->num_unused_syms, |
| 251 | if (ks) { | 286 | mod->unused_crcs, printk_unused_warning }, |
| 252 | *crc = symversion(mod->gpl_crcs, | 287 | { mod->unused_gpl_syms, |
| 253 | (ks - mod->gpl_syms)); | 288 | mod->unused_gpl_syms + mod->num_unused_gpl_syms, |
| 254 | return ks->value; | 289 | mod->unused_gpl_crcs, gpl_only_unused_warning }, |
| 255 | } | 290 | }; |
| 256 | } | 291 | |
| 257 | ks = lookup_symbol(name, mod->unused_syms, mod->unused_syms + mod->num_unused_syms); | 292 | ks = search_symarrays(arr, ARRAY_SIZE(arr), |
| 293 | name, gplok, warn, crc); | ||
| 258 | if (ks) { | 294 | if (ks) { |
| 259 | printk_unused_warning(name); | 295 | if (owner) |
| 260 | *crc = symversion(mod->unused_crcs, (ks - mod->unused_syms)); | 296 | *owner = mod; |
| 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(); |
| @@ -924,13 +933,10 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs, | |||
| 924 | struct module *mod) | 933 | struct module *mod) |
| 925 | { | 934 | { |
| 926 | const unsigned long *crc; | 935 | const unsigned long *crc; |
| 927 | struct module *owner; | ||
| 928 | 936 | ||
| 929 | if (IS_ERR_VALUE(__find_symbol("struct_module", | 937 | if (IS_ERR_VALUE(find_symbol("struct_module", NULL, &crc, true, false))) |
| 930 | &owner, &crc, 1))) | ||
| 931 | BUG(); | 938 | BUG(); |
| 932 | return check_version(sechdrs, versindex, "struct_module", mod, | 939 | return check_version(sechdrs, versindex, "struct_module", mod, crc); |
| 933 | crc); | ||
| 934 | } | 940 | } |
| 935 | 941 | ||
| 936 | /* First part is kernel version, which we ignore. */ | 942 | /* First part is kernel version, which we ignore. */ |
| @@ -974,8 +980,8 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs, | |||
| 974 | unsigned long ret; | 980 | unsigned long ret; |
| 975 | const unsigned long *crc; | 981 | const unsigned long *crc; |
| 976 | 982 | ||
| 977 | ret = __find_symbol(name, &owner, &crc, | 983 | ret = find_symbol(name, &owner, &crc, |
| 978 | !(mod->taints & TAINT_PROPRIETARY_MODULE)); | 984 | !(mod->taints & TAINT_PROPRIETARY_MODULE), true); |
| 979 | if (!IS_ERR_VALUE(ret)) { | 985 | if (!IS_ERR_VALUE(ret)) { |
| 980 | /* use_module can fail due to OOM, | 986 | /* use_module can fail due to OOM, |
| 981 | or module initialization or unloading */ | 987 | or module initialization or unloading */ |
| @@ -991,6 +997,20 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs, | |||
| 991 | * J. Corbet <corbet@lwn.net> | 997 | * J. Corbet <corbet@lwn.net> |
| 992 | */ | 998 | */ |
| 993 | #if defined(CONFIG_KALLSYMS) && defined(CONFIG_SYSFS) | 999 | #if defined(CONFIG_KALLSYMS) && defined(CONFIG_SYSFS) |
| 1000 | struct module_sect_attr | ||
| 1001 | { | ||
| 1002 | struct module_attribute mattr; | ||
| 1003 | char *name; | ||
| 1004 | unsigned long address; | ||
| 1005 | }; | ||
| 1006 | |||
| 1007 | struct module_sect_attrs | ||
| 1008 | { | ||
| 1009 | struct attribute_group grp; | ||
| 1010 | unsigned int nsections; | ||
| 1011 | struct module_sect_attr attrs[0]; | ||
| 1012 | }; | ||
| 1013 | |||
| 994 | static ssize_t module_sect_show(struct module_attribute *mattr, | 1014 | static ssize_t module_sect_show(struct module_attribute *mattr, |
| 995 | struct module *mod, char *buf) | 1015 | struct module *mod, char *buf) |
| 996 | { | 1016 | { |
| @@ -1001,7 +1021,7 @@ static ssize_t module_sect_show(struct module_attribute *mattr, | |||
| 1001 | 1021 | ||
| 1002 | static void free_sect_attrs(struct module_sect_attrs *sect_attrs) | 1022 | static void free_sect_attrs(struct module_sect_attrs *sect_attrs) |
| 1003 | { | 1023 | { |
| 1004 | int section; | 1024 | unsigned int section; |
| 1005 | 1025 | ||
| 1006 | for (section = 0; section < sect_attrs->nsections; section++) | 1026 | for (section = 0; section < sect_attrs->nsections; section++) |
| 1007 | kfree(sect_attrs->attrs[section].name); | 1027 | kfree(sect_attrs->attrs[section].name); |
| @@ -1362,10 +1382,9 @@ void *__symbol_get(const char *symbol) | |||
| 1362 | { | 1382 | { |
| 1363 | struct module *owner; | 1383 | struct module *owner; |
| 1364 | unsigned long value; | 1384 | unsigned long value; |
| 1365 | const unsigned long *crc; | ||
| 1366 | 1385 | ||
| 1367 | preempt_disable(); | 1386 | preempt_disable(); |
| 1368 | value = __find_symbol(symbol, &owner, &crc, 1); | 1387 | value = find_symbol(symbol, &owner, NULL, true, true); |
| 1369 | if (IS_ERR_VALUE(value)) | 1388 | if (IS_ERR_VALUE(value)) |
| 1370 | value = 0; | 1389 | value = 0; |
| 1371 | else if (strong_try_module_get(owner)) | 1390 | else if (strong_try_module_get(owner)) |
| @@ -1382,33 +1401,33 @@ EXPORT_SYMBOL_GPL(__symbol_get); | |||
| 1382 | */ | 1401 | */ |
| 1383 | static int verify_export_symbols(struct module *mod) | 1402 | static int verify_export_symbols(struct module *mod) |
| 1384 | { | 1403 | { |
| 1385 | const char *name = NULL; | 1404 | unsigned int i; |
| 1386 | unsigned long i, ret = 0; | ||
| 1387 | struct module *owner; | 1405 | struct module *owner; |
| 1388 | const unsigned long *crc; | 1406 | const struct kernel_symbol *s; |
| 1389 | 1407 | struct { | |
| 1390 | for (i = 0; i < mod->num_syms; i++) | 1408 | const struct kernel_symbol *sym; |
| 1391 | if (!IS_ERR_VALUE(__find_symbol(mod->syms[i].name, | 1409 | unsigned int num; |
| 1392 | &owner, &crc, 1))) { | 1410 | } arr[] = { |
| 1393 | name = mod->syms[i].name; | 1411 | { mod->syms, mod->num_syms }, |
| 1394 | ret = -ENOEXEC; | 1412 | { mod->gpl_syms, mod->num_gpl_syms }, |
| 1395 | goto dup; | 1413 | { mod->gpl_future_syms, mod->num_gpl_future_syms }, |
| 1396 | } | 1414 | { mod->unused_syms, mod->num_unused_syms }, |
| 1415 | { mod->unused_gpl_syms, mod->num_unused_gpl_syms }, | ||
| 1416 | }; | ||
| 1397 | 1417 | ||
| 1398 | for (i = 0; i < mod->num_gpl_syms; i++) | 1418 | for (i = 0; i < ARRAY_SIZE(arr); i++) { |
| 1399 | if (!IS_ERR_VALUE(__find_symbol(mod->gpl_syms[i].name, | 1419 | for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) { |
| 1400 | &owner, &crc, 1))) { | 1420 | if (!IS_ERR_VALUE(find_symbol(s->name, &owner, |
| 1401 | name = mod->gpl_syms[i].name; | 1421 | NULL, true, false))) { |
| 1402 | ret = -ENOEXEC; | 1422 | printk(KERN_ERR |
| 1403 | goto dup; | 1423 | "%s: exports duplicate symbol %s" |
| 1424 | " (owned by %s)\n", | ||
| 1425 | mod->name, s->name, module_name(owner)); | ||
| 1426 | return -ENOEXEC; | ||
| 1427 | } | ||
| 1404 | } | 1428 | } |
| 1405 | 1429 | } | |
| 1406 | dup: | 1430 | 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 | } | 1431 | } |
| 1413 | 1432 | ||
| 1414 | /* Change all symbols so that st_value encodes the pointer directly. */ | 1433 | /* Change all symbols so that st_value encodes the pointer directly. */ |
| @@ -1814,8 +1833,9 @@ static struct module *load_module(void __user *umod, | |||
| 1814 | unwindex = find_sec(hdr, sechdrs, secstrings, ARCH_UNWIND_SECTION_NAME); | 1833 | unwindex = find_sec(hdr, sechdrs, secstrings, ARCH_UNWIND_SECTION_NAME); |
| 1815 | #endif | 1834 | #endif |
| 1816 | 1835 | ||
| 1817 | /* Don't keep modinfo section */ | 1836 | /* Don't keep modinfo and version sections. */ |
| 1818 | sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC; | 1837 | sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC; |
| 1838 | sechdrs[versindex].sh_flags &= ~(unsigned long)SHF_ALLOC; | ||
| 1819 | #ifdef CONFIG_KALLSYMS | 1839 | #ifdef CONFIG_KALLSYMS |
| 1820 | /* Keep symbol and string tables for decoding later. */ | 1840 | /* Keep symbol and string tables for decoding later. */ |
| 1821 | sechdrs[symindex].sh_flags |= SHF_ALLOC; | 1841 | sechdrs[symindex].sh_flags |= SHF_ALLOC; |
| @@ -1977,7 +1997,8 @@ static struct module *load_module(void __user *umod, | |||
| 1977 | mod->unused_crcs = (void *)sechdrs[unusedcrcindex].sh_addr; | 1997 | mod->unused_crcs = (void *)sechdrs[unusedcrcindex].sh_addr; |
| 1978 | mod->unused_gpl_syms = (void *)sechdrs[unusedgplindex].sh_addr; | 1998 | mod->unused_gpl_syms = (void *)sechdrs[unusedgplindex].sh_addr; |
| 1979 | if (unusedgplcrcindex) | 1999 | if (unusedgplcrcindex) |
| 1980 | mod->unused_crcs = (void *)sechdrs[unusedgplcrcindex].sh_addr; | 2000 | mod->unused_gpl_crcs |
| 2001 | = (void *)sechdrs[unusedgplcrcindex].sh_addr; | ||
| 1981 | 2002 | ||
| 1982 | #ifdef CONFIG_MODVERSIONS | 2003 | #ifdef CONFIG_MODVERSIONS |
| 1983 | if ((mod->num_syms && !crcindex) || | 2004 | if ((mod->num_syms && !crcindex) || |
| @@ -2171,6 +2192,8 @@ sys_init_module(void __user *umod, | |||
| 2171 | mod->state = MODULE_STATE_GOING; | 2192 | mod->state = MODULE_STATE_GOING; |
| 2172 | synchronize_sched(); | 2193 | synchronize_sched(); |
| 2173 | module_put(mod); | 2194 | module_put(mod); |
| 2195 | blocking_notifier_call_chain(&module_notify_list, | ||
| 2196 | MODULE_STATE_GOING, mod); | ||
| 2174 | mutex_lock(&module_mutex); | 2197 | mutex_lock(&module_mutex); |
| 2175 | free_module(mod); | 2198 | free_module(mod); |
| 2176 | mutex_unlock(&module_mutex); | 2199 | mutex_unlock(&module_mutex); |
