diff options
Diffstat (limited to 'kernel/module.c')
| -rw-r--r-- | kernel/module.c | 187 |
1 files changed, 177 insertions, 10 deletions
diff --git a/kernel/module.c b/kernel/module.c index d190664f25ff..efa290ea94bf 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
| @@ -56,6 +56,7 @@ | |||
| 56 | #include <linux/percpu.h> | 56 | #include <linux/percpu.h> |
| 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 | 60 | ||
| 60 | #define CREATE_TRACE_POINTS | 61 | #define CREATE_TRACE_POINTS |
| 61 | #include <trace/events/module.h> | 62 | #include <trace/events/module.h> |
| @@ -70,6 +71,26 @@ | |||
| 70 | #define ARCH_SHF_SMALL 0 | 71 | #define ARCH_SHF_SMALL 0 |
| 71 | #endif | 72 | #endif |
| 72 | 73 | ||
| 74 | /* | ||
| 75 | * Modules' sections will be aligned on page boundaries | ||
| 76 | * to ensure complete separation of code and data, but | ||
| 77 | * only when CONFIG_DEBUG_SET_MODULE_RONX=y | ||
| 78 | */ | ||
| 79 | #ifdef CONFIG_DEBUG_SET_MODULE_RONX | ||
| 80 | # define debug_align(X) ALIGN(X, PAGE_SIZE) | ||
| 81 | #else | ||
| 82 | # define debug_align(X) (X) | ||
| 83 | #endif | ||
| 84 | |||
| 85 | /* | ||
| 86 | * Given BASE and SIZE this macro calculates the number of pages the | ||
| 87 | * memory regions occupies | ||
| 88 | */ | ||
| 89 | #define MOD_NUMBER_OF_PAGES(BASE, SIZE) (((SIZE) > 0) ? \ | ||
| 90 | (PFN_DOWN((unsigned long)(BASE) + (SIZE) - 1) - \ | ||
| 91 | PFN_DOWN((unsigned long)BASE) + 1) \ | ||
| 92 | : (0UL)) | ||
| 93 | |||
| 73 | /* If this is set, the section belongs in the init part of the module */ | 94 | /* If this is set, the section belongs in the init part of the module */ |
| 74 | #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1)) | 95 | #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1)) |
| 75 | 96 | ||
| @@ -1542,6 +1563,115 @@ static int __unlink_module(void *_mod) | |||
| 1542 | return 0; | 1563 | return 0; |
| 1543 | } | 1564 | } |
| 1544 | 1565 | ||
| 1566 | #ifdef CONFIG_DEBUG_SET_MODULE_RONX | ||
| 1567 | /* | ||
| 1568 | * LKM RO/NX protection: protect module's text/ro-data | ||
| 1569 | * from modification and any data from execution. | ||
| 1570 | */ | ||
| 1571 | void set_page_attributes(void *start, void *end, int (*set)(unsigned long start, int num_pages)) | ||
| 1572 | { | ||
| 1573 | unsigned long begin_pfn = PFN_DOWN((unsigned long)start); | ||
| 1574 | unsigned long end_pfn = PFN_DOWN((unsigned long)end); | ||
| 1575 | |||
| 1576 | if (end_pfn > begin_pfn) | ||
| 1577 | set(begin_pfn << PAGE_SHIFT, end_pfn - begin_pfn); | ||
| 1578 | } | ||
| 1579 | |||
| 1580 | static void set_section_ro_nx(void *base, | ||
| 1581 | unsigned long text_size, | ||
| 1582 | unsigned long ro_size, | ||
| 1583 | unsigned long total_size) | ||
| 1584 | { | ||
| 1585 | /* begin and end PFNs of the current subsection */ | ||
| 1586 | unsigned long begin_pfn; | ||
| 1587 | unsigned long end_pfn; | ||
| 1588 | |||
| 1589 | /* | ||
| 1590 | * Set RO for module text and RO-data: | ||
| 1591 | * - Always protect first page. | ||
| 1592 | * - Do not protect last partial page. | ||
| 1593 | */ | ||
| 1594 | if (ro_size > 0) | ||
| 1595 | set_page_attributes(base, base + ro_size, set_memory_ro); | ||
| 1596 | |||
| 1597 | /* | ||
| 1598 | * Set NX permissions for module data: | ||
| 1599 | * - Do not protect first partial page. | ||
| 1600 | * - Always protect last page. | ||
| 1601 | */ | ||
| 1602 | if (total_size > text_size) { | ||
| 1603 | begin_pfn = PFN_UP((unsigned long)base + text_size); | ||
| 1604 | end_pfn = PFN_UP((unsigned long)base + total_size); | ||
| 1605 | if (end_pfn > begin_pfn) | ||
| 1606 | set_memory_nx(begin_pfn << PAGE_SHIFT, end_pfn - begin_pfn); | ||
| 1607 | } | ||
| 1608 | } | ||
| 1609 | |||
| 1610 | /* Setting memory back to RW+NX before releasing it */ | ||
| 1611 | void unset_section_ro_nx(struct module *mod, void *module_region) | ||
| 1612 | { | ||
| 1613 | unsigned long total_pages; | ||
| 1614 | |||
| 1615 | if (mod->module_core == module_region) { | ||
| 1616 | /* Set core as NX+RW */ | ||
| 1617 | total_pages = MOD_NUMBER_OF_PAGES(mod->module_core, mod->core_size); | ||
| 1618 | set_memory_nx((unsigned long)mod->module_core, total_pages); | ||
| 1619 | set_memory_rw((unsigned long)mod->module_core, total_pages); | ||
| 1620 | |||
| 1621 | } else if (mod->module_init == module_region) { | ||
| 1622 | /* Set init as NX+RW */ | ||
| 1623 | total_pages = MOD_NUMBER_OF_PAGES(mod->module_init, mod->init_size); | ||
| 1624 | set_memory_nx((unsigned long)mod->module_init, total_pages); | ||
| 1625 | set_memory_rw((unsigned long)mod->module_init, total_pages); | ||
| 1626 | } | ||
| 1627 | } | ||
| 1628 | |||
| 1629 | /* Iterate through all modules and set each module's text as RW */ | ||
| 1630 | void set_all_modules_text_rw() | ||
| 1631 | { | ||
| 1632 | struct module *mod; | ||
| 1633 | |||
| 1634 | mutex_lock(&module_mutex); | ||
| 1635 | list_for_each_entry_rcu(mod, &modules, list) { | ||
| 1636 | if ((mod->module_core) && (mod->core_text_size)) { | ||
| 1637 | set_page_attributes(mod->module_core, | ||
| 1638 | mod->module_core + mod->core_text_size, | ||
| 1639 | set_memory_rw); | ||
| 1640 | } | ||
| 1641 | if ((mod->module_init) && (mod->init_text_size)) { | ||
| 1642 | set_page_attributes(mod->module_init, | ||
| 1643 | mod->module_init + mod->init_text_size, | ||
| 1644 | set_memory_rw); | ||
| 1645 | } | ||
| 1646 | } | ||
| 1647 | mutex_unlock(&module_mutex); | ||
| 1648 | } | ||
| 1649 | |||
| 1650 | /* Iterate through all modules and set each module's text as RO */ | ||
| 1651 | void set_all_modules_text_ro() | ||
| 1652 | { | ||
| 1653 | struct module *mod; | ||
| 1654 | |||
| 1655 | mutex_lock(&module_mutex); | ||
| 1656 | list_for_each_entry_rcu(mod, &modules, list) { | ||
| 1657 | if ((mod->module_core) && (mod->core_text_size)) { | ||
| 1658 | set_page_attributes(mod->module_core, | ||
| 1659 | mod->module_core + mod->core_text_size, | ||
| 1660 | set_memory_ro); | ||
| 1661 | } | ||
| 1662 | if ((mod->module_init) && (mod->init_text_size)) { | ||
| 1663 | set_page_attributes(mod->module_init, | ||
| 1664 | mod->module_init + mod->init_text_size, | ||
| 1665 | set_memory_ro); | ||
| 1666 | } | ||
| 1667 | } | ||
| 1668 | mutex_unlock(&module_mutex); | ||
| 1669 | } | ||
| 1670 | #else | ||
| 1671 | 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) { } | ||
| 1673 | #endif | ||
| 1674 | |||
| 1545 | /* Free a module, remove from lists, etc. */ | 1675 | /* Free a module, remove from lists, etc. */ |
| 1546 | static void free_module(struct module *mod) | 1676 | static void free_module(struct module *mod) |
| 1547 | { | 1677 | { |
| @@ -1566,6 +1696,7 @@ static void free_module(struct module *mod) | |||
| 1566 | destroy_params(mod->kp, mod->num_kp); | 1696 | destroy_params(mod->kp, mod->num_kp); |
| 1567 | 1697 | ||
| 1568 | /* This may be NULL, but that's OK */ | 1698 | /* This may be NULL, but that's OK */ |
| 1699 | unset_section_ro_nx(mod, mod->module_init); | ||
| 1569 | module_free(mod, mod->module_init); | 1700 | module_free(mod, mod->module_init); |
| 1570 | kfree(mod->args); | 1701 | kfree(mod->args); |
| 1571 | percpu_modfree(mod); | 1702 | percpu_modfree(mod); |
| @@ -1574,6 +1705,7 @@ static void free_module(struct module *mod) | |||
| 1574 | lockdep_free_key_range(mod->module_core, mod->core_size); | 1705 | lockdep_free_key_range(mod->module_core, mod->core_size); |
| 1575 | 1706 | ||
| 1576 | /* Finally, free the core (containing the module structure) */ | 1707 | /* Finally, free the core (containing the module structure) */ |
| 1708 | unset_section_ro_nx(mod, mod->module_core); | ||
| 1577 | module_free(mod, mod->module_core); | 1709 | module_free(mod, mod->module_core); |
| 1578 | 1710 | ||
| 1579 | #ifdef CONFIG_MPU | 1711 | #ifdef CONFIG_MPU |
| @@ -1777,8 +1909,19 @@ static void layout_sections(struct module *mod, struct load_info *info) | |||
| 1777 | s->sh_entsize = get_offset(mod, &mod->core_size, s, i); | 1909 | s->sh_entsize = get_offset(mod, &mod->core_size, s, i); |
| 1778 | DEBUGP("\t%s\n", name); | 1910 | DEBUGP("\t%s\n", name); |
| 1779 | } | 1911 | } |
| 1780 | if (m == 0) | 1912 | switch (m) { |
| 1913 | case 0: /* executable */ | ||
| 1914 | mod->core_size = debug_align(mod->core_size); | ||
| 1781 | mod->core_text_size = mod->core_size; | 1915 | mod->core_text_size = mod->core_size; |
| 1916 | break; | ||
| 1917 | case 1: /* RO: text and ro-data */ | ||
| 1918 | mod->core_size = debug_align(mod->core_size); | ||
| 1919 | mod->core_ro_size = mod->core_size; | ||
| 1920 | break; | ||
| 1921 | case 3: /* whole core */ | ||
| 1922 | mod->core_size = debug_align(mod->core_size); | ||
| 1923 | break; | ||
| 1924 | } | ||
| 1782 | } | 1925 | } |
| 1783 | 1926 | ||
| 1784 | DEBUGP("Init section allocation order:\n"); | 1927 | DEBUGP("Init section allocation order:\n"); |
| @@ -1796,8 +1939,19 @@ static void layout_sections(struct module *mod, struct load_info *info) | |||
| 1796 | | INIT_OFFSET_MASK); | 1939 | | INIT_OFFSET_MASK); |
| 1797 | DEBUGP("\t%s\n", sname); | 1940 | DEBUGP("\t%s\n", sname); |
| 1798 | } | 1941 | } |
| 1799 | if (m == 0) | 1942 | switch (m) { |
| 1943 | case 0: /* executable */ | ||
| 1944 | mod->init_size = debug_align(mod->init_size); | ||
| 1800 | mod->init_text_size = mod->init_size; | 1945 | mod->init_text_size = mod->init_size; |
| 1946 | break; | ||
| 1947 | case 1: /* RO: text and ro-data */ | ||
| 1948 | mod->init_size = debug_align(mod->init_size); | ||
| 1949 | mod->init_ro_size = mod->init_size; | ||
| 1950 | break; | ||
| 1951 | case 3: /* whole init */ | ||
| 1952 | mod->init_size = debug_align(mod->init_size); | ||
| 1953 | break; | ||
| 1954 | } | ||
| 1801 | } | 1955 | } |
| 1802 | } | 1956 | } |
| 1803 | 1957 | ||
| @@ -2306,9 +2460,9 @@ static void find_module_sections(struct module *mod, struct load_info *info) | |||
| 2306 | #endif | 2460 | #endif |
| 2307 | 2461 | ||
| 2308 | #ifdef CONFIG_TRACEPOINTS | 2462 | #ifdef CONFIG_TRACEPOINTS |
| 2309 | mod->tracepoints = section_objs(info, "__tracepoints", | 2463 | mod->tracepoints_ptrs = section_objs(info, "__tracepoints_ptrs", |
| 2310 | sizeof(*mod->tracepoints), | 2464 | sizeof(*mod->tracepoints_ptrs), |
| 2311 | &mod->num_tracepoints); | 2465 | &mod->num_tracepoints); |
| 2312 | #endif | 2466 | #endif |
| 2313 | #ifdef HAVE_JUMP_LABEL | 2467 | #ifdef HAVE_JUMP_LABEL |
| 2314 | mod->jump_entries = section_objs(info, "__jump_table", | 2468 | mod->jump_entries = section_objs(info, "__jump_table", |
| @@ -2722,6 +2876,18 @@ SYSCALL_DEFINE3(init_module, void __user *, umod, | |||
| 2722 | blocking_notifier_call_chain(&module_notify_list, | 2876 | blocking_notifier_call_chain(&module_notify_list, |
| 2723 | MODULE_STATE_COMING, mod); | 2877 | MODULE_STATE_COMING, mod); |
| 2724 | 2878 | ||
| 2879 | /* Set RO and NX regions for core */ | ||
| 2880 | set_section_ro_nx(mod->module_core, | ||
| 2881 | mod->core_text_size, | ||
| 2882 | mod->core_ro_size, | ||
| 2883 | mod->core_size); | ||
| 2884 | |||
| 2885 | /* Set RO and NX regions for init */ | ||
| 2886 | set_section_ro_nx(mod->module_init, | ||
| 2887 | mod->init_text_size, | ||
| 2888 | mod->init_ro_size, | ||
| 2889 | mod->init_size); | ||
| 2890 | |||
| 2725 | do_mod_ctors(mod); | 2891 | do_mod_ctors(mod); |
| 2726 | /* Start the module */ | 2892 | /* Start the module */ |
| 2727 | if (mod->init != NULL) | 2893 | if (mod->init != NULL) |
| @@ -2765,6 +2931,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod, | |||
| 2765 | mod->symtab = mod->core_symtab; | 2931 | mod->symtab = mod->core_symtab; |
| 2766 | mod->strtab = mod->core_strtab; | 2932 | mod->strtab = mod->core_strtab; |
| 2767 | #endif | 2933 | #endif |
| 2934 | unset_section_ro_nx(mod, mod->module_init); | ||
| 2768 | module_free(mod, mod->module_init); | 2935 | module_free(mod, mod->module_init); |
| 2769 | mod->module_init = NULL; | 2936 | mod->module_init = NULL; |
| 2770 | mod->init_size = 0; | 2937 | mod->init_size = 0; |
| @@ -3226,7 +3393,7 @@ void module_layout(struct module *mod, | |||
| 3226 | struct modversion_info *ver, | 3393 | struct modversion_info *ver, |
| 3227 | struct kernel_param *kp, | 3394 | struct kernel_param *kp, |
| 3228 | struct kernel_symbol *ks, | 3395 | struct kernel_symbol *ks, |
| 3229 | struct tracepoint *tp) | 3396 | struct tracepoint * const *tp) |
| 3230 | { | 3397 | { |
| 3231 | } | 3398 | } |
| 3232 | EXPORT_SYMBOL(module_layout); | 3399 | EXPORT_SYMBOL(module_layout); |
| @@ -3240,8 +3407,8 @@ void module_update_tracepoints(void) | |||
| 3240 | mutex_lock(&module_mutex); | 3407 | mutex_lock(&module_mutex); |
| 3241 | list_for_each_entry(mod, &modules, list) | 3408 | list_for_each_entry(mod, &modules, list) |
| 3242 | if (!mod->taints) | 3409 | if (!mod->taints) |
| 3243 | tracepoint_update_probe_range(mod->tracepoints, | 3410 | tracepoint_update_probe_range(mod->tracepoints_ptrs, |
| 3244 | mod->tracepoints + mod->num_tracepoints); | 3411 | mod->tracepoints_ptrs + mod->num_tracepoints); |
| 3245 | mutex_unlock(&module_mutex); | 3412 | mutex_unlock(&module_mutex); |
| 3246 | } | 3413 | } |
| 3247 | 3414 | ||
| @@ -3265,8 +3432,8 @@ int module_get_iter_tracepoints(struct tracepoint_iter *iter) | |||
| 3265 | else if (iter_mod > iter->module) | 3432 | else if (iter_mod > iter->module) |
| 3266 | iter->tracepoint = NULL; | 3433 | iter->tracepoint = NULL; |
| 3267 | found = tracepoint_get_iter_range(&iter->tracepoint, | 3434 | found = tracepoint_get_iter_range(&iter->tracepoint, |
| 3268 | iter_mod->tracepoints, | 3435 | iter_mod->tracepoints_ptrs, |
| 3269 | iter_mod->tracepoints | 3436 | iter_mod->tracepoints_ptrs |
| 3270 | + iter_mod->num_tracepoints); | 3437 | + iter_mod->num_tracepoints); |
| 3271 | if (found) { | 3438 | if (found) { |
| 3272 | iter->module = iter_mod; | 3439 | iter->module = iter_mod; |
