diff options
author | Kees Cook <keescook@chromium.org> | 2014-04-03 22:29:50 +0200 |
---|---|---|
committer | Kees Cook <keescook@chromium.org> | 2014-10-16 23:38:54 +0200 |
commit | 80d6b0c2eed2a504f6740cd1f5ea76dc50abfc4d (patch) | |
tree | 32f6d8a1c5a2250cc3f303df545dfbf52da62d19 /arch/arm/mm/init.c | |
parent | ARM: mm: allow non-text sections to be non-executable (diff) | |
download | linux-80d6b0c2eed2a504f6740cd1f5ea76dc50abfc4d.tar.xz linux-80d6b0c2eed2a504f6740cd1f5ea76dc50abfc4d.zip |
ARM: mm: allow text and rodata sections to be read-only
This introduces CONFIG_DEBUG_RODATA, making kernel text and rodata
read-only. Additionally, this splits rodata from text so that rodata can
also be NX, which may lead to wasted memory when aligning to SECTION_SIZE.
The read-only areas are made writable during ftrace updates and kexec.
Signed-off-by: Kees Cook <keescook@chromium.org>
Tested-by: Laura Abbott <lauraa@codeaurora.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Diffstat (limited to 'arch/arm/mm/init.c')
-rw-r--r-- | arch/arm/mm/init.c | 48 |
1 files changed, 47 insertions, 1 deletions
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index e6bfe76b2f59..dc2db779cdf4 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -622,9 +622,10 @@ struct section_perm { unsigned long end; pmdval_t mask; pmdval_t prot; + pmdval_t clear; }; -struct section_perm nx_perms[] = { +static struct section_perm nx_perms[] = { /* Make pages tables, etc before _stext RW (set NX). */ { .start = PAGE_OFFSET, @@ -639,8 +640,35 @@ struct section_perm nx_perms[] = { .mask = ~PMD_SECT_XN, .prot = PMD_SECT_XN, }, +#ifdef CONFIG_DEBUG_RODATA + /* Make rodata NX (set RO in ro_perms below). */ + { + .start = (unsigned long)__start_rodata, + .end = (unsigned long)__init_begin, + .mask = ~PMD_SECT_XN, + .prot = PMD_SECT_XN, + }, +#endif }; +#ifdef CONFIG_DEBUG_RODATA +static struct section_perm ro_perms[] = { + /* Make kernel code and rodata RX (set RO). */ + { + .start = (unsigned long)_stext, + .end = (unsigned long)__init_begin, +#ifdef CONFIG_ARM_LPAE + .mask = ~PMD_SECT_RDONLY, + .prot = PMD_SECT_RDONLY, +#else + .mask = ~(PMD_SECT_APX | PMD_SECT_AP_WRITE), + .prot = PMD_SECT_APX | PMD_SECT_AP_WRITE, + .clear = PMD_SECT_AP_WRITE, +#endif + }, +}; +#endif + /* * Updates section permissions only for the current mm (sections are * copied into each mm). During startup, this is the init_mm. Is only @@ -704,6 +732,24 @@ static inline void fix_kernmem_perms(void) { set_section_perms(nx_perms, prot); } + +#ifdef CONFIG_DEBUG_RODATA +void mark_rodata_ro(void) +{ + set_section_perms(ro_perms, prot); +} + +void set_kernel_text_rw(void) +{ + set_section_perms(ro_perms, clear); +} + +void set_kernel_text_ro(void) +{ + set_section_perms(ro_perms, prot); +} +#endif /* CONFIG_DEBUG_RODATA */ + #else static inline void fix_kernmem_perms(void) { } #endif /* CONFIG_ARM_KERNMEM_PERMS */ |