1*b33465feSAaron Tomlin // SPDX-License-Identifier: GPL-2.0-or-later 2*b33465feSAaron Tomlin /* 3*b33465feSAaron Tomlin * Module strict rwx 4*b33465feSAaron Tomlin * 5*b33465feSAaron Tomlin * Copyright (C) 2015 Rusty Russell 6*b33465feSAaron Tomlin */ 7*b33465feSAaron Tomlin 8*b33465feSAaron Tomlin #include <linux/module.h> 9*b33465feSAaron Tomlin #include <linux/mm.h> 10*b33465feSAaron Tomlin #include <linux/vmalloc.h> 11*b33465feSAaron Tomlin #include <linux/set_memory.h> 12*b33465feSAaron Tomlin #include "internal.h" 13*b33465feSAaron Tomlin 14*b33465feSAaron Tomlin static void frob_rodata(const struct module_layout *layout, 15*b33465feSAaron Tomlin int (*set_memory)(unsigned long start, int num_pages)) 16*b33465feSAaron Tomlin { 17*b33465feSAaron Tomlin BUG_ON(!PAGE_ALIGNED(layout->base)); 18*b33465feSAaron Tomlin BUG_ON(!PAGE_ALIGNED(layout->text_size)); 19*b33465feSAaron Tomlin BUG_ON(!PAGE_ALIGNED(layout->ro_size)); 20*b33465feSAaron Tomlin set_memory((unsigned long)layout->base + layout->text_size, 21*b33465feSAaron Tomlin (layout->ro_size - layout->text_size) >> PAGE_SHIFT); 22*b33465feSAaron Tomlin } 23*b33465feSAaron Tomlin 24*b33465feSAaron Tomlin static void frob_ro_after_init(const struct module_layout *layout, 25*b33465feSAaron Tomlin int (*set_memory)(unsigned long start, int num_pages)) 26*b33465feSAaron Tomlin { 27*b33465feSAaron Tomlin BUG_ON(!PAGE_ALIGNED(layout->base)); 28*b33465feSAaron Tomlin BUG_ON(!PAGE_ALIGNED(layout->ro_size)); 29*b33465feSAaron Tomlin BUG_ON(!PAGE_ALIGNED(layout->ro_after_init_size)); 30*b33465feSAaron Tomlin set_memory((unsigned long)layout->base + layout->ro_size, 31*b33465feSAaron Tomlin (layout->ro_after_init_size - layout->ro_size) >> PAGE_SHIFT); 32*b33465feSAaron Tomlin } 33*b33465feSAaron Tomlin 34*b33465feSAaron Tomlin static void frob_writable_data(const struct module_layout *layout, 35*b33465feSAaron Tomlin int (*set_memory)(unsigned long start, int num_pages)) 36*b33465feSAaron Tomlin { 37*b33465feSAaron Tomlin BUG_ON(!PAGE_ALIGNED(layout->base)); 38*b33465feSAaron Tomlin BUG_ON(!PAGE_ALIGNED(layout->ro_after_init_size)); 39*b33465feSAaron Tomlin BUG_ON(!PAGE_ALIGNED(layout->size)); 40*b33465feSAaron Tomlin set_memory((unsigned long)layout->base + layout->ro_after_init_size, 41*b33465feSAaron Tomlin (layout->size - layout->ro_after_init_size) >> PAGE_SHIFT); 42*b33465feSAaron Tomlin } 43*b33465feSAaron Tomlin 44*b33465feSAaron Tomlin void module_enable_ro(const struct module *mod, bool after_init) 45*b33465feSAaron Tomlin { 46*b33465feSAaron Tomlin if (!rodata_enabled) 47*b33465feSAaron Tomlin return; 48*b33465feSAaron Tomlin 49*b33465feSAaron Tomlin set_vm_flush_reset_perms(mod->core_layout.base); 50*b33465feSAaron Tomlin set_vm_flush_reset_perms(mod->init_layout.base); 51*b33465feSAaron Tomlin frob_text(&mod->core_layout, set_memory_ro); 52*b33465feSAaron Tomlin 53*b33465feSAaron Tomlin frob_rodata(&mod->core_layout, set_memory_ro); 54*b33465feSAaron Tomlin frob_text(&mod->init_layout, set_memory_ro); 55*b33465feSAaron Tomlin frob_rodata(&mod->init_layout, set_memory_ro); 56*b33465feSAaron Tomlin 57*b33465feSAaron Tomlin if (after_init) 58*b33465feSAaron Tomlin frob_ro_after_init(&mod->core_layout, set_memory_ro); 59*b33465feSAaron Tomlin } 60*b33465feSAaron Tomlin 61*b33465feSAaron Tomlin void module_enable_nx(const struct module *mod) 62*b33465feSAaron Tomlin { 63*b33465feSAaron Tomlin frob_rodata(&mod->core_layout, set_memory_nx); 64*b33465feSAaron Tomlin frob_ro_after_init(&mod->core_layout, set_memory_nx); 65*b33465feSAaron Tomlin frob_writable_data(&mod->core_layout, set_memory_nx); 66*b33465feSAaron Tomlin frob_rodata(&mod->init_layout, set_memory_nx); 67*b33465feSAaron Tomlin frob_writable_data(&mod->init_layout, set_memory_nx); 68*b33465feSAaron Tomlin } 69*b33465feSAaron Tomlin 70*b33465feSAaron Tomlin int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, 71*b33465feSAaron Tomlin char *secstrings, struct module *mod) 72*b33465feSAaron Tomlin { 73*b33465feSAaron Tomlin const unsigned long shf_wx = SHF_WRITE | SHF_EXECINSTR; 74*b33465feSAaron Tomlin int i; 75*b33465feSAaron Tomlin 76*b33465feSAaron Tomlin for (i = 0; i < hdr->e_shnum; i++) { 77*b33465feSAaron Tomlin if ((sechdrs[i].sh_flags & shf_wx) == shf_wx) { 78*b33465feSAaron Tomlin pr_err("%s: section %s (index %d) has invalid WRITE|EXEC flags\n", 79*b33465feSAaron Tomlin mod->name, secstrings + sechdrs[i].sh_name, i); 80*b33465feSAaron Tomlin return -ENOEXEC; 81*b33465feSAaron Tomlin } 82*b33465feSAaron Tomlin } 83*b33465feSAaron Tomlin 84*b33465feSAaron Tomlin return 0; 85*b33465feSAaron Tomlin } 86