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