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.
Showing the changes to kernel/module (2 of 4 files). Show all
Unified · Split
| @@ -1221,18 +1221,6 @@ void __weak module_arch_freeing_init(struct module *mod) · 1220 unmodified lines | |||
| 1221 | { | 1221 | { |
| 1222 | } | 1222 | } |
| 1223 | 1223 | ||
| 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 | |||
| 1236 | static int module_memory_alloc(struct module *mod, enum mod_mem_type type) | 1224 | static 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 | ||
| 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 | |||
| 1286 | static void module_memory_free(struct module *mod, enum mod_mem_type type) | 1281 | static 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 newly | 2698 | * 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; |
| 2719 | out_err: | 2707 | out_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 | ||
| 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 | |||
| 2873 | static int post_relocation(struct module *mod, const struct load_info *info) | 2855 | static 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 | /* |
| @@ -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 | ||
| 14 | static int module_set_memory(const struct module *mod, enum mod_mem_type type, | 15 | 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 | |||
| 32 | int module_enable_text_rox(const struct module *mod) | 33 | int 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 | else | 43 | else |
| 43 | ret = module_set_memory(mod, type, set_memory_x); | 44 | ret = module_set_memory(mod, type, set_memory_x); |