diff options
Diffstat (limited to 'kernel/module.c')
-rw-r--r-- | kernel/module.c | 56 |
1 files changed, 49 insertions, 7 deletions
diff --git a/kernel/module.c b/kernel/module.c index 4b06bbad49c2..e4276046a1b6 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -496,15 +496,15 @@ static void module_unload_free(struct module *mod) | |||
496 | } | 496 | } |
497 | 497 | ||
498 | #ifdef CONFIG_MODULE_FORCE_UNLOAD | 498 | #ifdef CONFIG_MODULE_FORCE_UNLOAD |
499 | static inline int try_force(unsigned int flags) | 499 | static inline int try_force_unload(unsigned int flags) |
500 | { | 500 | { |
501 | int ret = (flags & O_TRUNC); | 501 | int ret = (flags & O_TRUNC); |
502 | if (ret) | 502 | if (ret) |
503 | add_taint(TAINT_FORCED_MODULE); | 503 | add_taint(TAINT_FORCED_RMMOD); |
504 | return ret; | 504 | return ret; |
505 | } | 505 | } |
506 | #else | 506 | #else |
507 | static inline int try_force(unsigned int flags) | 507 | static inline int try_force_unload(unsigned int flags) |
508 | { | 508 | { |
509 | return 0; | 509 | return 0; |
510 | } | 510 | } |
@@ -524,7 +524,7 @@ static int __try_stop_module(void *_sref) | |||
524 | 524 | ||
525 | /* If it's not unused, quit unless we are told to block. */ | 525 | /* If it's not unused, quit unless we are told to block. */ |
526 | if ((sref->flags & O_NONBLOCK) && module_refcount(sref->mod) != 0) { | 526 | if ((sref->flags & O_NONBLOCK) && module_refcount(sref->mod) != 0) { |
527 | if (!(*sref->forced = try_force(sref->flags))) | 527 | if (!(*sref->forced = try_force_unload(sref->flags))) |
528 | return -EWOULDBLOCK; | 528 | return -EWOULDBLOCK; |
529 | } | 529 | } |
530 | 530 | ||
@@ -609,7 +609,7 @@ sys_delete_module(const char __user *name_user, unsigned int flags) | |||
609 | /* If it has an init func, it must have an exit func to unload */ | 609 | /* If it has an init func, it must have an exit func to unload */ |
610 | if ((mod->init != NULL && mod->exit == NULL) | 610 | if ((mod->init != NULL && mod->exit == NULL) |
611 | || mod->unsafe) { | 611 | || mod->unsafe) { |
612 | forced = try_force(flags); | 612 | forced = try_force_unload(flags); |
613 | if (!forced) { | 613 | if (!forced) { |
614 | /* This module can't be removed */ | 614 | /* This module can't be removed */ |
615 | ret = -EBUSY; | 615 | ret = -EBUSY; |
@@ -958,7 +958,6 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs, | |||
958 | unsigned long ret; | 958 | unsigned long ret; |
959 | const unsigned long *crc; | 959 | const unsigned long *crc; |
960 | 960 | ||
961 | spin_lock_irq(&modlist_lock); | ||
962 | ret = __find_symbol(name, &owner, &crc, mod->license_gplok); | 961 | ret = __find_symbol(name, &owner, &crc, mod->license_gplok); |
963 | if (ret) { | 962 | if (ret) { |
964 | /* use_module can fail due to OOM, or module unloading */ | 963 | /* use_module can fail due to OOM, or module unloading */ |
@@ -966,7 +965,6 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs, | |||
966 | !use_module(mod, owner)) | 965 | !use_module(mod, owner)) |
967 | ret = 0; | 966 | ret = 0; |
968 | } | 967 | } |
969 | spin_unlock_irq(&modlist_lock); | ||
970 | return ret; | 968 | return ret; |
971 | } | 969 | } |
972 | 970 | ||
@@ -1204,6 +1202,39 @@ void *__symbol_get(const char *symbol) | |||
1204 | } | 1202 | } |
1205 | EXPORT_SYMBOL_GPL(__symbol_get); | 1203 | EXPORT_SYMBOL_GPL(__symbol_get); |
1206 | 1204 | ||
1205 | /* | ||
1206 | * Ensure that an exported symbol [global namespace] does not already exist | ||
1207 | * in the Kernel or in some other modules exported symbol table. | ||
1208 | */ | ||
1209 | static int verify_export_symbols(struct module *mod) | ||
1210 | { | ||
1211 | const char *name = NULL; | ||
1212 | unsigned long i, ret = 0; | ||
1213 | struct module *owner; | ||
1214 | const unsigned long *crc; | ||
1215 | |||
1216 | for (i = 0; i < mod->num_syms; i++) | ||
1217 | if (__find_symbol(mod->syms[i].name, &owner, &crc, 1)) { | ||
1218 | name = mod->syms[i].name; | ||
1219 | ret = -ENOEXEC; | ||
1220 | goto dup; | ||
1221 | } | ||
1222 | |||
1223 | for (i = 0; i < mod->num_gpl_syms; i++) | ||
1224 | if (__find_symbol(mod->gpl_syms[i].name, &owner, &crc, 1)) { | ||
1225 | name = mod->gpl_syms[i].name; | ||
1226 | ret = -ENOEXEC; | ||
1227 | goto dup; | ||
1228 | } | ||
1229 | |||
1230 | dup: | ||
1231 | if (ret) | ||
1232 | printk(KERN_ERR "%s: exports duplicate symbol %s (owned by %s)\n", | ||
1233 | mod->name, name, module_name(owner)); | ||
1234 | |||
1235 | return ret; | ||
1236 | } | ||
1237 | |||
1207 | /* Change all symbols so that sh_value encodes the pointer directly. */ | 1238 | /* Change all symbols so that sh_value encodes the pointer directly. */ |
1208 | static int simplify_symbols(Elf_Shdr *sechdrs, | 1239 | static int simplify_symbols(Elf_Shdr *sechdrs, |
1209 | unsigned int symindex, | 1240 | unsigned int symindex, |
@@ -1715,6 +1746,11 @@ static struct module *load_module(void __user *umod, | |||
1715 | /* Set up license info based on the info section */ | 1746 | /* Set up license info based on the info section */ |
1716 | set_license(mod, get_modinfo(sechdrs, infoindex, "license")); | 1747 | set_license(mod, get_modinfo(sechdrs, infoindex, "license")); |
1717 | 1748 | ||
1749 | if (strcmp(mod->name, "ndiswrapper") == 0) | ||
1750 | add_taint(TAINT_PROPRIETARY_MODULE); | ||
1751 | if (strcmp(mod->name, "driverloader") == 0) | ||
1752 | add_taint(TAINT_PROPRIETARY_MODULE); | ||
1753 | |||
1718 | #ifdef CONFIG_MODULE_UNLOAD | 1754 | #ifdef CONFIG_MODULE_UNLOAD |
1719 | /* Set up MODINFO_ATTR fields */ | 1755 | /* Set up MODINFO_ATTR fields */ |
1720 | setup_modinfo(mod, sechdrs, infoindex); | 1756 | setup_modinfo(mod, sechdrs, infoindex); |
@@ -1767,6 +1803,12 @@ static struct module *load_module(void __user *umod, | |||
1767 | goto cleanup; | 1803 | goto cleanup; |
1768 | } | 1804 | } |
1769 | 1805 | ||
1806 | /* Find duplicate symbols */ | ||
1807 | err = verify_export_symbols(mod); | ||
1808 | |||
1809 | if (err < 0) | ||
1810 | goto cleanup; | ||
1811 | |||
1770 | /* Set up and sort exception table */ | 1812 | /* Set up and sort exception table */ |
1771 | mod->num_exentries = sechdrs[exindex].sh_size / sizeof(*mod->extable); | 1813 | mod->num_exentries = sechdrs[exindex].sh_size / sizeof(*mod->extable); |
1772 | mod->extable = extable = (void *)sechdrs[exindex].sh_addr; | 1814 | mod->extable = extable = (void *)sechdrs[exindex].sh_addr; |