History

module: switch to execmem API for remapping as RW and restoring ROX

Instead of using writable copy for module text sections, temporarily remap the memory allocated from execmem's ROX cache as writable and restore its ROX permissions after the module is formed. This will allow removing nasty games with writable copy in alternatives patching on x86.

Mike Rapoport (Microsoft) committed 1 year ago

Commit c287c071 parent 05e555b4 files · +27 −72Browse files

Showing the changes to kernel/module (2 of 4 files). Show all

Unified · Split

2 files
  1. kernel/module/main.c +21 −57
  2. kernel/module/strict_rwx.c +5 −4
kernel/module/main.c+21−57
@@ -1221,18 +1221,6 @@ void __weak module_arch_freeing_init(struct module *mod) · 1220 unmodified lines
12211221 {
12221222 }
12231223
1224−void *__module_writable_address(struct module *mod, void *loc)
1225−{
1226− for_class_mod_mem_type(type, text) {
1227− struct module_memory *mem = &mod->mem[type];
1228−
1229− if (loc >= mem->base && loc < mem->base + mem->size)
1230− return loc + (mem->rw_copy - mem->base);
1231− }
1232−
1233− return loc;
1234−}
1235−
12361224 static int module_memory_alloc(struct module *mod, enum mod_mem_type type)
12371225 {
12381226 unsigned int size = PAGE_ALIGN(mod->mem[type].size);
@@ -1250,21 +1238,15 @@ static int module_memory_alloc(struct module *mod, enum mod_mem_type type) · 11 unmodified lines
12501238 if (!ptr)
12511239 return -ENOMEM;
12521240
1253− mod->mem[type].base = ptr;
1254−
12551241 if (execmem_is_rox(execmem_type)) {
1256− ptr = vzalloc(size);
1242+ int err = execmem_make_temp_rw(ptr, size);
12571243
1258− if (!ptr) {
1259− execmem_free(mod->mem[type].base);
1244+ if (err) {
1245+ execmem_free(ptr);
12601246 return -ENOMEM;
12611247 }
12621248
1263− mod->mem[type].rw_copy = ptr;
12641249 mod->mem[type].is_rox = true;
1265− } else {
1266− mod->mem[type].rw_copy = mod->mem[type].base;
1267− memset(mod->mem[type].base, 0, size);
12681250 }
12691251
12701252 /*
@@ -1280,16 +1262,26 @@ static int module_memory_alloc(struct module *mod, enum mod_mem_type type) · 9 unmodified lines
12801262 */
12811263 kmemleak_not_leak(ptr);
12821264
1265+ memset(ptr, 0, size);
1266+ mod->mem[type].base = ptr;
1267+
12831268 return 0;
12841269 }
12851270
1271+static void module_memory_restore_rox(struct module *mod)
1272+{
1273+ for_class_mod_mem_type(type, text) {
1274+ struct module_memory *mem = &mod->mem[type];
1275+
1276+ if (mem->is_rox)
1277+ execmem_restore_rox(mem->base, mem->size);
1278+ }
1279+}
1280+
12861281 static void module_memory_free(struct module *mod, enum mod_mem_type type)
12871282 {
12881283 struct module_memory *mem = &mod->mem[type];
12891284
1290− if (mem->is_rox)
1291− vfree(mem->rw_copy);
1292−
12931285 execmem_free(mem->base);
12941286 }
12951287
@@ -2642,7 +2634,6 @@ static int move_module(struct module *mod, struct load_info *info) · 1346 unmodified lines
26422634 for_each_mod_mem_type(type) {
26432635 if (!mod->mem[type].size) {
26442636 mod->mem[type].base = NULL;
2645− mod->mem[type].rw_copy = NULL;
26462637 continue;
26472638 }
26482639
@@ -2659,7 +2650,6 @@ static int move_module(struct module *mod, struct load_info *info) · 10 unmodified lines
26592650 void *dest;
26602651 Elf_Shdr *shdr = &info->sechdrs[i];
26612652 const char *sname;
2662− unsigned long addr;
26632653
26642654 if (!(shdr->sh_flags & SHF_ALLOC))
26652655 continue;
@@ -2680,14 +2670,12 @@ static int move_module(struct module *mod, struct load_info *info) · 14 unmodified lines
26802670 ret = PTR_ERR(dest);
26812671 goto out_err;
26822672 }
2683− addr = (unsigned long)dest;
26842673 codetag_section_found = true;
26852674 } else {
26862675 enum mod_mem_type type = shdr->sh_entsize >> SH_ENTSIZE_TYPE_SHIFT;
26872676 unsigned long offset = shdr->sh_entsize & SH_ENTSIZE_OFFSET_MASK;
26882677
2689− addr = (unsigned long)mod->mem[type].base + offset;
2690− dest = mod->mem[type].rw_copy + offset;
2678+ dest = mod->mem[type].base + offset;
26912679 }
26922680
26932681 if (shdr->sh_type != SHT_NOBITS) {
@@ -2710,13 +2698,14 @@ static int move_module(struct module *mod, struct load_info *info) · 16 unmodified lines
27102698 * users of info can keep taking advantage and using the newly
27112699 * minted official memory area.
27122700 */
2713− shdr->sh_addr = addr;
2701+ shdr->sh_addr = (unsigned long)dest;
27142702 pr_debug("\t0x%lx 0x%.8lx %s\n", (long)shdr->sh_addr,
27152703 (long)shdr->sh_size, info->secstrings + shdr->sh_name);
27162704 }
27172705
27182706 return 0;
27192707 out_err:
2708+ module_memory_restore_rox(mod);
27202709 for (t--; t >= 0; t--)
27212710 module_memory_free(mod, t);
27222711 if (codetag_section_found)
@@ -2863,17 +2852,8 @@ int __weak module_finalize(const Elf_Ehdr *hdr, · 140 unmodified lines
28632852 return 0;
28642853 }
28652854
2866−int __weak module_post_finalize(const Elf_Ehdr *hdr,
2867− const Elf_Shdr *sechdrs,
2868− struct module *me)
2869−{
2870− return 0;
2871−}
2872−
28732855 static int post_relocation(struct module *mod, const struct load_info *info)
28742856 {
2875− int ret;
2876−
28772857 /* Sort exception table now relocations are done. */
28782858 sort_extable(mod->extable, mod->extable + mod->num_exentries);
28792859
@@ -2885,24 +2865,7 @@ static int post_relocation(struct module *mod, const struct load_info *info) · 5 unmodified lines
28852865 add_kallsyms(mod, info);
28862866
28872867 /* Arch-specific module finalizing. */
2888− ret = module_finalize(info->hdr, info->sechdrs, mod);
2889− if (ret)
2890− return ret;
2891−
2892− for_each_mod_mem_type(type) {
2893− struct module_memory *mem = &mod->mem[type];
2894−
2895− if (mem->is_rox) {
2896− if (!execmem_update_copy(mem->base, mem->rw_copy,
2897− mem->size))
2898− return -ENOMEM;
2899−
2900− vfree(mem->rw_copy);
2901− mem->rw_copy = NULL;
2902− }
2903− }
2904−
2905− return module_post_finalize(info->hdr, info->sechdrs, mod);
2868+ return module_finalize(info->hdr, info->sechdrs, mod);
29062869 }
29072870
29082871 /* Call module constructors. */
@@ -3499,6 +3462,7 @@ static int load_module(struct load_info *info, const char __user *uargs, · 590 unmodified lines
34993462 mod->mem[type].size);
35003463 }
35013464
3465+ module_memory_restore_rox(mod);
35023466 module_deallocate(mod, info);
35033467 free_copy:
35043468 /*
kernel/module/strict_rwx.c+5−4
@@ -9,6 +9,7 @@ · 8 unmodified lines
99 #include <linux/mm.h>
1010 #include <linux/vmalloc.h>
1111 #include <linux/set_memory.h>
12+#include <linux/execmem.h>
1213 #include "internal.h"
1314
1415 static int module_set_memory(const struct module *mod, enum mod_mem_type type,
@@ -32,12 +33,12 @@ static int module_set_memory(const struct module *mod, enum mod_mem_type type, · 17 unmodified lines
3233 int module_enable_text_rox(const struct module *mod)
3334 {
3435 for_class_mod_mem_type(type, text) {
36+ const struct module_memory *mem = &mod->mem[type];
3537 int ret;
3638
37− if (mod->mem[type].is_rox)
38− continue;
39−
40− if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX))
39+ if (mem->is_rox)
40+ ret = execmem_restore_rox(mem->base, mem->size);
41+ else if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX))
4142 ret = module_set_memory(mod, type, set_memory_rox);
4243 else
4344 ret = module_set_memory(mod, type, set_memory_x);