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
1221{1221{
1222}1222}
1223 1223
1224void *__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
1236static int module_memory_alloc(struct module *mod, enum mod_mem_type type)1224static int module_memory_alloc(struct module *mod, enum mod_mem_type type)
1237{1225{
1238 unsigned int size = PAGE_ALIGN(mod->mem[type].size);1226 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
1250 if (!ptr)1238 if (!ptr)
1251 return -ENOMEM;1239 return -ENOMEM;
1252 1240
1253 mod->mem[type].base = ptr;
1254
1255 if (execmem_is_rox(execmem_type)) {1241 if (execmem_is_rox(execmem_type)) {
1256 ptr = vzalloc(size);1242 int err = execmem_make_temp_rw(ptr, size);
1257 1243
1258 if (!ptr) {1244 if (err) {
1259 execmem_free(mod->mem[type].base);1245 execmem_free(ptr);
1260 return -ENOMEM;1246 return -ENOMEM;
1261 }1247 }
1262 1248
1263 mod->mem[type].rw_copy = ptr;
1264 mod->mem[type].is_rox = true;1249 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);
1268 }1250 }
1269 1251
1270 /*1252 /*
@@ -1280,16 +1262,26 @@ static int module_memory_alloc(struct module *mod, enum mod_mem_type type) · 9 unmodified lines
1280 */1262 */
1281 kmemleak_not_leak(ptr);1263 kmemleak_not_leak(ptr);
1282 1264
1265 memset(ptr, 0, size);
1266 mod->mem[type].base = ptr;
1267
1283 return 0;1268 return 0;
1284}1269}
1285 1270
1271static 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
1286static void module_memory_free(struct module *mod, enum mod_mem_type type)1281static void module_memory_free(struct module *mod, enum mod_mem_type type)
1287{1282{
1288 struct module_memory *mem = &mod->mem[type];1283 struct module_memory *mem = &mod->mem[type];
1289 1284
1290 if (mem->is_rox)
1291 vfree(mem->rw_copy);
1292
1293 execmem_free(mem->base);1285 execmem_free(mem->base);
1294}1286}
1295 1287
@@ -2642,7 +2634,6 @@ static int move_module(struct module *mod, struct load_info *info) · 1346 unmodified lines
2642 for_each_mod_mem_type(type) {2634 for_each_mod_mem_type(type) {
2643 if (!mod->mem[type].size) {2635 if (!mod->mem[type].size) {
2644 mod->mem[type].base = NULL;2636 mod->mem[type].base = NULL;
2645 mod->mem[type].rw_copy = NULL;
2646 continue;2637 continue;
2647 }2638 }
2648 2639
@@ -2659,7 +2650,6 @@ static int move_module(struct module *mod, struct load_info *info) · 10 unmodified lines
2659 void *dest;2650 void *dest;
2660 Elf_Shdr *shdr = &info->sechdrs[i];2651 Elf_Shdr *shdr = &info->sechdrs[i];
2661 const char *sname;2652 const char *sname;
2662 unsigned long addr;
2663 2653
2664 if (!(shdr->sh_flags & SHF_ALLOC))2654 if (!(shdr->sh_flags & SHF_ALLOC))
2665 continue;2655 continue;
@@ -2680,14 +2670,12 @@ static int move_module(struct module *mod, struct load_info *info) · 14 unmodified lines
2680 ret = PTR_ERR(dest);2670 ret = PTR_ERR(dest);
2681 goto out_err;2671 goto out_err;
2682 }2672 }
2683 addr = (unsigned long)dest;
2684 codetag_section_found = true;2673 codetag_section_found = true;
2685 } else {2674 } else {
2686 enum mod_mem_type type = shdr->sh_entsize >> SH_ENTSIZE_TYPE_SHIFT;2675 enum mod_mem_type type = shdr->sh_entsize >> SH_ENTSIZE_TYPE_SHIFT;
2687 unsigned long offset = shdr->sh_entsize & SH_ENTSIZE_OFFSET_MASK;2676 unsigned long offset = shdr->sh_entsize & SH_ENTSIZE_OFFSET_MASK;
2688 2677
2689 addr = (unsigned long)mod->mem[type].base + offset;2678 dest = mod->mem[type].base + offset;
2690 dest = mod->mem[type].rw_copy + offset;
2691 }2679 }
2692 2680
2693 if (shdr->sh_type != SHT_NOBITS) {2681 if (shdr->sh_type != SHT_NOBITS) {
@@ -2710,13 +2698,14 @@ static int move_module(struct module *mod, struct load_info *info) · 16 unmodified lines
2710 * users of info can keep taking advantage and using the newly2698 * users of info can keep taking advantage and using the newly
2711 * minted official memory area.2699 * minted official memory area.
2712 */2700 */
2713 shdr->sh_addr = addr;2701 shdr->sh_addr = (unsigned long)dest;
2714 pr_debug("\t0x%lx 0x%.8lx %s\n", (long)shdr->sh_addr,2702 pr_debug("\t0x%lx 0x%.8lx %s\n", (long)shdr->sh_addr,
2715 (long)shdr->sh_size, info->secstrings + shdr->sh_name);2703 (long)shdr->sh_size, info->secstrings + shdr->sh_name);
2716 }2704 }
2717 2705
2718 return 0;2706 return 0;
2719out_err:2707out_err:
2708 module_memory_restore_rox(mod);
2720 for (t--; t >= 0; t--)2709 for (t--; t >= 0; t--)
2721 module_memory_free(mod, t);2710 module_memory_free(mod, t);
2722 if (codetag_section_found)2711 if (codetag_section_found)
@@ -2863,17 +2852,8 @@ int __weak module_finalize(const Elf_Ehdr *hdr, · 140 unmodified lines
2863 return 0;2852 return 0;
2864}2853}
2865 2854
2866int __weak module_post_finalize(const Elf_Ehdr *hdr,
2867 const Elf_Shdr *sechdrs,
2868 struct module *me)
2869{
2870 return 0;
2871}
2872
2873static int post_relocation(struct module *mod, const struct load_info *info)2855static int post_relocation(struct module *mod, const struct load_info *info)
2874{2856{
2875 int ret;
2876
2877 /* Sort exception table now relocations are done. */2857 /* Sort exception table now relocations are done. */
2878 sort_extable(mod->extable, mod->extable + mod->num_exentries);2858 sort_extable(mod->extable, mod->extable + mod->num_exentries);
2879 2859
@@ -2885,24 +2865,7 @@ static int post_relocation(struct module *mod, const struct load_info *info) · 5 unmodified lines
2885 add_kallsyms(mod, info);2865 add_kallsyms(mod, info);
2886 2866
2887 /* Arch-specific module finalizing. */2867 /* Arch-specific module finalizing. */
2888 ret = module_finalize(info->hdr, info->sechdrs, mod);2868 return 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);
2906}2869}
2907 2870
2908/* Call module constructors. */2871/* Call module constructors. */
@@ -3499,6 +3462,7 @@ static int load_module(struct load_info *info, const char __user *uargs, · 590 unmodified lines
3499 mod->mem[type].size);3462 mod->mem[type].size);
3500 }3463 }
3501 3464
3465 module_memory_restore_rox(mod);
3502 module_deallocate(mod, info);3466 module_deallocate(mod, info);
3503 free_copy:3467 free_copy:
3504 /*3468 /*
kernel/module/strict_rwx.c+5−4
@@ -9,6 +9,7 @@ · 8 unmodified lines
9#include <linux/mm.h>9#include <linux/mm.h>
10#include <linux/vmalloc.h>10#include <linux/vmalloc.h>
11#include <linux/set_memory.h>11#include <linux/set_memory.h>
12#include <linux/execmem.h>
12#include "internal.h"13#include "internal.h"
13 14
14static int module_set_memory(const struct module *mod, enum mod_mem_type type,15static 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
32int module_enable_text_rox(const struct module *mod)33int module_enable_text_rox(const struct module *mod)
33{34{
34 for_class_mod_mem_type(type, text) {35 for_class_mod_mem_type(type, text) {
36 const struct module_memory *mem = &mod->mem[type];
35 int ret;37 int ret;
36 38
37 if (mod->mem[type].is_rox)39 if (mem->is_rox)
38 continue;40 ret = execmem_restore_rox(mem->base, mem->size);
39 41 else if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX))
40 if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX))
41 ret = module_set_memory(mod, type, set_memory_rox);42 ret = module_set_memory(mod, type, set_memory_rox);
42 else43 else
43 ret = module_set_memory(mod, type, set_memory_x);44 ret = module_set_memory(mod, type, set_memory_x);