xref: /openbmc/linux/kernel/module/strict_rwx.c (revision b33465fe9c52a3719f013deeca261bd82af235ee)
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