Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752089AbaDDCQw (ORCPT ); Thu, 3 Apr 2014 22:16:52 -0400 Received: from smtp.outflux.net ([198.145.64.163]:56947 "EHLO smtp.outflux.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751965AbaDDCQd (ORCPT ); Thu, 3 Apr 2014 22:16:33 -0400 From: Kees Cook To: linux-arm-kernel@lists.infradead.org Cc: Rabin Vincent , Laura Abbott , Alexander Holler , Catalin Marinas , Will Deacon , Russell King , linux-kernel@vger.kernel.org, Kees Cook Subject: [PATCH 2/2] ARM: mm: make text and rodata read-only Date: Thu, 3 Apr 2014 19:15:19 -0700 Message-Id: <1396577719-14786-3-git-send-email-keescook@chromium.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1396577719-14786-1-git-send-email-keescook@chromium.org> References: <1396577719-14786-1-git-send-email-keescook@chromium.org> X-HELO: www.outflux.net Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This introduces CONFIG_DEBUG_RODATA, making kernel text and rodata read-only. It splits rodata from text so that rodata can also be NX. Signed-off-by: Kees Cook --- arch/arm/include/asm/cacheflush.h | 9 ++++ arch/arm/kernel/ftrace.c | 17 +++++++ arch/arm/kernel/vmlinux.lds.S | 3 ++ arch/arm/mm/Kconfig | 11 +++++ arch/arm/mm/init.c | 97 +++++++++++++++++++++++++++++-------- 5 files changed, 117 insertions(+), 20 deletions(-) diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index 8b8b61685a34..b6fea0a1a88b 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -487,4 +487,13 @@ int set_memory_rw(unsigned long addr, int numpages); int set_memory_x(unsigned long addr, int numpages); int set_memory_nx(unsigned long addr, int numpages); +#ifdef CONFIG_DEBUG_RODATA +void mark_rodata_ro(void); +void set_kernel_text_rw(void); +void set_kernel_text_ro(void); +#else +static inline void set_kernel_text_rw(void) { } +static inline void set_kernel_text_ro(void) { } +#endif + #endif diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c index 34e56647dcee..4ae343c1e2a3 100644 --- a/arch/arm/kernel/ftrace.c +++ b/arch/arm/kernel/ftrace.c @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -34,6 +35,22 @@ #define OLD_NOP 0xe1a00000 /* mov r0, r0 */ +static int __ftrace_modify_code(void *data) +{ + int *command = data; + + set_kernel_text_rw(); + ftrace_modify_all_code(*command); + set_kernel_text_ro(); + + return 0; +} + +void arch_ftrace_update_code(int command) +{ + stop_machine(__ftrace_modify_code, &command, NULL); +} + static unsigned long ftrace_nop_replace(struct dyn_ftrace *rec) { return rec->arch.old_mcount ? OLD_NOP : NOP; diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index 08fa667ef2f1..ec79e7268e09 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -120,6 +120,9 @@ SECTIONS ARM_CPU_KEEP(PROC_INFO) } +#ifdef CONFIG_DEBUG_RODATA + . = ALIGN(1<active_mm; + pmd = pmd_offset(pud_offset(pgd_offset(mm, addr), addr), addr); #ifdef CONFIG_ARM_LPAE pmd[0] = __pmd((pmd_val(pmd[0]) & mask) | prot); @@ -681,30 +716,52 @@ static inline bool arch_has_strict_perms(void) return true; } +#define set_section_perms(perms, field) { \ + size_t i; \ + unsigned long addr; \ + \ + if (!arch_has_strict_perms()) \ + return; \ + \ + for (i = 0; i < ARRAY_SIZE(perms); i++) { \ + if (!IS_ALIGNED(perms[i].start, SECTION_SIZE) || \ + !IS_ALIGNED(perms[i].end, SECTION_SIZE)) { \ + pr_err("BUG: section %lx-%lx not aligned to %lx\n", \ + perms[i].start, perms[i].end, \ + SECTION_SIZE); \ + continue; \ + } \ + \ + for (addr = perms[i].start; \ + addr < perms[i].end; \ + addr += SECTION_SIZE) \ + section_update(addr, perms[i].mask, \ + perms[i].field); \ + } \ +} + static inline void fix_kernmem_perms(void) { - unsigned long addr; - unsigned int i; + set_section_perms(nx_perms, prot); +} - if (!arch_has_strict_perms()) - return; +#ifdef CONFIG_DEBUG_RODATA +void mark_rodata_ro(void) +{ + set_section_perms(ro_perms, prot); +} - for (i = 0; i < ARRAY_SIZE(section_perms); i++) { - if (!IS_ALIGNED(section_perms[i].start, SECTION_SIZE) || - !IS_ALIGNED(section_perms[i].end, SECTION_SIZE)) { - pr_err("BUG: section %lx-%lx not aligned to %lx\n", - section_perms[i].start, section_perms[i].end, - SECTION_SIZE); - continue; - } +void set_kernel_text_rw(void) +{ + set_section_perms(ro_perms, clear); +} - for (addr = section_perms[i].start; - addr < section_perms[i].end; - addr += SECTION_SIZE) - section_update(addr, section_perms[i].mask, - section_perms[i].prot); - } +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 */ -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/