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: 12812046 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 kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 45F2AC433F5 for ; Wed, 13 Apr 2022 13:50:03 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id CE2276B0074; Wed, 13 Apr 2022 09:50:02 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id C6A6A6B0075; Wed, 13 Apr 2022 09:50:02 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id AE4056B0078; Wed, 13 Apr 2022 09:50:02 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (relay.hostedemail.com [64.99.140.27]) by kanga.kvack.org (Postfix) with ESMTP id 9BBF26B0074 for ; Wed, 13 Apr 2022 09:50:02 -0400 (EDT) Received: from smtpin18.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay01.hostedemail.com (Postfix) with ESMTP id 6E2EE60D36 for ; Wed, 13 Apr 2022 13:50:02 +0000 (UTC) X-FDA: 79351989444.18.19C35E3 Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by imf24.hostedemail.com (Postfix) with ESMTP id B9902180003 for ; Wed, 13 Apr 2022 13:50:01 +0000 (UTC) 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-Stat-Signature: 41udpmibwyqxgimmbaqkupb4fecmnujs Authentication-Results: imf24.hostedemail.com; dkim=none; spf=pass (imf24.hostedemail.com: domain of cmarinas@kernel.org designates 145.40.68.75 as permitted sender) smtp.mailfrom=cmarinas@kernel.org; dmarc=fail reason="SPF not aligned (relaxed), No valid DKIM" header.from=arm.com (policy=none) X-Rspam-User: X-Rspamd-Server: rspam08 X-Rspamd-Queue-Id: B9902180003 X-HE-Tag: 1649857801-297091 X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: 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;