diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/module.c | 105 | ||||
| -rw-r--r-- | kernel/params.c | 23 |
2 files changed, 74 insertions, 54 deletions
diff --git a/kernel/module.c b/kernel/module.c index d5938a5c19c4..22879725678d 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
| @@ -57,6 +57,7 @@ | |||
| 57 | #include <linux/kmemleak.h> | 57 | #include <linux/kmemleak.h> |
| 58 | #include <linux/jump_label.h> | 58 | #include <linux/jump_label.h> |
| 59 | #include <linux/pfn.h> | 59 | #include <linux/pfn.h> |
| 60 | #include <linux/bsearch.h> | ||
| 60 | 61 | ||
| 61 | #define CREATE_TRACE_POINTS | 62 | #define CREATE_TRACE_POINTS |
| 62 | #include <trace/events/module.h> | 63 | #include <trace/events/module.h> |
| @@ -240,23 +241,24 @@ static bool each_symbol_in_section(const struct symsearch *arr, | |||
| 240 | struct module *owner, | 241 | struct module *owner, |
| 241 | bool (*fn)(const struct symsearch *syms, | 242 | bool (*fn)(const struct symsearch *syms, |
| 242 | struct module *owner, | 243 | struct module *owner, |
| 243 | unsigned int symnum, void *data), | 244 | void *data), |
| 244 | void *data) | 245 | void *data) |
| 245 | { | 246 | { |
| 246 | unsigned int i, j; | 247 | unsigned int j; |
| 247 | 248 | ||
| 248 | for (j = 0; j < arrsize; j++) { | 249 | for (j = 0; j < arrsize; j++) { |
| 249 | for (i = 0; i < arr[j].stop - arr[j].start; i++) | 250 | if (fn(&arr[j], owner, data)) |
| 250 | if (fn(&arr[j], owner, i, data)) | 251 | return true; |
| 251 | return true; | ||
| 252 | } | 252 | } |
| 253 | 253 | ||
| 254 | return false; | 254 | return false; |
| 255 | } | 255 | } |
| 256 | 256 | ||
| 257 | /* Returns true as soon as fn returns true, otherwise false. */ | 257 | /* Returns true as soon as fn returns true, otherwise false. */ |
| 258 | bool each_symbol(bool (*fn)(const struct symsearch *arr, struct module *owner, | 258 | bool each_symbol_section(bool (*fn)(const struct symsearch *arr, |
| 259 | unsigned int symnum, void *data), void *data) | 259 | struct module *owner, |
| 260 | void *data), | ||
| 261 | void *data) | ||
| 260 | { | 262 | { |
| 261 | struct module *mod; | 263 | struct module *mod; |
| 262 | static const struct symsearch arr[] = { | 264 | static const struct symsearch arr[] = { |
| @@ -309,7 +311,7 @@ bool each_symbol(bool (*fn)(const struct symsearch *arr, struct module *owner, | |||
| 309 | } | 311 | } |
| 310 | return false; | 312 | return false; |
| 311 | } | 313 | } |
| 312 | EXPORT_SYMBOL_GPL(each_symbol); | 314 | EXPORT_SYMBOL_GPL(each_symbol_section); |
| 313 | 315 | ||
| 314 | struct find_symbol_arg { | 316 | struct find_symbol_arg { |
| 315 | /* Input */ | 317 | /* Input */ |
| @@ -323,15 +325,12 @@ struct find_symbol_arg { | |||
| 323 | const struct kernel_symbol *sym; | 325 | const struct kernel_symbol *sym; |
| 324 | }; | 326 | }; |
| 325 | 327 | ||
| 326 | static bool find_symbol_in_section(const struct symsearch *syms, | 328 | static bool check_symbol(const struct symsearch *syms, |
| 327 | struct module *owner, | 329 | struct module *owner, |
| 328 | unsigned int symnum, void *data) | 330 | unsigned int symnum, void *data) |
| 329 | { | 331 | { |
| 330 | struct find_symbol_arg *fsa = data; | 332 | struct find_symbol_arg *fsa = data; |
| 331 | 333 | ||
| 332 | if (strcmp(syms->start[symnum].name, fsa->name) != 0) | ||
| 333 | return false; | ||
| 334 | |||
| 335 | if (!fsa->gplok) { | 334 | if (!fsa->gplok) { |
| 336 | if (syms->licence == GPL_ONLY) | 335 | if (syms->licence == GPL_ONLY) |
| 337 | return false; | 336 | return false; |
| @@ -365,6 +364,30 @@ static bool find_symbol_in_section(const struct symsearch *syms, | |||
| 365 | return true; | 364 | return true; |
| 366 | } | 365 | } |
| 367 | 366 | ||
| 367 | static int cmp_name(const void *va, const void *vb) | ||
| 368 | { | ||
| 369 | const char *a; | ||
| 370 | const struct kernel_symbol *b; | ||
| 371 | a = va; b = vb; | ||
| 372 | return strcmp(a, b->name); | ||
| 373 | } | ||
| 374 | |||
| 375 | static bool find_symbol_in_section(const struct symsearch *syms, | ||
| 376 | struct module *owner, | ||
| 377 | void *data) | ||
| 378 | { | ||
| 379 | struct find_symbol_arg *fsa = data; | ||
| 380 | struct kernel_symbol *sym; | ||
| 381 | |||
| 382 | sym = bsearch(fsa->name, syms->start, syms->stop - syms->start, | ||
| 383 | sizeof(struct kernel_symbol), cmp_name); | ||
| 384 | |||
| 385 | if (sym != NULL && check_symbol(syms, owner, sym - syms->start, data)) | ||
| 386 | return true; | ||
| 387 | |||
| 388 | return false; | ||
| 389 | } | ||
| 390 | |||
| 368 | /* Find a symbol and return it, along with, (optional) crc and | 391 | /* Find a symbol and return it, along with, (optional) crc and |
| 369 | * (optional) module which owns it. Needs preempt disabled or module_mutex. */ | 392 | * (optional) module which owns it. Needs preempt disabled or module_mutex. */ |
| 370 | const struct kernel_symbol *find_symbol(const char *name, | 393 | const struct kernel_symbol *find_symbol(const char *name, |
| @@ -379,7 +402,7 @@ const struct kernel_symbol *find_symbol(const char *name, | |||
| 379 | fsa.gplok = gplok; | 402 | fsa.gplok = gplok; |
| 380 | fsa.warn = warn; | 403 | fsa.warn = warn; |
| 381 | 404 | ||
| 382 | if (each_symbol(find_symbol_in_section, &fsa)) { | 405 | if (each_symbol_section(find_symbol_in_section, &fsa)) { |
| 383 | if (owner) | 406 | if (owner) |
| 384 | *owner = fsa.owner; | 407 | *owner = fsa.owner; |
| 385 | if (crc) | 408 | if (crc) |
| @@ -1607,27 +1630,28 @@ static void set_section_ro_nx(void *base, | |||
| 1607 | } | 1630 | } |
| 1608 | } | 1631 | } |
| 1609 | 1632 | ||
| 1610 | /* Setting memory back to RW+NX before releasing it */ | 1633 | static void unset_module_core_ro_nx(struct module *mod) |
| 1611 | void unset_section_ro_nx(struct module *mod, void *module_region) | ||
| 1612 | { | 1634 | { |
| 1613 | unsigned long total_pages; | 1635 | set_page_attributes(mod->module_core + mod->core_text_size, |
| 1614 | 1636 | mod->module_core + mod->core_size, | |
| 1615 | if (mod->module_core == module_region) { | 1637 | set_memory_x); |
| 1616 | /* Set core as NX+RW */ | 1638 | set_page_attributes(mod->module_core, |
| 1617 | total_pages = MOD_NUMBER_OF_PAGES(mod->module_core, mod->core_size); | 1639 | mod->module_core + mod->core_ro_size, |
| 1618 | set_memory_nx((unsigned long)mod->module_core, total_pages); | 1640 | set_memory_rw); |
| 1619 | set_memory_rw((unsigned long)mod->module_core, total_pages); | 1641 | } |
| 1620 | 1642 | ||
| 1621 | } else if (mod->module_init == module_region) { | 1643 | static void unset_module_init_ro_nx(struct module *mod) |
| 1622 | /* Set init as NX+RW */ | 1644 | { |
| 1623 | total_pages = MOD_NUMBER_OF_PAGES(mod->module_init, mod->init_size); | 1645 | set_page_attributes(mod->module_init + mod->init_text_size, |
| 1624 | set_memory_nx((unsigned long)mod->module_init, total_pages); | 1646 | mod->module_init + mod->init_size, |
| 1625 | set_memory_rw((unsigned long)mod->module_init, total_pages); | 1647 | set_memory_x); |
| 1626 | } | 1648 | set_page_attributes(mod->module_init, |
| 1649 | mod->module_init + mod->init_ro_size, | ||
| 1650 | set_memory_rw); | ||
| 1627 | } | 1651 | } |
| 1628 | 1652 | ||
| 1629 | /* Iterate through all modules and set each module's text as RW */ | 1653 | /* Iterate through all modules and set each module's text as RW */ |
| 1630 | void set_all_modules_text_rw() | 1654 | void set_all_modules_text_rw(void) |
| 1631 | { | 1655 | { |
| 1632 | struct module *mod; | 1656 | struct module *mod; |
| 1633 | 1657 | ||
| @@ -1648,7 +1672,7 @@ void set_all_modules_text_rw() | |||
| 1648 | } | 1672 | } |
| 1649 | 1673 | ||
| 1650 | /* Iterate through all modules and set each module's text as RO */ | 1674 | /* Iterate through all modules and set each module's text as RO */ |
| 1651 | void set_all_modules_text_ro() | 1675 | void set_all_modules_text_ro(void) |
| 1652 | { | 1676 | { |
| 1653 | struct module *mod; | 1677 | struct module *mod; |
| 1654 | 1678 | ||
| @@ -1669,7 +1693,8 @@ void set_all_modules_text_ro() | |||
| 1669 | } | 1693 | } |
| 1670 | #else | 1694 | #else |
| 1671 | static inline void set_section_ro_nx(void *base, unsigned long text_size, unsigned long ro_size, unsigned long total_size) { } | 1695 | static inline void set_section_ro_nx(void *base, unsigned long text_size, unsigned long ro_size, unsigned long total_size) { } |
| 1672 | static inline void unset_section_ro_nx(struct module *mod, void *module_region) { } | 1696 | static void unset_module_core_ro_nx(struct module *mod) { } |
| 1697 | static void unset_module_init_ro_nx(struct module *mod) { } | ||
| 1673 | #endif | 1698 | #endif |
| 1674 | 1699 | ||
| 1675 | /* Free a module, remove from lists, etc. */ | 1700 | /* Free a module, remove from lists, etc. */ |
| @@ -1696,7 +1721,7 @@ static void free_module(struct module *mod) | |||
| 1696 | destroy_params(mod->kp, mod->num_kp); | 1721 | destroy_params(mod->kp, mod->num_kp); |
| 1697 | 1722 | ||
| 1698 | /* This may be NULL, but that's OK */ | 1723 | /* This may be NULL, but that's OK */ |
| 1699 | unset_section_ro_nx(mod, mod->module_init); | 1724 | unset_module_init_ro_nx(mod); |
| 1700 | module_free(mod, mod->module_init); | 1725 | module_free(mod, mod->module_init); |
| 1701 | kfree(mod->args); | 1726 | kfree(mod->args); |
| 1702 | percpu_modfree(mod); | 1727 | percpu_modfree(mod); |
| @@ -1705,7 +1730,7 @@ static void free_module(struct module *mod) | |||
| 1705 | lockdep_free_key_range(mod->module_core, mod->core_size); | 1730 | lockdep_free_key_range(mod->module_core, mod->core_size); |
| 1706 | 1731 | ||
| 1707 | /* Finally, free the core (containing the module structure) */ | 1732 | /* Finally, free the core (containing the module structure) */ |
| 1708 | unset_section_ro_nx(mod, mod->module_core); | 1733 | unset_module_core_ro_nx(mod); |
| 1709 | module_free(mod, mod->module_core); | 1734 | module_free(mod, mod->module_core); |
| 1710 | 1735 | ||
| 1711 | #ifdef CONFIG_MPU | 1736 | #ifdef CONFIG_MPU |
| @@ -2030,11 +2055,8 @@ static const struct kernel_symbol *lookup_symbol(const char *name, | |||
| 2030 | const struct kernel_symbol *start, | 2055 | const struct kernel_symbol *start, |
| 2031 | const struct kernel_symbol *stop) | 2056 | const struct kernel_symbol *stop) |
| 2032 | { | 2057 | { |
| 2033 | const struct kernel_symbol *ks = start; | 2058 | return bsearch(name, start, stop - start, |
| 2034 | for (; ks < stop; ks++) | 2059 | sizeof(struct kernel_symbol), cmp_name); |
| 2035 | if (strcmp(ks->name, name) == 0) | ||
| 2036 | return ks; | ||
| 2037 | return NULL; | ||
| 2038 | } | 2060 | } |
| 2039 | 2061 | ||
| 2040 | static int is_exported(const char *name, unsigned long value, | 2062 | static int is_exported(const char *name, unsigned long value, |
| @@ -2931,10 +2953,11 @@ SYSCALL_DEFINE3(init_module, void __user *, umod, | |||
| 2931 | mod->symtab = mod->core_symtab; | 2953 | mod->symtab = mod->core_symtab; |
| 2932 | mod->strtab = mod->core_strtab; | 2954 | mod->strtab = mod->core_strtab; |
| 2933 | #endif | 2955 | #endif |
| 2934 | unset_section_ro_nx(mod, mod->module_init); | 2956 | unset_module_init_ro_nx(mod); |
| 2935 | module_free(mod, mod->module_init); | 2957 | module_free(mod, mod->module_init); |
| 2936 | mod->module_init = NULL; | 2958 | mod->module_init = NULL; |
| 2937 | mod->init_size = 0; | 2959 | mod->init_size = 0; |
| 2960 | mod->init_ro_size = 0; | ||
| 2938 | mod->init_text_size = 0; | 2961 | mod->init_text_size = 0; |
| 2939 | mutex_unlock(&module_mutex); | 2962 | mutex_unlock(&module_mutex); |
| 2940 | 2963 | ||
diff --git a/kernel/params.c b/kernel/params.c index 7ab388a48a2e..ed72e1330862 100644 --- a/kernel/params.c +++ b/kernel/params.c | |||
| @@ -297,21 +297,15 @@ EXPORT_SYMBOL(param_ops_charp); | |||
| 297 | int param_set_bool(const char *val, const struct kernel_param *kp) | 297 | int param_set_bool(const char *val, const struct kernel_param *kp) |
| 298 | { | 298 | { |
| 299 | bool v; | 299 | bool v; |
| 300 | int ret; | ||
| 300 | 301 | ||
| 301 | /* No equals means "set"... */ | 302 | /* No equals means "set"... */ |
| 302 | if (!val) val = "1"; | 303 | if (!val) val = "1"; |
| 303 | 304 | ||
| 304 | /* One of =[yYnN01] */ | 305 | /* One of =[yYnN01] */ |
| 305 | switch (val[0]) { | 306 | ret = strtobool(val, &v); |
| 306 | case 'y': case 'Y': case '1': | 307 | if (ret) |
| 307 | v = true; | 308 | return ret; |
| 308 | break; | ||
| 309 | case 'n': case 'N': case '0': | ||
| 310 | v = false; | ||
| 311 | break; | ||
| 312 | default: | ||
| 313 | return -EINVAL; | ||
| 314 | } | ||
| 315 | 309 | ||
| 316 | if (kp->flags & KPARAM_ISBOOL) | 310 | if (kp->flags & KPARAM_ISBOOL) |
| 317 | *(bool *)kp->arg = v; | 311 | *(bool *)kp->arg = v; |
| @@ -821,15 +815,18 @@ ssize_t __modver_version_show(struct module_attribute *mattr, | |||
| 821 | return sprintf(buf, "%s\n", vattr->version); | 815 | return sprintf(buf, "%s\n", vattr->version); |
| 822 | } | 816 | } |
| 823 | 817 | ||
| 824 | extern struct module_version_attribute __start___modver[], __stop___modver[]; | 818 | extern const struct module_version_attribute *__start___modver[]; |
| 819 | extern const struct module_version_attribute *__stop___modver[]; | ||
| 825 | 820 | ||
| 826 | static void __init version_sysfs_builtin(void) | 821 | static void __init version_sysfs_builtin(void) |
| 827 | { | 822 | { |
| 828 | const struct module_version_attribute *vattr; | 823 | const struct module_version_attribute **p; |
| 829 | struct module_kobject *mk; | 824 | struct module_kobject *mk; |
| 830 | int err; | 825 | int err; |
| 831 | 826 | ||
| 832 | for (vattr = __start___modver; vattr < __stop___modver; vattr++) { | 827 | for (p = __start___modver; p < __stop___modver; p++) { |
| 828 | const struct module_version_attribute *vattr = *p; | ||
| 829 | |||
| 833 | mk = locate_module_kobject(vattr->module_name); | 830 | mk = locate_module_kobject(vattr->module_name); |
| 834 | if (mk) { | 831 | if (mk) { |
| 835 | err = sysfs_create_file(&mk->kobj, &vattr->mattr.attr); | 832 | err = sysfs_create_file(&mk->kobj, &vattr->mattr.attr); |
