diff options
author | Kees Cook <keescook@chromium.org> | 2014-04-03 16:29:50 -0400 |
---|---|---|
committer | Kees Cook <keescook@chromium.org> | 2014-10-16 17:38:54 -0400 |
commit | 80d6b0c2eed2a504f6740cd1f5ea76dc50abfc4d (patch) | |
tree | 32f6d8a1c5a2250cc3f303df545dfbf52da62d19 /arch/arm/mm/init.c | |
parent | 1e6b48116a95046ec51f3d40f83aff8b006674d7 (diff) |
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 { | |||
622 | unsigned long end; | 622 | unsigned long end; |
623 | pmdval_t mask; | 623 | pmdval_t mask; |
624 | pmdval_t prot; | 624 | pmdval_t prot; |
625 | pmdval_t clear; | ||
625 | }; | 626 | }; |
626 | 627 | ||
627 | struct section_perm nx_perms[] = { | 628 | static struct section_perm nx_perms[] = { |
628 | /* Make pages tables, etc before _stext RW (set NX). */ | 629 | /* Make pages tables, etc before _stext RW (set NX). */ |
629 | { | 630 | { |
630 | .start = PAGE_OFFSET, | 631 | .start = PAGE_OFFSET, |
@@ -639,8 +640,35 @@ struct section_perm nx_perms[] = { | |||
639 | .mask = ~PMD_SECT_XN, | 640 | .mask = ~PMD_SECT_XN, |
640 | .prot = PMD_SECT_XN, | 641 | .prot = PMD_SECT_XN, |
641 | }, | 642 | }, |
643 | #ifdef CONFIG_DEBUG_RODATA | ||
644 | /* Make rodata NX (set RO in ro_perms below). */ | ||
645 | { | ||
646 | .start = (unsigned long)__start_rodata, | ||
647 | .end = (unsigned long)__init_begin, | ||
648 | .mask = ~PMD_SECT_XN, | ||
649 | .prot = PMD_SECT_XN, | ||
650 | }, | ||
651 | #endif | ||
642 | }; | 652 | }; |
643 | 653 | ||
654 | #ifdef CONFIG_DEBUG_RODATA | ||
655 | static struct section_perm ro_perms[] = { | ||
656 | /* Make kernel code and rodata RX (set RO). */ | ||
657 | { | ||
658 | .start = (unsigned long)_stext, | ||
659 | .end = (unsigned long)__init_begin, | ||
660 | #ifdef CONFIG_ARM_LPAE | ||
661 | .mask = ~PMD_SECT_RDONLY, | ||
662 | .prot = PMD_SECT_RDONLY, | ||
663 | #else | ||
664 | .mask = ~(PMD_SECT_APX | PMD_SECT_AP_WRITE), | ||
665 | .prot = PMD_SECT_APX | PMD_SECT_AP_WRITE, | ||
666 | .clear = PMD_SECT_AP_WRITE, | ||
667 | #endif | ||
668 | }, | ||
669 | }; | ||
670 | #endif | ||
671 | |||
644 | /* | 672 | /* |
645 | * Updates section permissions only for the current mm (sections are | 673 | * Updates section permissions only for the current mm (sections are |
646 | * copied into each mm). During startup, this is the init_mm. Is only | 674 | * copied into each mm). During startup, this is the init_mm. Is only |
@@ -704,6 +732,24 @@ static inline void fix_kernmem_perms(void) | |||
704 | { | 732 | { |
705 | set_section_perms(nx_perms, prot); | 733 | set_section_perms(nx_perms, prot); |
706 | } | 734 | } |
735 | |||
736 | #ifdef CONFIG_DEBUG_RODATA | ||
737 | void mark_rodata_ro(void) | ||
738 | { | ||
739 | set_section_perms(ro_perms, prot); | ||
740 | } | ||
741 | |||
742 | void set_kernel_text_rw(void) | ||
743 | { | ||
744 | set_section_perms(ro_perms, clear); | ||
745 | } | ||
746 | |||
747 | void set_kernel_text_ro(void) | ||
748 | { | ||
749 | set_section_perms(ro_perms, prot); | ||
750 | } | ||
751 | #endif /* CONFIG_DEBUG_RODATA */ | ||
752 | |||
707 | #else | 753 | #else |
708 | static inline void fix_kernmem_perms(void) { } | 754 | static inline void fix_kernmem_perms(void) { } |
709 | #endif /* CONFIG_ARM_KERNMEM_PERMS */ | 755 | #endif /* CONFIG_ARM_KERNMEM_PERMS */ |