From patchwork Wed Mar 29 18:15:53 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 9652207 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id D637D602C8 for ; Wed, 29 Mar 2017 18:17:26 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C055D27165 for ; Wed, 29 Mar 2017 18:17:26 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B5096284EF; Wed, 29 Mar 2017 18:17:26 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.1 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.wl.linuxfoundation.org (Postfix) with SMTP id 9CA5D27165 for ; Wed, 29 Mar 2017 18:17:25 +0000 (UTC) Received: (qmail 24052 invoked by uid 550); 29 Mar 2017 18:16:53 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Received: (qmail 20368 invoked from network); 29 Mar 2017 18:16:34 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=zlkiRT9AyW3/nSkVnueEO+byp+8dXSqmdZQZBk4PW6M=; b=JjXb/WNOBv30CnzKrgL4TOVcUXJe69v56C7CErvtSUpLhHtYDk7Ix+6iWdC2sKEW5D 0GpZSoiO+LnDp6mK9jqE8LufepEtwf9JjDwKpcIB164EDv/vBUrYECYJ0YJAw86AUiyo 7CY91r1d8kIhxgHj4o12k/W33bwos7LNeNdzE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=zlkiRT9AyW3/nSkVnueEO+byp+8dXSqmdZQZBk4PW6M=; b=GupkB1THm4Ee132RKPvWz2xGWjhl7j0Whq8R04hBhMAtcsF+58UNq7v69GHLfH0liH ymWA9CPOIMnlRWUPmQV4AFbLa2kFRGra1Iw/4vBKJwzBNFuUpHQI/OtFMeDHXFUyYeD6 Wy++X6mZRD6x5mZRZpBOeaSmwcgFcN/n+d1alJF9ucd+rV82C7cympp9FqMuqpc0csNC sTNvNHMrjFHl60M2NKERcux0BKBc7lJ/YYPORgYXGbgoMo+7vxWXk46u7OBo+8ChQFGG obiCKyGGZZq+IsweC1xrCtszACUeCJX/A8Nz/UcrXPof7/9yDM4m+nhtlB5APAaIPhwt KIRA== X-Gm-Message-State: AFeK/H3RZD8jH/7Tg7n7+dj7c39yfdeHsEQYYTX2ELze9dThj7REP0CoaHOvVgcyqt29I1X6 X-Received: by 10.84.169.36 with SMTP id g33mr2180072plb.36.1490811382510; Wed, 29 Mar 2017 11:16:22 -0700 (PDT) From: Kees Cook To: kernel-hardening@lists.openwall.com Cc: Kees Cook , Mark Rutland , Andy Lutomirski , Hoeun Ryu , PaX Team , Emese Revfy , Russell King , x86@kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org Date: Wed, 29 Mar 2017 11:15:53 -0700 Message-Id: <1490811363-93944-2-git-send-email-keescook@chromium.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1490811363-93944-1-git-send-email-keescook@chromium.org> References: <1490811363-93944-1-git-send-email-keescook@chromium.org> Subject: [kernel-hardening] [RFC v2][PATCH 01/11] Introduce rare_write() infrastructure X-Virus-Scanned: ClamAV using ClamSMTP Several types of data storage exist in the kernel: read-write data (.data, .bss), read-only data (.rodata), and RO-after-init. This introduces the infrastructure for another type: write-rarely, which is intended for data that is either only rarely modified or especially security-sensitive. The goal is to further reduce the internal attack surface of the kernel by making this storage read-only when "at rest". This makes it much harder to be subverted by attackers who have a kernel-write flaw, since they cannot directly change these memory contents. This work is heavily based on PaX and grsecurity's pax_{open,close}_kernel API, its __read_only annotations, its constify plugin, and the work done to identify sensitive structures that should be moved from .data into .rodata. This builds the initial infrastructure to support these kinds of changes, though the API and naming has been adjusted in places for clarity and maintainability. Variables declared with the __wr_rare annotation will be moved to the .rodata section if an architecture supports CONFIG_HAVE_ARCH_WRITE_RARE. To change these variables, either a single rare_write() macro can be used, or multiple uses of __rare_write(), wrapped in a matching pair of rare_write_begin() and rare_write_end() macros can be used. These macros are expanded into the arch-specific functions that perform the actions needed to write to otherwise read-only memory. As detailed in the Kconfig help, the arch-specific helpers have several requirements to make them sensible/safe for use by the kernel: they must not allow non-current CPUs to write the memory area, they must run non-preemptible to avoid accidentally leaving memory writable, and must be inline to avoid making them desirable ROP targets for attackers. Signed-off-by: Kees Cook --- arch/Kconfig | 25 +++++++++++++++++++++++++ include/linux/compiler.h | 32 ++++++++++++++++++++++++++++++++ include/linux/preempt.h | 6 ++++-- 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index cd211a14a88f..5ebf62500b99 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -847,4 +847,29 @@ config STRICT_MODULE_RWX config ARCH_WANT_RELAX_ORDER bool +config HAVE_ARCH_RARE_WRITE + def_bool n + help + An arch should select this option if it has defined the functions + __arch_rare_write_begin() and __arch_rare_write_end() to + respectively enable and disable writing to read-only memory. The + routines must meet the following requirements: + - read-only memory writing must only be available on the current + CPU (to make sure other CPUs can't race to make changes too). + - the routines must be declared inline (to discourage ROP use). + - the routines must not be preemptible (likely they will call + preempt_disable() and preempt_enable_no_resched() respectively). + - the routines must validate expected state (e.g. when enabling + writes, BUG() if writes are already be enabled). + +config HAVE_ARCH_RARE_WRITE_MEMCPY + def_bool n + depends on HAVE_ARCH_RARE_WRITE + help + An arch should select this option if a special accessor is needed + to write to otherwise read-only memory, defined by the function + __arch_rare_write_memcpy(). Without this, the write-rarely + infrastructure will just attempt to write directly to the memory + using a const-ignoring assignment. + source "kernel/gcov/Kconfig" diff --git a/include/linux/compiler.h b/include/linux/compiler.h index f8110051188f..274bd03cfe9e 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -336,6 +336,38 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s __u.__val; \ }) +/* + * Build "write rarely" infrastructure for flipping memory r/w + * on a per-CPU basis. + */ +#ifndef CONFIG_HAVE_ARCH_RARE_WRITE +# define __wr_rare +# define __wr_rare_type +# define __rare_write(__var, __val) (__var = (__val)) +# define rare_write_begin() do { } while (0) +# define rare_write_end() do { } while (0) +#else +# define __wr_rare __ro_after_init +# define __wr_rare_type const +# ifdef CONFIG_HAVE_ARCH_RARE_WRITE_MEMCPY +# define __rare_write_n(dst, src, len) ({ \ + BUILD_BUG(!builtin_const(len)); \ + __arch_rare_write_memcpy((dst), (src), (len)); \ + }) +# define __rare_write(var, val) __rare_write_n(&(var), &(val), sizeof(var)) +# else +# define __rare_write(var, val) ((*(typeof((typeof(var))0) *)&(var)) = (val)) +# endif +# define rare_write_begin() __arch_rare_write_begin() +# define rare_write_end() __arch_rare_write_end() +#endif +#define rare_write(__var, __val) ({ \ + rare_write_begin(); \ + __rare_write(__var, __val); \ + rare_write_end(); \ + __var; \ +}) + #endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */ diff --git a/include/linux/preempt.h b/include/linux/preempt.h index cae461224948..4fc97aaa22ea 100644 --- a/include/linux/preempt.h +++ b/include/linux/preempt.h @@ -258,10 +258,12 @@ do { \ /* * Modules have no business playing preemption tricks. */ -#undef sched_preempt_enable_no_resched -#undef preempt_enable_no_resched #undef preempt_enable_no_resched_notrace #undef preempt_check_resched +#ifndef CONFIG_HAVE_ARCH_RARE_WRITE +#undef sched_preempt_enable_no_resched +#undef preempt_enable_no_resched +#endif #endif #define preempt_set_need_resched() \