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); |
