From patchwork Fri Apr 4 02:15:19 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 3935391 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 69B6EBFF02 for ; Fri, 4 Apr 2014 02:17:18 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 5FF9D2034F for ; Fri, 4 Apr 2014 02:17:17 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 38A902035D for ; Fri, 4 Apr 2014 02:17:16 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1WVtgS-0003Zw-BS; Fri, 04 Apr 2014 02:16:44 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1WVtgP-0003lh-OL; Fri, 04 Apr 2014 02:16:41 +0000 Received: from smtp.outflux.net ([2001:19d0:2:6:c0de:0:736d:7470]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1WVtgE-0003kD-NT for linux-arm-kernel@lists.infradead.org; Fri, 04 Apr 2014 02:16:32 +0000 Received: from www.outflux.net (serenity.outflux.net [10.2.0.2]) by vinyl.outflux.net (8.14.4/8.14.4/Debian-2ubuntu2.1) with ESMTP id s342FX1g029783; Thu, 3 Apr 2014 19:15:33 -0700 From: Kees Cook To: linux-arm-kernel@lists.infradead.org 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-MIMEDefang-Filter: outflux$Revision: 1.316 $ X-HELO: www.outflux.net X-Scanned-By: MIMEDefang 2.71 on 10.2.0.1 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140403_221630_989883_55888328 X-CRM114-Status: GOOD ( 20.47 ) X-Spam-Score: -2.5 (--) Cc: Russell King , Kees Cook , Catalin Marinas , Laura Abbott , Will Deacon , linux-kernel@vger.kernel.org, Rabin Vincent , Alexander Holler X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.8 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 */