From patchwork Wed Oct 7 07:39:31 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jann Horn X-Patchwork-Id: 11819879 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A0E1D6CA for ; Wed, 7 Oct 2020 07:41:32 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 5D41E207EA for ; Wed, 7 Oct 2020 07:41:32 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="xxWvP/0w"; dkim=fail reason="signature verification failed" (2048-bit key) header.d=google.com header.i=@google.com header.b="ruoXB4q0" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 5D41E207EA Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:Message-Id:Date:Subject:To:From: Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender :Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Owner; bh=iKLOxEp+zY525lx5PtyNIjVtLC8TFCmFeAULxyieopM=; b=xxWvP/0wwfAFUg5bS0vcb9Cn3Q h4XA9n8oJItMu7SiFeiCvCaxhpy1nb6QZOfN7byqqcLecRROAmxgeLjy6vtmKnBwFu1o493SJi4vd k00JUbgDIBaYqsZaCoQHeUEBCWuT12FC4DGto6/tbij1MCr++qmaklaQwL6+/c8ariihhl068KkO+ QRbHTIsisQppL3fC/wby/Hroc9Y7rc+M/0WVSxNYd0UP2cwF0gB+RoGocN5FRQ7EeLKkQpFDXX8Ny Ck09SQs9J9OfmlmJkopSzQUBv+Af9FzoYTUG7dnjBp0P8J3nb0qQKXr8Cz9lFaMC7hdv4ZHdfVtg4 doI6HdYg==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kQ438-0004fc-V9; Wed, 07 Oct 2020 07:39:47 +0000 Received: from mail-wr1-x443.google.com ([2a00:1450:4864:20::443]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1kQ436-0004eG-0P for linux-arm-kernel@lists.infradead.org; Wed, 07 Oct 2020 07:39:45 +0000 Received: by mail-wr1-x443.google.com with SMTP id e17so933387wru.12 for ; Wed, 07 Oct 2020 00:39:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=RYwEGS7gOxFlwuQRTr7QM+pg66rzdyTCfIUfekhpUBo=; b=ruoXB4q0W4dOYr0HkGK3Qg2MUNaxXi9Tfm5XoN+wJuao1gaRUueT0KcnNUVdAc6i7R ad7CYmcCeYVK++bMrK+3TtUU+XRMTKATzz4A0NJN3o7RmWQUbCtCU/k7VX8UmjxZCcLx 90FV/U6rqDEoHznYihJVKIjTp59Cgm6dxLKO0y4kB8P9aqgDO09c+9jYYxfNjQeQwLeT 0iJgvI4hvfuLW4QF6oH+DgdLqWEER3NlD8sgZ8ZestVegmAZlB3/yPVxiKvaoeSu1NTg gTBMILXz/Q4NZ/g/+Fxx+UK5QvpWKKFVUDzwBk6TTlfiUYgu85IgWeCGYmrwbyzcKAGT TBSw== 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:mime-version :content-transfer-encoding; bh=RYwEGS7gOxFlwuQRTr7QM+pg66rzdyTCfIUfekhpUBo=; b=otG+J5pN2THej5Hz8vn1ZNcBZrT0O7uI/XLJYj3XwvCNE7VAgXFPkfeJO6fTT5xsjz xoYX/bLDPnuZaw9l1S7ytiMM5U4xHLNcNtf/QX4b/4KIVFP1tn7qPQW7BHAk+IzJO7Xm Bo5Ij/zxht0Xdc539gqtGPZTxMRkM+LK5Jd7xRJAwCw3EaOB/QKJ/P4HbizKKdrLJcXw oMBFy6IpXIhE3JSPtLxMgucfDIMJ/xPKIeTslcSg1Z3mtUXpXS4+0VRsZAtSiHuqsSM1 Ug7WFqLRxUIf1qxp/zG4PLIYKHc8wVO4cTqKFvSbfgz+2JrJpDAzJgxvrNipEr7S6B3H gYiA== X-Gm-Message-State: AOAM532aOKRwYAp0hKOtvrMOjRk4yzap3xIiLsBri5Smt7K3E8gICSqW 2f2pMKLYuG1El6UJJMsaSxK5RA== X-Google-Smtp-Source: ABdhPJx+7ke9fEecAqH/fAr9lPYggeTnVTs2kZ4YZOSai+UmsGlcT1A4NpyX9005g+lQnoEoGseTpw== X-Received: by 2002:adf:e88a:: with SMTP id d10mr2072440wrm.247.1602056382670; Wed, 07 Oct 2020 00:39:42 -0700 (PDT) Received: from localhost ([2a02:168:96c5:1:55ed:514f:6ad7:5bcc]) by smtp.gmail.com with ESMTPSA id r3sm1639024wrm.51.2020.10.07.00.39.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 07 Oct 2020 00:39:41 -0700 (PDT) From: Jann Horn To: "David S. Miller" , sparclinux@vger.kernel.org, Andrew Morton , linux-mm@kvack.org Subject: [PATCH 1/2] mm/mprotect: Call arch_validate_prot under mmap_lock and with length Date: Wed, 7 Oct 2020 09:39:31 +0200 Message-Id: <20201007073932.865218-1-jannh@google.com> X-Mailer: git-send-email 2.28.0.806.g8561365e88-goog MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20201007_033944_158811_37E7513D X-CRM114-Status: GOOD ( 21.61 ) X-Spam-Score: -15.7 (---------------) X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary: Content analysis details: (-15.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2a00:1450:4864:20:0:0:0:443 listed in] [list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -7.5 USER_IN_DEF_SPF_WL From: address is in the default SPF white-list -7.5 USER_IN_DEF_DKIM_WL From: address is in the default DKIM white-list 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.5 ENV_AND_HDR_SPF_MATCH Env and Hdr From used in default SPF WL Match -0.0 DKIMWL_WL_MED DKIMwl.org - Medium trust sender X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Benjamin Herrenschmidt , Catalin Marinas , linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org, Christoph Hellwig , Khalid Aziz , Paul Mackerras , Michael Ellerman , Anthony Yznaga , Will Deacon , linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org arch_validate_prot() is a hook that can validate whether a given set of protection flags is valid in an mprotect() operation. It is given the set of protection flags and the address being modified. However, the address being modified can currently not actually be used in a meaningful way because: 1. Only the address is given, but not the length, and the operation can span multiple VMAs. Therefore, the callee can't actually tell which virtual address range, or which VMAs, are being targeted. 2. The mmap_lock is not held, meaning that if the callee were to check the VMA at @addr, that VMA would be unrelated to the one the operation is performed on. Currently, custom arch_validate_prot() handlers are defined by arm64, powerpc and sparc. arm64 and powerpc don't care about the address range, they just check the flags against CPU support masks. sparc's arch_validate_prot() attempts to look at the VMA, but doesn't take the mmap_lock. Change the function signature to also take a length, and move the arch_validate_prot() call in mm/mprotect.c down into the locked region. Cc: stable@vger.kernel.org Fixes: 9035cf9a97e4 ("mm: Add address parameter to arch_validate_prot()") Suggested-by: Khalid Aziz Suggested-by: Christoph Hellwig Signed-off-by: Jann Horn Reviewed-by: Khalid Aziz --- arch/arm64/include/asm/mman.h | 4 ++-- arch/powerpc/include/asm/mman.h | 3 ++- arch/powerpc/kernel/syscalls.c | 2 +- arch/sparc/include/asm/mman.h | 6 ++++-- include/linux/mman.h | 3 ++- mm/mprotect.c | 6 ++++-- 6 files changed, 15 insertions(+), 9 deletions(-) base-commit: c85fb28b6f999db9928b841f63f1beeb3074eeca diff --git a/arch/arm64/include/asm/mman.h b/arch/arm64/include/asm/mman.h index 081ec8de9ea6..0876a87986dc 100644 --- a/arch/arm64/include/asm/mman.h +++ b/arch/arm64/include/asm/mman.h @@ -23,7 +23,7 @@ static inline pgprot_t arch_vm_get_page_prot(unsigned long vm_flags) #define arch_vm_get_page_prot(vm_flags) arch_vm_get_page_prot(vm_flags) static inline bool arch_validate_prot(unsigned long prot, - unsigned long addr __always_unused) + unsigned long addr __always_unused, unsigned long len __always_unused) { unsigned long supported = PROT_READ | PROT_WRITE | PROT_EXEC | PROT_SEM; @@ -32,6 +32,6 @@ static inline bool arch_validate_prot(unsigned long prot, return (prot & ~supported) == 0; } -#define arch_validate_prot(prot, addr) arch_validate_prot(prot, addr) +#define arch_validate_prot(prot, addr, len) arch_validate_prot(prot, addr, len) #endif /* ! __ASM_MMAN_H__ */ diff --git a/arch/powerpc/include/asm/mman.h b/arch/powerpc/include/asm/mman.h index 7cb6d18f5cd6..65dd9b594985 100644 --- a/arch/powerpc/include/asm/mman.h +++ b/arch/powerpc/include/asm/mman.h @@ -36,7 +36,8 @@ static inline pgprot_t arch_vm_get_page_prot(unsigned long vm_flags) } #define arch_vm_get_page_prot(vm_flags) arch_vm_get_page_prot(vm_flags) -static inline bool arch_validate_prot(unsigned long prot, unsigned long addr) +static inline bool arch_validate_prot(unsigned long prot, unsigned long addr, + unsigned long len) { if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC | PROT_SEM | PROT_SAO)) return false; diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c index 078608ec2e92..b1fabb97d138 100644 --- a/arch/powerpc/kernel/syscalls.c +++ b/arch/powerpc/kernel/syscalls.c @@ -43,7 +43,7 @@ static inline long do_mmap2(unsigned long addr, size_t len, { long ret = -EINVAL; - if (!arch_validate_prot(prot, addr)) + if (!arch_validate_prot(prot, addr, len)) goto out; if (shift) { diff --git a/arch/sparc/include/asm/mman.h b/arch/sparc/include/asm/mman.h index f94532f25db1..e85222c76585 100644 --- a/arch/sparc/include/asm/mman.h +++ b/arch/sparc/include/asm/mman.h @@ -52,9 +52,11 @@ static inline pgprot_t sparc_vm_get_page_prot(unsigned long vm_flags) return (vm_flags & VM_SPARC_ADI) ? __pgprot(_PAGE_MCD_4V) : __pgprot(0); } -#define arch_validate_prot(prot, addr) sparc_validate_prot(prot, addr) -static inline int sparc_validate_prot(unsigned long prot, unsigned long addr) +#define arch_validate_prot(prot, addr, len) sparc_validate_prot(prot, addr, len) +static inline int sparc_validate_prot(unsigned long prot, unsigned long addr, + unsigned long len) { + mmap_assert_write_locked(current->mm); if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC | PROT_SEM | PROT_ADI)) return 0; if (prot & PROT_ADI) { diff --git a/include/linux/mman.h b/include/linux/mman.h index 6f34c33075f9..5b4d554d3189 100644 --- a/include/linux/mman.h +++ b/include/linux/mman.h @@ -96,7 +96,8 @@ static inline void vm_unacct_memory(long pages) * * Returns true if the prot flags are valid */ -static inline bool arch_validate_prot(unsigned long prot, unsigned long addr) +static inline bool arch_validate_prot(unsigned long prot, unsigned long addr, + unsigned long len) { return (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC | PROT_SEM)) == 0; } diff --git a/mm/mprotect.c b/mm/mprotect.c index ce8b8a5eacbb..e2d6b51acbf8 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -533,14 +533,16 @@ static int do_mprotect_pkey(unsigned long start, size_t len, end = start + len; if (end <= start) return -ENOMEM; - if (!arch_validate_prot(prot, start)) - return -EINVAL; reqprot = prot; if (mmap_write_lock_killable(current->mm)) return -EINTR; + error = -EINVAL; + if (!arch_validate_prot(prot, start, len)) + goto out; + /* * If userspace did not allocate the pkey, do not let * them use it here.