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*ac3b4328SSong Liu static void module_set_memory(const struct module *mod, enum mod_mem_type type, 15*ac3b4328SSong Liu int (*set_memory)(unsigned long start, int num_pages)) 16*ac3b4328SSong Liu { 17*ac3b4328SSong Liu const struct module_memory *mod_mem = &mod->mem[type]; 18*ac3b4328SSong Liu 19*ac3b4328SSong Liu set_vm_flush_reset_perms(mod_mem->base); 20*ac3b4328SSong Liu set_memory((unsigned long)mod_mem->base, mod_mem->size >> PAGE_SHIFT); 21*ac3b4328SSong Liu } 2232a08c17SChristophe Leroy 2332a08c17SChristophe Leroy /* 2432a08c17SChristophe Leroy * Since some arches are moving towards PAGE_KERNEL module allocations instead 25*ac3b4328SSong Liu * of PAGE_KERNEL_EXEC, keep module_enable_x() independent of 2632a08c17SChristophe Leroy * CONFIG_STRICT_MODULE_RWX because they are needed regardless of whether we 2732a08c17SChristophe Leroy * are strict. 2832a08c17SChristophe Leroy */ 2932a08c17SChristophe Leroy void module_enable_x(const struct module *mod) 3032a08c17SChristophe Leroy { 31*ac3b4328SSong Liu for_class_mod_mem_type(type, text) 32*ac3b4328SSong Liu module_set_memory(mod, type, set_memory_x); 3332a08c17SChristophe Leroy } 3432a08c17SChristophe Leroy 35b33465feSAaron Tomlin void module_enable_ro(const struct module *mod, bool after_init) 36b33465feSAaron Tomlin { 3732a08c17SChristophe Leroy if (!IS_ENABLED(CONFIG_STRICT_MODULE_RWX)) 3832a08c17SChristophe Leroy return; 3932a08c17SChristophe Leroy #ifdef CONFIG_STRICT_MODULE_RWX 40b33465feSAaron Tomlin if (!rodata_enabled) 41b33465feSAaron Tomlin return; 4232a08c17SChristophe Leroy #endif 43b33465feSAaron Tomlin 44*ac3b4328SSong Liu module_set_memory(mod, MOD_TEXT, set_memory_ro); 45*ac3b4328SSong Liu module_set_memory(mod, MOD_INIT_TEXT, set_memory_ro); 46*ac3b4328SSong Liu module_set_memory(mod, MOD_RODATA, set_memory_ro); 47*ac3b4328SSong Liu module_set_memory(mod, MOD_INIT_RODATA, set_memory_ro); 48b33465feSAaron Tomlin 49b33465feSAaron Tomlin if (after_init) 50*ac3b4328SSong Liu module_set_memory(mod, MOD_RO_AFTER_INIT, set_memory_ro); 51b33465feSAaron Tomlin } 52b33465feSAaron Tomlin 53b33465feSAaron Tomlin void module_enable_nx(const struct module *mod) 54b33465feSAaron Tomlin { 5532a08c17SChristophe Leroy if (!IS_ENABLED(CONFIG_STRICT_MODULE_RWX)) 5632a08c17SChristophe Leroy return; 5732a08c17SChristophe Leroy 58*ac3b4328SSong Liu for_class_mod_mem_type(type, data) 59*ac3b4328SSong Liu module_set_memory(mod, type, set_memory_nx); 60b33465feSAaron Tomlin } 61b33465feSAaron Tomlin 62b33465feSAaron Tomlin int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, 63b33465feSAaron Tomlin char *secstrings, struct module *mod) 64b33465feSAaron Tomlin { 65b33465feSAaron Tomlin const unsigned long shf_wx = SHF_WRITE | SHF_EXECINSTR; 66b33465feSAaron Tomlin int i; 67b33465feSAaron Tomlin 6832a08c17SChristophe Leroy if (!IS_ENABLED(CONFIG_STRICT_MODULE_RWX)) 6932a08c17SChristophe Leroy return 0; 7032a08c17SChristophe Leroy 71b33465feSAaron Tomlin for (i = 0; i < hdr->e_shnum; i++) { 72b33465feSAaron Tomlin if ((sechdrs[i].sh_flags & shf_wx) == shf_wx) { 73b33465feSAaron Tomlin pr_err("%s: section %s (index %d) has invalid WRITE|EXEC flags\n", 74b33465feSAaron Tomlin mod->name, secstrings + sechdrs[i].sh_name, i); 75b33465feSAaron Tomlin return -ENOEXEC; 76b33465feSAaron Tomlin } 77b33465feSAaron Tomlin } 78b33465feSAaron Tomlin 79b33465feSAaron Tomlin return 0; 80b33465feSAaron Tomlin } 81