aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorLaura Abbott <labbott@redhat.com>2015-11-30 13:36:28 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2015-12-04 14:20:34 -0500
commit08925c2f124f1bac6152a8b234268f9874fc70a5 (patch)
tree37bc92623cc72be72dde47ea5bf6bde6c86cdf31 /arch
parent40ee068ec09b2d98162da5ea18b7c6fdbaa2bb71 (diff)
ARM: 8464/1: Update all mm structures with section adjustments
Currently, when updating section permissions to mark areas RO or NX, the only mm updated is current->mm. This is working off the assumption that there are no additional mm structures at the time. This may not always hold true. (Example: calling modprobe early will trigger a fork/exec). Ensure all mm structres get updated with the new section information. Reviewed-by: Kees Cook <keescook@chromium.org> Signed-off-by: Laura Abbott <labbott@fedoraproject.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mm/init.c92
1 files changed, 62 insertions, 30 deletions
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 8a63b4cdc0f2..7f8cd1b3557f 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -22,6 +22,7 @@
22#include <linux/memblock.h> 22#include <linux/memblock.h>
23#include <linux/dma-contiguous.h> 23#include <linux/dma-contiguous.h>
24#include <linux/sizes.h> 24#include <linux/sizes.h>
25#include <linux/stop_machine.h>
25 26
26#include <asm/cp15.h> 27#include <asm/cp15.h>
27#include <asm/mach-types.h> 28#include <asm/mach-types.h>
@@ -627,12 +628,10 @@ static struct section_perm ro_perms[] = {
627 * safe to be called with preemption disabled, as under stop_machine(). 628 * safe to be called with preemption disabled, as under stop_machine().
628 */ 629 */
629static inline void section_update(unsigned long addr, pmdval_t mask, 630static inline void section_update(unsigned long addr, pmdval_t mask,
630 pmdval_t prot) 631 pmdval_t prot, struct mm_struct *mm)
631{ 632{
632 struct mm_struct *mm;
633 pmd_t *pmd; 633 pmd_t *pmd;
634 634
635 mm = current->active_mm;
636 pmd = pmd_offset(pud_offset(pgd_offset(mm, addr), addr), addr); 635 pmd = pmd_offset(pud_offset(pgd_offset(mm, addr), addr), addr);
637 636
638#ifdef CONFIG_ARM_LPAE 637#ifdef CONFIG_ARM_LPAE
@@ -656,49 +655,82 @@ static inline bool arch_has_strict_perms(void)
656 return !!(get_cr() & CR_XP); 655 return !!(get_cr() & CR_XP);
657} 656}
658 657
659#define set_section_perms(perms, field) { \ 658void set_section_perms(struct section_perm *perms, int n, bool set,
660 size_t i; \ 659 struct mm_struct *mm)
661 unsigned long addr; \ 660{
662 \ 661 size_t i;
663 if (!arch_has_strict_perms()) \ 662 unsigned long addr;
664 return; \ 663
665 \ 664 if (!arch_has_strict_perms())
666 for (i = 0; i < ARRAY_SIZE(perms); i++) { \ 665 return;
667 if (!IS_ALIGNED(perms[i].start, SECTION_SIZE) || \ 666
668 !IS_ALIGNED(perms[i].end, SECTION_SIZE)) { \ 667 for (i = 0; i < n; i++) {
669 pr_err("BUG: section %lx-%lx not aligned to %lx\n", \ 668 if (!IS_ALIGNED(perms[i].start, SECTION_SIZE) ||
670 perms[i].start, perms[i].end, \ 669 !IS_ALIGNED(perms[i].end, SECTION_SIZE)) {
671 SECTION_SIZE); \ 670 pr_err("BUG: section %lx-%lx not aligned to %lx\n",
672 continue; \ 671 perms[i].start, perms[i].end,
673 } \ 672 SECTION_SIZE);
674 \ 673 continue;
675 for (addr = perms[i].start; \ 674 }
676 addr < perms[i].end; \ 675
677 addr += SECTION_SIZE) \ 676 for (addr = perms[i].start;
678 section_update(addr, perms[i].mask, \ 677 addr < perms[i].end;
679 perms[i].field); \ 678 addr += SECTION_SIZE)
680 } \ 679 section_update(addr, perms[i].mask,
680 set ? perms[i].prot : perms[i].clear, mm);
681 }
682
681} 683}
682 684
683static inline void fix_kernmem_perms(void) 685static void update_sections_early(struct section_perm perms[], int n)
684{ 686{
685 set_section_perms(nx_perms, prot); 687 struct task_struct *t, *s;
688
689 read_lock(&tasklist_lock);
690 for_each_process(t) {
691 if (t->flags & PF_KTHREAD)
692 continue;
693 for_each_thread(t, s)
694 set_section_perms(perms, n, true, s->mm);
695 }
696 read_unlock(&tasklist_lock);
697 set_section_perms(perms, n, true, current->active_mm);
698 set_section_perms(perms, n, true, &init_mm);
699}
700
701int __fix_kernmem_perms(void *unused)
702{
703 update_sections_early(nx_perms, ARRAY_SIZE(nx_perms));
704 return 0;
705}
706
707void fix_kernmem_perms(void)
708{
709 stop_machine(__fix_kernmem_perms, NULL, NULL);
686} 710}
687 711
688#ifdef CONFIG_DEBUG_RODATA 712#ifdef CONFIG_DEBUG_RODATA
713int __mark_rodata_ro(void *unused)
714{
715 update_sections_early(ro_perms, ARRAY_SIZE(ro_perms));
716 return 0;
717}
718
689void mark_rodata_ro(void) 719void mark_rodata_ro(void)
690{ 720{
691 set_section_perms(ro_perms, prot); 721 stop_machine(__mark_rodata_ro, NULL, NULL);
692} 722}
693 723
694void set_kernel_text_rw(void) 724void set_kernel_text_rw(void)
695{ 725{
696 set_section_perms(ro_perms, clear); 726 set_section_perms(ro_perms, ARRAY_SIZE(ro_perms), false,
727 current->active_mm);
697} 728}
698 729
699void set_kernel_text_ro(void) 730void set_kernel_text_ro(void)
700{ 731{
701 set_section_perms(ro_perms, prot); 732 set_section_perms(ro_perms, ARRAY_SIZE(ro_perms), true,
733 current->active_mm);
702} 734}
703#endif /* CONFIG_DEBUG_RODATA */ 735#endif /* CONFIG_DEBUG_RODATA */
704 736