diff options
author | Laura Abbott <labbott@redhat.com> | 2015-11-30 13:36:28 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2015-12-04 14:20:34 -0500 |
commit | 08925c2f124f1bac6152a8b234268f9874fc70a5 (patch) | |
tree | 37bc92623cc72be72dde47ea5bf6bde6c86cdf31 /arch | |
parent | 40ee068ec09b2d98162da5ea18b7c6fdbaa2bb71 (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.c | 92 |
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 | */ |
629 | static inline void section_update(unsigned long addr, pmdval_t mask, | 630 | static 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) { \ | 658 | void 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 | ||
683 | static inline void fix_kernmem_perms(void) | 685 | static 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 | |||
701 | int __fix_kernmem_perms(void *unused) | ||
702 | { | ||
703 | update_sections_early(nx_perms, ARRAY_SIZE(nx_perms)); | ||
704 | return 0; | ||
705 | } | ||
706 | |||
707 | void 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 |
713 | int __mark_rodata_ro(void *unused) | ||
714 | { | ||
715 | update_sections_early(ro_perms, ARRAY_SIZE(ro_perms)); | ||
716 | return 0; | ||
717 | } | ||
718 | |||
689 | void mark_rodata_ro(void) | 719 | void 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 | ||
694 | void set_kernel_text_rw(void) | 724 | void 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 | ||
699 | void set_kernel_text_ro(void) | 730 | void 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 | ||