1b33465feSAaron Tomlin // SPDX-License-Identifier: GPL-2.0-or-later 2b33465feSAaron Tomlin /* 3b33465feSAaron Tomlin * Module strict rwx 4b33465feSAaron Tomlin * 5b33465feSAaron Tomlin * Copyright (C) 2015 Rusty Russell 6b33465feSAaron Tomlin */ 7b33465feSAaron Tomlin 8b33465feSAaron Tomlin #include <linux/module.h> 9b33465feSAaron Tomlin #include <linux/mm.h> 10b33465feSAaron Tomlin #include <linux/vmalloc.h> 11b33465feSAaron Tomlin #include <linux/set_memory.h> 12b33465feSAaron Tomlin #include "internal.h" 13b33465feSAaron Tomlin 14*32a08c17SChristophe Leroy /* 15*32a08c17SChristophe Leroy * LKM RO/NX protection: protect module's text/ro-data 16*32a08c17SChristophe Leroy * from modification and any data from execution. 17*32a08c17SChristophe Leroy * 18*32a08c17SChristophe Leroy * General layout of module is: 19*32a08c17SChristophe Leroy * [text] [read-only-data] [ro-after-init] [writable data] 20*32a08c17SChristophe Leroy * text_size -----^ ^ ^ ^ 21*32a08c17SChristophe Leroy * ro_size ------------------------| | | 22*32a08c17SChristophe Leroy * ro_after_init_size -----------------------------| | 23*32a08c17SChristophe Leroy * size -----------------------------------------------------------| 24*32a08c17SChristophe Leroy * 25*32a08c17SChristophe Leroy * These values are always page-aligned (as is base) when 26*32a08c17SChristophe Leroy * CONFIG_STRICT_MODULE_RWX is set. 27*32a08c17SChristophe Leroy */ 28*32a08c17SChristophe Leroy 29*32a08c17SChristophe Leroy /* 30*32a08c17SChristophe Leroy * Since some arches are moving towards PAGE_KERNEL module allocations instead 31*32a08c17SChristophe Leroy * of PAGE_KERNEL_EXEC, keep frob_text() and module_enable_x() independent of 32*32a08c17SChristophe Leroy * CONFIG_STRICT_MODULE_RWX because they are needed regardless of whether we 33*32a08c17SChristophe Leroy * are strict. 34*32a08c17SChristophe Leroy */ 35*32a08c17SChristophe Leroy static void frob_text(const struct module_layout *layout, 36*32a08c17SChristophe Leroy int (*set_memory)(unsigned long start, int num_pages)) 37*32a08c17SChristophe Leroy { 38*32a08c17SChristophe Leroy set_memory((unsigned long)layout->base, 39*32a08c17SChristophe Leroy PAGE_ALIGN(layout->text_size) >> PAGE_SHIFT); 40*32a08c17SChristophe Leroy } 41*32a08c17SChristophe Leroy 42b33465feSAaron Tomlin static void frob_rodata(const struct module_layout *layout, 43b33465feSAaron Tomlin int (*set_memory)(unsigned long start, int num_pages)) 44b33465feSAaron Tomlin { 45b33465feSAaron Tomlin BUG_ON(!PAGE_ALIGNED(layout->base)); 46b33465feSAaron Tomlin BUG_ON(!PAGE_ALIGNED(layout->text_size)); 47b33465feSAaron Tomlin BUG_ON(!PAGE_ALIGNED(layout->ro_size)); 48b33465feSAaron Tomlin set_memory((unsigned long)layout->base + layout->text_size, 49b33465feSAaron Tomlin (layout->ro_size - layout->text_size) >> PAGE_SHIFT); 50b33465feSAaron Tomlin } 51b33465feSAaron Tomlin 52b33465feSAaron Tomlin static void frob_ro_after_init(const struct module_layout *layout, 53b33465feSAaron Tomlin int (*set_memory)(unsigned long start, int num_pages)) 54b33465feSAaron Tomlin { 55b33465feSAaron Tomlin BUG_ON(!PAGE_ALIGNED(layout->base)); 56b33465feSAaron Tomlin BUG_ON(!PAGE_ALIGNED(layout->ro_size)); 57b33465feSAaron Tomlin BUG_ON(!PAGE_ALIGNED(layout->ro_after_init_size)); 58b33465feSAaron Tomlin set_memory((unsigned long)layout->base + layout->ro_size, 59b33465feSAaron Tomlin (layout->ro_after_init_size - layout->ro_size) >> PAGE_SHIFT); 60b33465feSAaron Tomlin } 61b33465feSAaron Tomlin 62b33465feSAaron Tomlin static void frob_writable_data(const struct module_layout *layout, 63b33465feSAaron Tomlin int (*set_memory)(unsigned long start, int num_pages)) 64b33465feSAaron Tomlin { 65b33465feSAaron Tomlin BUG_ON(!PAGE_ALIGNED(layout->base)); 66b33465feSAaron Tomlin BUG_ON(!PAGE_ALIGNED(layout->ro_after_init_size)); 67b33465feSAaron Tomlin BUG_ON(!PAGE_ALIGNED(layout->size)); 68b33465feSAaron Tomlin set_memory((unsigned long)layout->base + layout->ro_after_init_size, 69b33465feSAaron Tomlin (layout->size - layout->ro_after_init_size) >> PAGE_SHIFT); 70b33465feSAaron Tomlin } 71b33465feSAaron Tomlin 72*32a08c17SChristophe Leroy void module_enable_x(const struct module *mod) 73*32a08c17SChristophe Leroy { 74*32a08c17SChristophe Leroy if (!PAGE_ALIGNED(mod->core_layout.base) || 75*32a08c17SChristophe Leroy !PAGE_ALIGNED(mod->init_layout.base)) 76*32a08c17SChristophe Leroy return; 77*32a08c17SChristophe Leroy 78*32a08c17SChristophe Leroy frob_text(&mod->core_layout, set_memory_x); 79*32a08c17SChristophe Leroy frob_text(&mod->init_layout, set_memory_x); 80*32a08c17SChristophe Leroy } 81*32a08c17SChristophe Leroy 82b33465feSAaron Tomlin void module_enable_ro(const struct module *mod, bool after_init) 83b33465feSAaron Tomlin { 84*32a08c17SChristophe Leroy if (!IS_ENABLED(CONFIG_STRICT_MODULE_RWX)) 85*32a08c17SChristophe Leroy return; 86*32a08c17SChristophe Leroy #ifdef CONFIG_STRICT_MODULE_RWX 87b33465feSAaron Tomlin if (!rodata_enabled) 88b33465feSAaron Tomlin return; 89*32a08c17SChristophe Leroy #endif 90b33465feSAaron Tomlin 91b33465feSAaron Tomlin set_vm_flush_reset_perms(mod->core_layout.base); 92b33465feSAaron Tomlin set_vm_flush_reset_perms(mod->init_layout.base); 93b33465feSAaron Tomlin frob_text(&mod->core_layout, set_memory_ro); 94b33465feSAaron Tomlin 95b33465feSAaron Tomlin frob_rodata(&mod->core_layout, set_memory_ro); 96b33465feSAaron Tomlin frob_text(&mod->init_layout, set_memory_ro); 97b33465feSAaron Tomlin frob_rodata(&mod->init_layout, set_memory_ro); 98b33465feSAaron Tomlin 99b33465feSAaron Tomlin if (after_init) 100b33465feSAaron Tomlin frob_ro_after_init(&mod->core_layout, set_memory_ro); 101b33465feSAaron Tomlin } 102b33465feSAaron Tomlin 103b33465feSAaron Tomlin void module_enable_nx(const struct module *mod) 104b33465feSAaron Tomlin { 105*32a08c17SChristophe Leroy if (!IS_ENABLED(CONFIG_STRICT_MODULE_RWX)) 106*32a08c17SChristophe Leroy return; 107*32a08c17SChristophe Leroy 108b33465feSAaron Tomlin frob_rodata(&mod->core_layout, set_memory_nx); 109b33465feSAaron Tomlin frob_ro_after_init(&mod->core_layout, set_memory_nx); 110b33465feSAaron Tomlin frob_writable_data(&mod->core_layout, set_memory_nx); 111b33465feSAaron Tomlin frob_rodata(&mod->init_layout, set_memory_nx); 112b33465feSAaron Tomlin frob_writable_data(&mod->init_layout, set_memory_nx); 113b33465feSAaron Tomlin } 114b33465feSAaron Tomlin 115b33465feSAaron Tomlin int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, 116b33465feSAaron Tomlin char *secstrings, struct module *mod) 117b33465feSAaron Tomlin { 118b33465feSAaron Tomlin const unsigned long shf_wx = SHF_WRITE | SHF_EXECINSTR; 119b33465feSAaron Tomlin int i; 120b33465feSAaron Tomlin 121*32a08c17SChristophe Leroy if (!IS_ENABLED(CONFIG_STRICT_MODULE_RWX)) 122*32a08c17SChristophe Leroy return 0; 123*32a08c17SChristophe Leroy 124b33465feSAaron Tomlin for (i = 0; i < hdr->e_shnum; i++) { 125b33465feSAaron Tomlin if ((sechdrs[i].sh_flags & shf_wx) == shf_wx) { 126b33465feSAaron Tomlin pr_err("%s: section %s (index %d) has invalid WRITE|EXEC flags\n", 127b33465feSAaron Tomlin mod->name, secstrings + sechdrs[i].sh_name, i); 128b33465feSAaron Tomlin return -ENOEXEC; 129b33465feSAaron Tomlin } 130b33465feSAaron Tomlin } 131b33465feSAaron Tomlin 132b33465feSAaron Tomlin return 0; 133b33465feSAaron Tomlin } 134