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 | static int module_set_memory(const struct module *mod, enum mod_mem_type type, |
15 | int (*set_memory)(unsigned long start, int num_pages)) |
16 | { |
17 | const struct module_memory *mod_mem = &mod->mem[type]; |
18 | |
19 | if (!mod_mem->base) |
20 | return 0; |
21 | |
22 | set_vm_flush_reset_perms(mod_mem->base); |
23 | return set_memory((unsigned long)mod_mem->base, mod_mem->size >> PAGE_SHIFT); |
24 | } |
25 | |
26 | /* |
27 | * Since some arches are moving towards PAGE_KERNEL module allocations instead |
28 | * of PAGE_KERNEL_EXEC, keep module_enable_x() independent of |
29 | * CONFIG_STRICT_MODULE_RWX because they are needed regardless of whether we |
30 | * are strict. |
31 | */ |
32 | int module_enable_text_rox(const struct module *mod) |
33 | { |
34 | for_class_mod_mem_type(type, text) { |
35 | int ret; |
36 | |
37 | if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX)) |
38 | ret = module_set_memory(mod, type, set_memory_rox); |
39 | else |
40 | ret = module_set_memory(mod, type, set_memory: set_memory_x); |
41 | if (ret) |
42 | return ret; |
43 | } |
44 | return 0; |
45 | } |
46 | |
47 | int module_enable_rodata_ro(const struct module *mod, bool after_init) |
48 | { |
49 | int ret; |
50 | |
51 | if (!IS_ENABLED(CONFIG_STRICT_MODULE_RWX) || !rodata_enabled) |
52 | return 0; |
53 | |
54 | ret = module_set_memory(mod, type: MOD_RODATA, set_memory: set_memory_ro); |
55 | if (ret) |
56 | return ret; |
57 | ret = module_set_memory(mod, type: MOD_INIT_RODATA, set_memory: set_memory_ro); |
58 | if (ret) |
59 | return ret; |
60 | |
61 | if (after_init) |
62 | return module_set_memory(mod, type: MOD_RO_AFTER_INIT, set_memory: set_memory_ro); |
63 | |
64 | return 0; |
65 | } |
66 | |
67 | int module_enable_data_nx(const struct module *mod) |
68 | { |
69 | if (!IS_ENABLED(CONFIG_STRICT_MODULE_RWX)) |
70 | return 0; |
71 | |
72 | for_class_mod_mem_type(type, data) { |
73 | int ret = module_set_memory(mod, type, set_memory: set_memory_nx); |
74 | |
75 | if (ret) |
76 | return ret; |
77 | } |
78 | return 0; |
79 | } |
80 | |
81 | int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, |
82 | char *secstrings, struct module *mod) |
83 | { |
84 | const unsigned long shf_wx = SHF_WRITE | SHF_EXECINSTR; |
85 | int i; |
86 | |
87 | if (!IS_ENABLED(CONFIG_STRICT_MODULE_RWX)) |
88 | return 0; |
89 | |
90 | for (i = 0; i < hdr->e_shnum; i++) { |
91 | if ((sechdrs[i].sh_flags & shf_wx) == shf_wx) { |
92 | pr_err("%s: section %s (index %d) has invalid WRITE|EXEC flags\n" , |
93 | mod->name, secstrings + sechdrs[i].sh_name, i); |
94 | return -ENOEXEC; |
95 | } |
96 | } |
97 | |
98 | return 0; |
99 | } |
100 | |