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