From patchwork Wed Apr 13 13:49:44 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Catalin Marinas X-Patchwork-Id: 12812051 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id AF4BBC433EF for ; Wed, 13 Apr 2022 13:51:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=xT/Svh5hHvFSTkPeEYk51lGoSGvscL3BB3v765uSAWo=; b=mc7uvA0NgKcYrh h0cZFUbbo2kbP9SrhzhuEelZC0l+5Pdh/xQV69bI4WFuH+7E4nYdIL0/rmGemed08TZc2/kOJmk2Z ZMMVxKma3iks0KzQ1LRNYoLs55jfrWmOuOKmQlxyT81ckkNThsMvhN3u1Og57n9pCB2MYwy1Kp8PW N0+558m4n3p6mc9wfnvLJW/10P5KVUaSTg6upvvIhP1JNqU9b9aIz1lvbb3HlwQLAWZe2SQoyUVdu Cb8c9EFrWY+H6XQDfnyKbFzVfaPZlZXRlGyN4Lvy+HHYktu+byPqLs+v50X9/7CoQe0Zv68HlCeix vjgu6lIsThXWCDJC+cfw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nedO1-001GWb-NG; Wed, 13 Apr 2022 13:50:21 +0000 Received: from ams.source.kernel.org ([145.40.68.75]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nedNh-001GOp-O6 for linux-arm-kernel@lists.infradead.org; Wed, 13 Apr 2022 13:50:04 +0000 Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 6432AB824E4; Wed, 13 Apr 2022 13:50:00 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6B4ADC385A3; Wed, 13 Apr 2022 13:49:55 +0000 (UTC) From: Catalin Marinas To: Andrew Morton , Christoph Hellwig , Lennart Poettering , =?utf-8?q?Zbigniew_J=C4=99drze?= =?utf-8?q?jewski-Szmek?= Cc: Will Deacon , Alexander Viro , Eric Biederman , Kees Cook , Szabolcs Nagy , Mark Brown , Jeremy Linton , Topi Miettinen , linux-mm@kvack.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-abi-devel@lists.sourceforge.net Subject: [PATCH RFC 2/4] mm, personality: Implement memory-deny-write-execute as a personality flag Date: Wed, 13 Apr 2022 14:49:44 +0100 Message-Id: <20220413134946.2732468-3-catalin.marinas@arm.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220413134946.2732468-1-catalin.marinas@arm.com> References: <20220413134946.2732468-1-catalin.marinas@arm.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20220413_065002_124840_426DD3B7 X-CRM114-Status: GOOD ( 18.45 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org The aim of such policy is to prevent a user task from inadvertently creating an executable mapping that is or was writeable (and subsequently made read-only). An example of mmap() returning -EACCESS if the policy is enabled: mmap(0, size, PROT_READ | PROT_WRITE | PROT_EXEC, flags, 0, 0); Similarly, mprotect() would return -EACCESS below: addr = mmap(0, size, PROT_READ | PROT_EXEC, flags, 0, 0); mprotect(addr, size, PROT_READ | PROT_WRITE | PROT_EXEC); With the past vma writeable permission tracking, mprotect() below would also fail with -EACCESS: addr = mmap(0, size, PROT_READ | PROT_WRITE, flags, 0, 0); mprotect(addr, size, PROT_READ | PROT_EXEC); While the above could be achieved by checking PROT_WRITE & PROT_EXEC on mmap/mprotect and denying mprotect(PROT_EXEC) altogether (current systemd MDWE approach via SECCOMP BPF filters), we want the following scenario to succeed: addr = mmap(0, size, PROT_READ | PROT_EXEC, flags, 0, 0); mprotect(addr, size, PROT_READ | PROT_EXEC | PROT_BTI); where PROT_BTI enables branch tracking identification on arm64. The choice for a DENY_WRITE_EXEC personality flag, inherited on fork() and execve(), was made by analogy to READ_IMPLIES_EXEC. Note that it is sufficient to check for VM_WAS_WRITE in map_deny_write_exec() as this flag is always set on VM_WRITE mappings. Signed-off-by: Catalin Marinas Cc: Christoph Hellwig Cc: Andrew Morton --- include/linux/mman.h | 10 ++++++++++ include/uapi/linux/personality.h | 1 + mm/mmap.c | 3 +++ mm/mprotect.c | 5 +++++ 4 files changed, 19 insertions(+) diff --git a/include/linux/mman.h b/include/linux/mman.h index 2d841ddae2aa..17e91a1bdfb3 100644 --- a/include/linux/mman.h +++ b/include/linux/mman.h @@ -166,4 +166,14 @@ calc_vm_flag_bits(unsigned long flags) } unsigned long vm_commit_limit(void); + +static inline bool map_deny_write_exec(unsigned long vm_flags) +{ + if (IS_ENABLED(CONFIG_ARCH_ENABLE_DENY_WRITE_EXEC) && + (current->personality & DENY_WRITE_EXEC) && + (vm_flags & VM_EXEC) && (vm_flags & VM_WAS_WRITE)) + return true; + return false; +} + #endif /* _LINUX_MMAN_H */ diff --git a/include/uapi/linux/personality.h b/include/uapi/linux/personality.h index 49796b7756af..c8d924be3dcd 100644 --- a/include/uapi/linux/personality.h +++ b/include/uapi/linux/personality.h @@ -22,6 +22,7 @@ enum { WHOLE_SECONDS = 0x2000000, STICKY_TIMEOUTS = 0x4000000, ADDR_LIMIT_3GB = 0x8000000, + DENY_WRITE_EXEC = 0x10000000, }; /* diff --git a/mm/mmap.c b/mm/mmap.c index 3aa839f81e63..8e894270a80e 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1579,6 +1579,9 @@ unsigned long do_mmap(struct file *file, unsigned long addr, vm_flags |= VM_NORESERVE; } + if (map_deny_write_exec(vm_flags)) + return -EACCES; + addr = mmap_region(file, addr, len, vm_flags, pgoff, uf); if (!IS_ERR_VALUE(addr) && ((vm_flags & VM_LOCKED) || diff --git a/mm/mprotect.c b/mm/mprotect.c index b69ce7a7b2b7..ff0d13a4c1ed 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -627,6 +627,11 @@ static int do_mprotect_pkey(unsigned long start, size_t len, goto out; } + if (map_deny_write_exec(newflags)) { + error = -EACCES; + goto out; + } + /* Allow architectures to sanity-check the new flags */ if (!arch_validate_flags(newflags)) { error = -EINVAL;