From patchwork Mon May 15 13:05:47 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Xu X-Patchwork-Id: 13241402 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 DCA77C7EE22 for ; Mon, 15 May 2023 13:08:03 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 5BDE5900009; Mon, 15 May 2023 09:08:03 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 56D5990000A; Mon, 15 May 2023 09:08:03 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 40E70900009; Mon, 15 May 2023 09:08:03 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0010.hostedemail.com [216.40.44.10]) by kanga.kvack.org (Postfix) with ESMTP id 259FE900002 for ; Mon, 15 May 2023 09:08:03 -0400 (EDT) Received: from smtpin05.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay09.hostedemail.com (Postfix) with ESMTP id B583A80F15 for ; Mon, 15 May 2023 13:08:02 +0000 (UTC) X-FDA: 80792517204.05.7BE2D94 Received: from mail-pg1-f174.google.com (mail-pg1-f174.google.com [209.85.215.174]) by imf28.hostedemail.com (Postfix) with ESMTP id 1E623C01AB for ; Mon, 15 May 2023 13:06:02 +0000 (UTC) Authentication-Results: imf28.hostedemail.com; dkim=pass header.d=chromium.org header.s=google header.b="N/+vAM46"; spf=pass (imf28.hostedemail.com: domain of jeffxu@chromium.org designates 209.85.215.174 as permitted sender) smtp.mailfrom=jeffxu@chromium.org; dmarc=pass (policy=none) header.from=chromium.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1684155963; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=amUmjeQdjogZim3KCvDHtpibL1Mlx7r/unbXJ7VLzz4=; b=yUTzj1JOrhwLTd3BtH1JsPKUbOXyTzjxiTBffR/TgddfOIisF4FlqwX4OLunfXb4jyqlgo 7V00rvCpWxvJcRiRNpfbTZLqvpZhtl4P5OSj1BzHlTUDZcsXMvP6PXsUVHBy9Y+X3Lx1Np +cN+JpCEKTsueimhLmcjPalRwT7rQOk= ARC-Authentication-Results: i=1; imf28.hostedemail.com; dkim=pass header.d=chromium.org header.s=google header.b="N/+vAM46"; spf=pass (imf28.hostedemail.com: domain of jeffxu@chromium.org designates 209.85.215.174 as permitted sender) smtp.mailfrom=jeffxu@chromium.org; dmarc=pass (policy=none) header.from=chromium.org ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1684155963; a=rsa-sha256; cv=none; b=ymaQT+jHVLk5GvStL5xqiMXkAxRJnsGwhfAnksyPPT/kHji+0FdF86clinur8Q43LULwP4 IcQY9GkbBcDCc3UaUjOqqaeiUmaV0UMxc7tj90JCqTh1d/Zn8KmkpSNJIUyrYmazUbnWeB F/blJIpN070VRNFuu0VL5bK4WAGMq98= Received: by mail-pg1-f174.google.com with SMTP id 41be03b00d2f7-52c30fbccd4so11751142a12.0 for ; Mon, 15 May 2023 06:06:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1684155961; x=1686747961; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=amUmjeQdjogZim3KCvDHtpibL1Mlx7r/unbXJ7VLzz4=; b=N/+vAM467OglvcK5xTQfs4XWaq6XdqOUlnNqgaqWQ23QJto1u5hnHaDbMk15m9A1Dr YOq7k5ElDFHK8lgmhn3iChrsAtjQgcB4vHR77/JH3M/x2tgCBJK502XSHwtBKBaZYzbk rA7ZQqU99ZIhg7TK53UiwR7aFgmnN3dZNqKsA= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684155961; x=1686747961; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=amUmjeQdjogZim3KCvDHtpibL1Mlx7r/unbXJ7VLzz4=; b=H7w+alu4XP/Q3H3aFnVndPinCwT2LOTnFyrnWPTvf+g121QKjQH1D1gKuC4JO1OKyD JH4P0mc2jfELJyFbzMHM2eDyisPVazzEipCXYeE4Q8prpB5aDKRF6svAJKGKiJFg0D1H iO9bZU21JCv2sQ5167hZzA20fNkK7leE1Z+PvOEwiRZ/TWeRbM0ZlhlGRcq87Gq+Ta+r FeABRK1iQRRKEGG4+uDgcm4kLE0eBin2nREtGEniDZF38DmXx3nKorOAy0k9/OeMuC+c fHHEzT+GrOJhqTGy0UBkAlinMj7xaqeabF1oo+bOUMzJC8g9tKZ+Qvh6bUNUvvzAhav3 LQfQ== X-Gm-Message-State: AC+VfDzvwCiyTzZNgdzaUzFnbSkNjT04keuX3HksNqFgNDpN3/ikruFN RzzHy9pVW/hFBakN/I7Y2EAOrQ== X-Google-Smtp-Source: ACHHUZ54OoJ9C5mGmXEjFBPZ+0O08cKmkUJ5oO7isFCKnT6ICVIBMxV1xzNCBVY30Rgzi3YVlV184g== X-Received: by 2002:a05:6a20:72aa:b0:100:d061:52ce with SMTP id o42-20020a056a2072aa00b00100d06152cemr30768717pzk.55.1684155961118; Mon, 15 May 2023 06:06:01 -0700 (PDT) Received: from localhost (183.43.230.35.bc.googleusercontent.com. [35.230.43.183]) by smtp.gmail.com with UTF8SMTPSA id g17-20020aa78751000000b005aa60d8545esm11745710pfo.61.2023.05.15.06.06.00 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 15 May 2023 06:06:00 -0700 (PDT) From: jeffxu@chromium.org To: dave.hansen@intel.com, luto@kernel.org, jorgelo@chromium.org, keescook@chromium.org, groeck@chromium.org, jannh@google.com, sroettger@google.com Cc: akpm@linux-foundation.org, jeffxu@google.com, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org, linux-hardening@vger.kernel.org Subject: [PATCH 1/6] PKEY: Introduce PKEY_ENFORCE_API flag Date: Mon, 15 May 2023 13:05:47 +0000 Message-ID: <20230515130553.2311248-2-jeffxu@chromium.org> X-Mailer: git-send-email 2.40.1.606.ga4b1b128d6-goog In-Reply-To: <20230515130553.2311248-1-jeffxu@chromium.org> References: <20230515130553.2311248-1-jeffxu@chromium.org> MIME-Version: 1.0 X-Rspam-User: X-Rspamd-Server: rspam01 X-Rspamd-Queue-Id: 1E623C01AB X-Stat-Signature: tfzy4dq4rnm5nrkwox5rkyq7efkc8ayf X-HE-Tag: 1684155962-851798 X-HE-Meta: U2FsdGVkX1+xWf7oQVev4dYDYWLS/Ax1ifhtQQaOW22NNGxez8CoEOX5RiDf5PfH0GPComrpiC0VtEjivYD/RKzo8SEfG1ZLBzpqW0l3l2iOaxYrw1jqvKOGkclWTyI8Od4TgaDvWnwNWQAXDTGOdzTayCtHSIiWvqg9amugENKxNSmVBush6xcnXJGpDX1c9sq6pUy5vI78x6rCDwJmh7Zy4jt1rUBRc60NMgSFpcseEvt+C/xXG+jAXlPBa+DeIP652x9ipWwvOU6sQdXKWnm665lVNnjJfmUQ0MUPT33VUwvEkM5XsASqcSR6oreb4mqm8wYM1n15ESSXwXNxd+VdliJ4+gfXpF3Hu6nEOvGfBPXHT4FqZ63VmE7qjNMeNJzGnhRK+6Mkty1HRnHKm6hiK/vfzxeoW4M2tah1cxrHlfWYne92Vg/42Zx9hwOE/KOsie4/mGhQvvS31K/jSMngcoXn1THhaHEuWijVW63Jzrzga1ypsMXWUEc153tqGVUAXJDzL4/YE/OfTljJFs0b/Ca4+MOKkgSMT4rERaxQsDdOM04q7oZD4IlyypSH95g0vffNvn+TRp+DzJ143rC3dp/zHukzOxFzOzq4khNUpJM352H62/ZquOUpvxjSKq9zHdOCkmpH09y2j+GNdY3K+CQ+SHTFWKyNwhX1rrB7uS3D3WErAwHmD42zV/iY4N4X6x38h6RczL3tRvAIT8g3TB1R2vWiJBCqpNCA6RsmyDJbMV+6MEteq+iZtWK1GEgCdnx5WhvuqRcqME1eDpoYnAHkagMZCibrH57udaD1BxMffH9/6zGQowweUvF8dlz6olmIoJHozYcmCsCkBTr0o0R4vJrtfRiVq1OUPRNFQa14zuTnA1yjeFsdVLDl6jFssEDZalLw8R9/tZSIrjJ9F4YXoHYtVxfBTlRgchwu7z16SX7okcYhlrjW/H0t6lrMzrKz3U4bolug/2Z nonL4c9X SaK96rypRJ77wYkcyQofsoykjUwhkGm6d59Zqg4xKaaJeSqzF4xzRECdAqNKtdyLcZUQwGWIGOMcomEYmTYmvlT6NM9Wc9HCyPqPuW0m1znIlN4+rldPBTRDl4CxP6lOkmqW7ds1C61Dc5YjdcS8Uul/00fiApHfSiTG84mVUgloXNADysgnnJYrFGt2LR0niH7J9D9PB2VVfvPSb1r6hBSxTC7zl7+GFUWyrMu9dg+E3Udf5J6tK6/raiZcNYHrPpge6508exdp2UA+a228Fnmia+9a6X2SBHAMdwYY/4RgAWud/eCRx3r37vZQva5xFjgYXONoRFrd5qwHAplGRPDvQdmKcfkwYuxvyVqJ7SM0+KNtathFeVMgX8w== 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: From: Jeff Xu This patch introduces a new flag, PKEY_ENFORCE_API, to the pkey_alloc() function. When a PKEY is created with this flag, it is enforced that any thread that wants to make changes to the memory mapping (such as mprotect/munmap) of the memory must have write access to the PKEY. This is to prevent unauthorized access to protected memory. PKEYs created without this flag will continue to work as they do now, for backwards compatibility. Signed-off-by: Jeff Xu --- arch/powerpc/include/asm/pkeys.h | 11 ++++++++- arch/x86/include/asm/mmu.h | 7 ++++++ arch/x86/include/asm/pkeys.h | 42 ++++++++++++++++++++++++++++++-- arch/x86/mm/pkeys.c | 2 +- include/linux/pkeys.h | 9 ++++++- include/uapi/linux/mman.h | 5 ++++ mm/mprotect.c | 6 ++--- 7 files changed, 74 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/include/asm/pkeys.h b/arch/powerpc/include/asm/pkeys.h index 59a2c7dbc78f..943333ac0fee 100644 --- a/arch/powerpc/include/asm/pkeys.h +++ b/arch/powerpc/include/asm/pkeys.h @@ -82,7 +82,7 @@ static inline bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey) * Relies on the mmap_lock to protect against concurrency in mm_pkey_alloc() and * mm_pkey_free(). */ -static inline int mm_pkey_alloc(struct mm_struct *mm) +static inline int mm_pkey_alloc(struct mm_struct *mm, unsigned long flags) { /* * Note: this is the one and only place we make sure that the pkey is @@ -168,5 +168,14 @@ static inline bool arch_pkeys_enabled(void) return mmu_has_feature(MMU_FTR_PKEY); } +static inline bool arch_check_pkey_alloc_flags(unsigned long flags) +{ + /* No flags supported yet. */ + if (flags) + return false; + + return true; +} + extern void pkey_mm_init(struct mm_struct *mm); #endif /*_ASM_POWERPC_KEYS_H */ diff --git a/arch/x86/include/asm/mmu.h b/arch/x86/include/asm/mmu.h index 0da5c227f490..d97594b44d9a 100644 --- a/arch/x86/include/asm/mmu.h +++ b/arch/x86/include/asm/mmu.h @@ -66,6 +66,13 @@ typedef struct { */ u16 pkey_allocation_map; s16 execute_only_pkey; + /* + * One bit per protection key. + * When set, thread must have write permission on corresponding + * PKRU in order to call memory mapping API, such as mprotect, + * munmap, etc. + */ + u16 pkey_enforce_api_map; #endif } mm_context_t; diff --git a/arch/x86/include/asm/pkeys.h b/arch/x86/include/asm/pkeys.h index 2e6c04d8a45b..ecadf04a8251 100644 --- a/arch/x86/include/asm/pkeys.h +++ b/arch/x86/include/asm/pkeys.h @@ -51,6 +51,17 @@ static inline int arch_override_mprotect_pkey(struct vm_area_struct *vma, mm_pkey_allocation_map(mm) &= ~(1U << pkey); \ } while (0) +#define mm_pkey_enforce_api_map(mm) (mm->context.pkey_enforce_api_map) +#define mm_set_pkey_enforce_api(mm, pkey) \ + { \ + mm_pkey_enforce_api_map(mm) |= (1U << pkey); \ + } + +#define mm_clear_pkey_enforce_api(mm, pkey) \ + { \ + mm_pkey_enforce_api_map(mm) &= ~(1U << pkey); \ + } + static inline bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey) { @@ -74,11 +85,25 @@ bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey) return mm_pkey_allocation_map(mm) & (1U << pkey); } +/* + * Return true if the pkey has ENFORCE_API flag during allocation. + */ +static inline bool mm_pkey_enforce_api(struct mm_struct *mm, int pkey) +{ + /* + * Only pkey created by user space has the flag. + * execute_only_pkey check is in mm_pkey_is_allocated(). + */ + if (pkey != ARCH_DEFAULT_PKEY && mm_pkey_is_allocated(mm, pkey)) + return mm_pkey_enforce_api_map(mm) & (1U << pkey); + + return false; +} + /* * Returns a positive, 4-bit key on success, or -1 on failure. */ -static inline -int mm_pkey_alloc(struct mm_struct *mm) +static inline int mm_pkey_alloc(struct mm_struct *mm, unsigned long flags) { /* * Note: this is the one and only place we make sure @@ -101,6 +126,9 @@ int mm_pkey_alloc(struct mm_struct *mm) mm_set_pkey_allocated(mm, ret); + if (flags & PKEY_ENFORCE_API) + mm_set_pkey_enforce_api(mm, ret); + return ret; } @@ -110,6 +138,7 @@ int mm_pkey_free(struct mm_struct *mm, int pkey) if (!mm_pkey_is_allocated(mm, pkey)) return -EINVAL; + mm_clear_pkey_enforce_api(mm, pkey); mm_set_pkey_free(mm, pkey); return 0; @@ -123,4 +152,13 @@ static inline int vma_pkey(struct vm_area_struct *vma) return (vma->vm_flags & vma_pkey_mask) >> VM_PKEY_SHIFT; } +static inline bool arch_check_pkey_alloc_flags(unsigned long flags) +{ + unsigned long valid_flags = PKEY_ENFORCE_API; + + if (flags & ~valid_flags) + return false; + + return true; +} #endif /*_ASM_X86_PKEYS_H */ diff --git a/arch/x86/mm/pkeys.c b/arch/x86/mm/pkeys.c index 7418c367e328..a76981f44acf 100644 --- a/arch/x86/mm/pkeys.c +++ b/arch/x86/mm/pkeys.c @@ -20,7 +20,7 @@ int __execute_only_pkey(struct mm_struct *mm) /* Do we need to assign a pkey for mm's execute-only maps? */ if (execute_only_pkey == -1) { /* Go allocate one to use, which might fail */ - execute_only_pkey = mm_pkey_alloc(mm); + execute_only_pkey = mm_pkey_alloc(mm, 0); if (execute_only_pkey < 0) return -1; need_to_set_mm_pkey = true; diff --git a/include/linux/pkeys.h b/include/linux/pkeys.h index 86be8bf27b41..81a482c3e051 100644 --- a/include/linux/pkeys.h +++ b/include/linux/pkeys.h @@ -3,6 +3,7 @@ #define _LINUX_PKEYS_H #include +#include #define ARCH_DEFAULT_PKEY 0 @@ -25,7 +26,7 @@ static inline bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey) return (pkey == 0); } -static inline int mm_pkey_alloc(struct mm_struct *mm) +static inline int mm_pkey_alloc(struct mm_struct *mm, unsigned long flags) { return -1; } @@ -46,6 +47,12 @@ static inline bool arch_pkeys_enabled(void) return false; } +static inline bool arch_check_pkey_alloc_flags(unsigned long flags) +{ + if (flags) + return false; + return true; +} #endif /* ! CONFIG_ARCH_HAS_PKEYS */ #endif /* _LINUX_PKEYS_H */ diff --git a/include/uapi/linux/mman.h b/include/uapi/linux/mman.h index f55bc680b5b0..8c69b9a7ff5b 100644 --- a/include/uapi/linux/mman.h +++ b/include/uapi/linux/mman.h @@ -41,4 +41,9 @@ #define MAP_HUGE_2GB HUGETLB_FLAG_ENCODE_2GB #define MAP_HUGE_16GB HUGETLB_FLAG_ENCODE_16GB +/* + * Flags for pkey_alloc + */ +#define PKEY_ENFORCE_API (1 << 0) + #endif /* _UAPI_LINUX_MMAN_H */ diff --git a/mm/mprotect.c b/mm/mprotect.c index 92d3d3ca390a..8a68fdca8487 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -894,15 +894,15 @@ SYSCALL_DEFINE2(pkey_alloc, unsigned long, flags, unsigned long, init_val) int pkey; int ret; - /* No flags supported yet. */ - if (flags) + if (!arch_check_pkey_alloc_flags(flags)) return -EINVAL; + /* check for unsupported init values */ if (init_val & ~PKEY_ACCESS_MASK) return -EINVAL; mmap_write_lock(current->mm); - pkey = mm_pkey_alloc(current->mm); + pkey = mm_pkey_alloc(current->mm, flags); ret = -ENOSPC; if (pkey == -1) From patchwork Mon May 15 13:05:48 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Xu X-Patchwork-Id: 13241401 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 38FF8C7EE22 for ; Mon, 15 May 2023 13:07:26 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 91AD7900008; Mon, 15 May 2023 09:07:25 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 8A280900002; Mon, 15 May 2023 09:07:25 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 74323900008; Mon, 15 May 2023 09:07:25 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0011.hostedemail.com [216.40.44.11]) by kanga.kvack.org (Postfix) with ESMTP id 5C395900002 for ; Mon, 15 May 2023 09:07:25 -0400 (EDT) Received: from smtpin24.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay09.hostedemail.com (Postfix) with ESMTP id D02A28125A for ; Mon, 15 May 2023 13:07:24 +0000 (UTC) X-FDA: 80792515608.24.B6E41CF Received: from mail-pl1-f169.google.com (mail-pl1-f169.google.com [209.85.214.169]) by imf25.hostedemail.com (Postfix) with ESMTP id 68A0FA02C1 for ; Mon, 15 May 2023 13:06:03 +0000 (UTC) Authentication-Results: imf25.hostedemail.com; dkim=pass header.d=chromium.org header.s=google header.b=lVLtpSyn; spf=pass (imf25.hostedemail.com: domain of jeffxu@chromium.org designates 209.85.214.169 as permitted sender) smtp.mailfrom=jeffxu@chromium.org; dmarc=pass (policy=none) header.from=chromium.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1684155963; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=TQS98FLuUxt8kfip9Nk8O1hVfeuWAt0sl7+06c/6tso=; b=aL/3YfKOlRjJnbmAA48Z1IMGQdoTNyChHCzP6UszQnOCEo+sPfT8xXqWaehD8RI8clXk0c Vd0TFB3Hv0fOMfGPfduI0iNMlytB7X82XLWHZzJu+9tMYwzRA5h37uYiyCE/aoHxiRhg17 fJQFG6Po8/Pit83ozxfFj1bXxC3xC1I= ARC-Authentication-Results: i=1; imf25.hostedemail.com; dkim=pass header.d=chromium.org header.s=google header.b=lVLtpSyn; spf=pass (imf25.hostedemail.com: domain of jeffxu@chromium.org designates 209.85.214.169 as permitted sender) smtp.mailfrom=jeffxu@chromium.org; dmarc=pass (policy=none) header.from=chromium.org ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1684155963; a=rsa-sha256; cv=none; b=Uxyl5wUnrIyCP5/RhRCbemlVD/0IrrivdpPuBAHDacuz02pVmZpuUdy8NtTjRg8zXZFYyp qQQ6+murfoQmIRIJCte6rSYjeGG8bqoUg6gsmsqqoJQ/mT2DoYDbTMwbQT75+JewIVsDCQ MZCylXj6pNeSE2To75kH/oc6V/5sSCM= Received: by mail-pl1-f169.google.com with SMTP id d9443c01a7336-1ab0c697c2bso117565585ad.1 for ; Mon, 15 May 2023 06:06:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1684155962; x=1686747962; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=TQS98FLuUxt8kfip9Nk8O1hVfeuWAt0sl7+06c/6tso=; b=lVLtpSynI8nMT2aDpFG0AwTYGHG10mCOzf2uMVGaztPOf63EnxTkd4eJJVNqJlr8C5 g4595V6nKOPML2z8/lcW1UhNkQhkCyXDVgAutORAhmXktQaBwlD2yr8BPgV8UP/5LyyG byJlw9BmRMYbGWCADO6h/aSqv0KiIADjBwCC4= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684155962; x=1686747962; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=TQS98FLuUxt8kfip9Nk8O1hVfeuWAt0sl7+06c/6tso=; b=OBvdI6cYWST8SI6yeE3oyo22t3tW8dDx8d4q9RaD/C/5+NBEguQoWvW2BNX08phrHu 79DQyet4znWePhVBZIVbu6fCzBB+ACIwTk+d1CXvriH18R121iPEmpnKQkFlqXYuZPao sU6aUaeD1uoI65iH/NcseKNXZ2KLFbEZ5Cy183WMI0PbSMWdeHPf5wPZszedbnsn1GNZ mOmocpX/ItgJot+VQ82CKUmWeRu96nizus/SESaNIvuLy/2O49azwWlMYBHhhivViBj1 NgRu7xNU+068vA3Xop+i/qvQwENVNHnfAe7TKRpp8Rf+LJc8Ys4QQeiuUX6m2f5eVWMR 0CMQ== X-Gm-Message-State: AC+VfDxvBUDNu9I1S71Hsmjll2Qmx/tjbSS6fEvLYzM7Op34UVbTg+sf GwwmX0POucgaKea4tvrYsECY1A== X-Google-Smtp-Source: ACHHUZ5LvI01D49NaxlHJHiG9oq5TunRXuf9uX9R4zcylWjAPhk6R7RxfjFf6bkyuvAy6sflWATEYg== X-Received: by 2002:a17:902:788d:b0:1ac:8215:623d with SMTP id q13-20020a170902788d00b001ac8215623dmr24516585pll.0.1684155961805; Mon, 15 May 2023 06:06:01 -0700 (PDT) Received: from localhost (183.43.230.35.bc.googleusercontent.com. [35.230.43.183]) by smtp.gmail.com with UTF8SMTPSA id nn4-20020a17090b38c400b0024df7d7c35esm1095703pjb.43.2023.05.15.06.06.01 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 15 May 2023 06:06:01 -0700 (PDT) From: jeffxu@chromium.org To: dave.hansen@intel.com, luto@kernel.org, jorgelo@chromium.org, keescook@chromium.org, groeck@chromium.org, jannh@google.com, sroettger@google.com Cc: akpm@linux-foundation.org, jeffxu@google.com, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org, linux-hardening@vger.kernel.org Subject: [PATCH 2/6] PKEY: Add arch_check_pkey_enforce_api() Date: Mon, 15 May 2023 13:05:48 +0000 Message-ID: <20230515130553.2311248-3-jeffxu@chromium.org> X-Mailer: git-send-email 2.40.1.606.ga4b1b128d6-goog In-Reply-To: <20230515130553.2311248-1-jeffxu@chromium.org> References: <20230515130553.2311248-1-jeffxu@chromium.org> MIME-Version: 1.0 X-Stat-Signature: orui74jq3jfrkuzh86f75i6wxdsacm9e X-Rspamd-Server: rspam05 X-Rspamd-Queue-Id: 68A0FA02C1 X-Rspam-User: X-HE-Tag: 1684155963-240352 X-HE-Meta: U2FsdGVkX18vcPonre/GGCfF3wLm4vds4ktD36qhoc2hkHM4U5Olza0p2+Lgr3MnlMvzgj/SPvf3m2bKxLpSk15C3FxgZTbtJli+IdRQ8H+DpEDq7cs/NRoBn5URSh7TOJlHP1LjaCa3jQu5dNQ8qAhaI0Uk0u4IxLJZQouPbdZPFpOqVVfisfLy5+8WkD7frB450WCZEqZHQ11heIaZlrIxOdLTZB4/DDy18zWQNijyO5L3hphnBE3twKyCRDQmEYL6RmV/FZm2lO+BtNE6H1eHGWNOgDItanIt8Wi53SM2vjEmxWJqGjWOVetvNOTioXZgLziy/P4WReHHxOPQyCUdN3D8ZFOgiyBgAIQXDB+40Pzz/wCTMj5DcTYN2Bw/gevHDCDSq7oy0sQJjD+rP8RINwzJOmPHLprKVCpvYkF9us3QomX1R6trA2Cu9JGz6aOiWc7aC3Dekz2oPb3q+brBxHnpGUolVTY+uu2DSHmQG3gwOZb7Qd9uOJ2HD+2ibWHLv+XPJWj3pciPTrRc+AHFvJvxe5nMHzMX7JAdKdCUs5V2kIEHF5YJ61rWbOD4QqahOyV3iMAPBwnbWW+Kw33K4XLIY3G60jm9CgSJbkxNHqBYGyewFHKudcSRw47N5DLUjTqkLQrSc1Pr/0VkMMeSAvLrMdGE30FLSWUzsq91RNq9u86smV0yXdZ4vEEJPfcdUqK/cPiktcEs+oDdnz0wSYL3brg4jSv4EAfsHbEB+nm9Hlw7CVmz9/aZYqwUqPhiwfDlxW0qPgzER0PCw7z2J8OoF53VAQoJd7SQsb0oK4EARcdwpRzTqED8rE7E+iuHxDZSObn31m0+v7AhKwU4A0JYeI8b9yrS1sSBPVSlcGsYheum/TCw2YI1QF9YyOgPeCxfUuzDkryGGiybv1LIBcEmkA/c4rhYlBFNvLa9hq+LCgImIzrr7trAPzxz8SDEkRfEyiFGWRsJWW5 GRXPACUD p99wdZyaYOx6nCK2/jyTrMBFriryQP6WcwpaT6b6L8gMRONuT6/vIVhWZzQv0JRr+FdZ7OSyeBvKb34XORTW+kj6V6NUUeJQVlcAUoQBGRA6sRB/ofGVlwBCMf5p6bGwOOVXjEVPT/UCqmk3kF3ufO2wzRl7q0FCu1NbD4nVAl8wT1ZvY1I51nIC+7kLwS5bQJTmKfwBDXgV24LCM/wqRH2CLV64TFJP7SBAwSzFZhhghDsFO18XiiloADnSAYMSC8EycF/7gpjOYsMw7qIMTny7Gbec76EHT/d2DaGj4jAKjT1f27DxyE/AdNFi860gw93F1YDC+F/Q3BukcBsgsg6vH4KaqlCCHppts1JnKlXVSHKGdzL6UJQ87iw== 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: From: Jeff Xu This patch adds an architecture-independent function, arch_check_pkey_enforce_api(), that checks whether the calling thread has write access to the PKRU for a given range of memory. If the memory range is protected by PKEY_ENFORCE_API, then the thread must have write access to the PKRU in order to make changes to the memory mapping (such as mprotect/munmap). This function is used by the kernel to enforce the PKEY_ENFORCE_API flag. Signed-off-by: Jeff Xu --- arch/powerpc/include/asm/pkeys.h | 8 +++++ arch/x86/include/asm/pkeys.h | 50 ++++++++++++++++++++++++++++++++ include/linux/pkeys.h | 9 ++++++ 3 files changed, 67 insertions(+) diff --git a/arch/powerpc/include/asm/pkeys.h b/arch/powerpc/include/asm/pkeys.h index 943333ac0fee..24c481e5e95b 100644 --- a/arch/powerpc/include/asm/pkeys.h +++ b/arch/powerpc/include/asm/pkeys.h @@ -177,5 +177,13 @@ static inline bool arch_check_pkey_alloc_flags(unsigned long flags) return true; } +static inline int arch_check_pkey_enforce_api(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + /* Allow by default */ + return 0; +} + extern void pkey_mm_init(struct mm_struct *mm); #endif /*_ASM_POWERPC_KEYS_H */ diff --git a/arch/x86/include/asm/pkeys.h b/arch/x86/include/asm/pkeys.h index ecadf04a8251..8b94ffc4ca32 100644 --- a/arch/x86/include/asm/pkeys.h +++ b/arch/x86/include/asm/pkeys.h @@ -161,4 +161,54 @@ static inline bool arch_check_pkey_alloc_flags(unsigned long flags) return true; } + +static inline int __arch_check_vma_pkey_for_write(struct vm_area_struct *vma) +{ + int pkey = vma_pkey(vma); + + if (mm_pkey_enforce_api(vma->vm_mm, pkey)) { + if (!__pkru_allows_write(read_pkru(), pkey)) + return -EACCES; + } + + return 0; +} + +/* + * arch_check_pkey_enforce_api is used by the kernel to enforce + * PKEY_ENFORCE_API flag. + * It checks whether the calling thread has write access to the PKRU + * for a given range of memory. If the memory range is protected by + * PKEY_ENFORCE_API, then the thread must have write access to the + * PKRU in order to make changes to the memory mapping, such as + * mprotect/munmap. + */ +static inline int arch_check_pkey_enforce_api(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + int error; + struct vm_area_struct *vma; + + if (!arch_pkeys_enabled()) + return 0; + + while (true) { + vma = find_vma_intersection(mm, start, end); + if (!vma) + break; + + error = __arch_check_vma_pkey_for_write(vma); + if (error) + return error; + + if (vma->vm_end >= end) + break; + + start = vma->vm_end; + } + + return 0; +} + #endif /*_ASM_X86_PKEYS_H */ diff --git a/include/linux/pkeys.h b/include/linux/pkeys.h index 81a482c3e051..7b00689e1c24 100644 --- a/include/linux/pkeys.h +++ b/include/linux/pkeys.h @@ -53,6 +53,15 @@ static inline bool arch_check_pkey_alloc_flags(unsigned long flags) return false; return true; } + +static inline int arch_check_pkey_enforce_api(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + // Allow by default. + return 0; +} + #endif /* ! CONFIG_ARCH_HAS_PKEYS */ #endif /* _LINUX_PKEYS_H */ From patchwork Mon May 15 13:05:49 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Xu X-Patchwork-Id: 13241396 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 8BFBEC77B75 for ; Mon, 15 May 2023 13:06:12 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 8F2A2900003; Mon, 15 May 2023 09:06:11 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 8A2C2900002; Mon, 15 May 2023 09:06:11 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 76A38900003; Mon, 15 May 2023 09:06:11 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0017.hostedemail.com [216.40.44.17]) by kanga.kvack.org (Postfix) with ESMTP id 63519900002 for ; Mon, 15 May 2023 09:06:11 -0400 (EDT) Received: from smtpin04.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay01.hostedemail.com (Postfix) with ESMTP id A4BBB1C896B for ; Mon, 15 May 2023 13:06:09 +0000 (UTC) X-FDA: 80792512458.04.0FB5AEA Received: from mail-pl1-f182.google.com (mail-pl1-f182.google.com [209.85.214.182]) by imf24.hostedemail.com (Postfix) with ESMTP id 4B0B41800DB for ; Mon, 15 May 2023 13:06:03 +0000 (UTC) Authentication-Results: imf24.hostedemail.com; dkim=pass header.d=chromium.org header.s=google header.b=Rt5yYfm0; spf=pass (imf24.hostedemail.com: domain of jeffxu@chromium.org designates 209.85.214.182 as permitted sender) smtp.mailfrom=jeffxu@chromium.org; dmarc=pass (policy=none) header.from=chromium.org ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1684155964; a=rsa-sha256; cv=none; b=KfqFG3cniAPWKxDoY5yO0S41B8A2ZztauvqxbDV8QUP4Gmdg8FdQZdHZWsw2qrNSVr5Y0X 0RUmJs1MIVkEOha8rfTuJyNVftRq+2eIZqJo9M0m+jDm10kCg0DeCnK/qjdlwykLqa9eYo P5zBPE4gkdfhAuEQPKQ9ITFC6UKxfKE= ARC-Authentication-Results: i=1; imf24.hostedemail.com; dkim=pass header.d=chromium.org header.s=google header.b=Rt5yYfm0; spf=pass (imf24.hostedemail.com: domain of jeffxu@chromium.org designates 209.85.214.182 as permitted sender) smtp.mailfrom=jeffxu@chromium.org; dmarc=pass (policy=none) header.from=chromium.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1684155964; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=+ujRp+fUzXaEUmgqKvUj1r8AuZXVhmdz7uVnxDSzpYA=; b=IbS2sCrQdgEtNU8AXmBjjk+9gTocBqliPDVlpC2sCKwnEsGJ6a2tJHxL2nsqP1MVYtA/4F fpAn2l0hggAg6z34W75pSNrxdx/t5u49smW2+FL76gZQMHDtLu+pbRHAOZ2NZ1+wG0flkK 7CizKnLNm1Plp0Z/lLedFsgFprn1zrM= Received: by mail-pl1-f182.google.com with SMTP id d9443c01a7336-1addac3de73so29114385ad.1 for ; Mon, 15 May 2023 06:06:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1684155963; x=1686747963; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=+ujRp+fUzXaEUmgqKvUj1r8AuZXVhmdz7uVnxDSzpYA=; b=Rt5yYfm0CK8EUUQDrYdxuqMd3n+YNkZzNsjoe7Sh2TMU94iFWNQ9XbZV1szPVs7im8 +tqDWyCl21fUMShhLNa9cxw1wcdjPBpuZrvT2b9Xhnfk8Tltierjd6QqsJqZl2irCBNZ 75n9PT1i0yFsyihOnR4+Se6E/rdRMjFhTYgCA= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684155963; x=1686747963; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=+ujRp+fUzXaEUmgqKvUj1r8AuZXVhmdz7uVnxDSzpYA=; b=BskcpKH+sXesmgCpuN0HX+yHisX4w+i4pXw7yF9X1Ulnwn/iRAx6GANEv7+G10v7Z0 kjM4KSku2ViXuCZTtBFowh3EHT/FaXX1yCHoRkGw4C/3AXWD8BWJYKKHYE5ctcmReZNO sTfQ7bo7ATUz76KXr2hWDItogRRCT+11/QrBKnrsYCWEqsBKXdH7e7RTSak/N1p/5rlr wQRexno9Unpa/Ds5nUwNPO+4s9ImCDFVx6X+XCIKHi5BdXx/kxUHR67u67ZXUly91TUh 7YVo3Mc2Tez33RNNpv9tttNrr3jNj58d9uwu1rfkHrcp+FH5KUigOiT4VAq0wBCoIEmS 5ATw== X-Gm-Message-State: AC+VfDxDrvEZydqZoQXVZcz68UfklGbiVUDId8PwhhtMxpXaXQoZG5VB TrrRz9HX+6Yf/O+6qhcmTZlycA== X-Google-Smtp-Source: ACHHUZ6kGDKbByWmlumIW033viVHhT0CSCqBtVBlJ4yzye+I6JDMWWkia59K77zKHw/c/xUVQ4KIpw== X-Received: by 2002:a17:902:ce84:b0:1ac:a030:c30a with SMTP id f4-20020a170902ce8400b001aca030c30amr28883712plg.19.1684155962938; Mon, 15 May 2023 06:06:02 -0700 (PDT) Received: from localhost (183.43.230.35.bc.googleusercontent.com. [35.230.43.183]) by smtp.gmail.com with UTF8SMTPSA id i2-20020a170902c94200b001a988a71617sm13474160pla.192.2023.05.15.06.06.02 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 15 May 2023 06:06:02 -0700 (PDT) From: jeffxu@chromium.org To: dave.hansen@intel.com, luto@kernel.org, jorgelo@chromium.org, keescook@chromium.org, groeck@chromium.org, jannh@google.com, sroettger@google.com Cc: akpm@linux-foundation.org, jeffxu@google.com, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org, linux-hardening@vger.kernel.org Subject: [PATCH 3/6] PKEY: Apply PKEY_ENFORCE_API to mprotect Date: Mon, 15 May 2023 13:05:49 +0000 Message-ID: <20230515130553.2311248-4-jeffxu@chromium.org> X-Mailer: git-send-email 2.40.1.606.ga4b1b128d6-goog In-Reply-To: <20230515130553.2311248-1-jeffxu@chromium.org> References: <20230515130553.2311248-1-jeffxu@chromium.org> MIME-Version: 1.0 X-Rspam-User: X-Stat-Signature: dw3wig9ow5kkrssb7bgb9ey1spoaccm3 X-Rspamd-Server: rspam08 X-Rspamd-Queue-Id: 4B0B41800DB X-HE-Tag: 1684155963-956624 X-HE-Meta: U2FsdGVkX19y13SbLDKWYRUZOyv4bDmENvIxkg+Ay5OEUQ3x4a3f7Kt8QX/Yrcq0dq3pgPaXbG7Mu57xnQkNJISMa8eIiqz51Jg3/12T/HJOMAfNZwNz21B6CYnPBLE/udKfLCM4ZsRcjVIoInGDWhbtzh9hRtPltRKr6HdbVv7AvQVdub4jhJUxyoIDRRYQcPJtiFWhqlkVGP63pJ/6GH8SVVKxATjIavyzNsb/8Zr3Ukva+K7SbaQTwY18HUxrzDytgFeZCkb2YyHkwNaEPOLO6NbKFbXlmi1UXYTrwLMmLg+S3DXBUB4iDdLgdmkqOeFj/P421SrFZGntYTWFfAsJ/CD35108Ff+u2IfXrOYRYFDC7UD27IpZT+zfdt85FyL1ExlKEqCRLa2TuldCy4Ly5wKRcZIFMq4Lgi7H40dx5ZGbsBOit+oHD+5jxKJV9lnkwU9e9+y5si1CCpm20hVFdlDbo9KmfmT/iuQ3/3ZpxKds9m+l22pGWQRDK+Gjld3aFnWHbr+tW96HNs9s9xUlhJe+nmCkUgzP5wxyej/vAPt6YDTyB7FanZDKSZI2r/gumQsO8i+GpYQizNZxrcFHNxvfHPXhqJK8xJvBOsJ7r+oLVCURNM8mlMivRXKwIJT+s9em0/BxHnfpInkRB4DHqAAINsMjpFN+A3QekCCR8XQkoYT0SyuJ50AfAqVokdUVUKL/P25qsv7YGkpRsbQO3LHN5tWgdNuX2aM14rrZdqAVwkBxL8IAQ5fHleqX39tSqSbRcF9U+AQLYCLoyGWjO2ldmYLnkBl8c0JJUa7Q9qPs/HGVyblLbX8lathDQVtC/JkWPTCPhAL5PtKt5/gauXZYzFGnTNik1jVf73k1qRChOlFguOvoTFUPJbL0cXMTq2HTrOfG4styA6yx+VFj+Xm1sgfzFpz65KrvHyJg0c5RwL97l/BVD693kCAjVmiGCUubgA7coLhGZTH U53JOdXb m3w27FyRsmjT2/Lqmkv3A0RvseC8rwXM7RIS7LQfhX6fZ3C6W5PtmXjhhpNJi3l6LI+Gd5m4N01RMggEL9er2TAPTK2MFZQO+QNpi71P7bDzr95fSPYLjq1YkSMx7TKLH8yehZt8G+Okvpmu17Ouf/GuSYQdnygbzOSrOWZcw8IJn9bXc1XkuhAXccLptAoR6wkIgplDqjUDkerwryLTPqBW39xruND4/yQjotxEgQCtqj7/gpeOg5VAaJSNYQ8RqX+VlvukD4HxHq2RRCaMbHU3rMK3X8+Mip5tIiu/P7f6s61e1ChVtYsFxrEUAc2r3e14CbpOkUlFRuhoqeNCS1TwCw4C/U+iLt+M4l5EFggiRsaX7WJirmv4nmIeiER1vEtM6rfE/rLSfQ1+jlAU4qyGsx7oTccuIeH94 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: From: Jeff Xu This patch enables PKEY_ENFORCE_API for the mprotect and mprotect_pkey syscalls. Signed-off-by: Jeff Xu --- mm/mprotect.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/mm/mprotect.c b/mm/mprotect.c index 8a68fdca8487..1378be50567d 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -727,9 +727,13 @@ mprotect_fixup(struct vma_iterator *vmi, struct mmu_gather *tlb, /* * pkey==-1 when doing a legacy mprotect() + * syscall==true if this is called by syscall from userspace. + * Note: this is always true for now, added as a reminder in case that + * do_mprotect_pkey is called directly by kernel in the future. + * Also it is consistent with __do_munmap(). */ static int do_mprotect_pkey(unsigned long start, size_t len, - unsigned long prot, int pkey) + unsigned long prot, int pkey, bool syscall) { unsigned long nstart, end, tmp, reqprot; struct vm_area_struct *vma, *prev; @@ -794,6 +798,21 @@ static int do_mprotect_pkey(unsigned long start, size_t len, } } + /* + * When called by syscall from userspace, check if the calling + * thread has the PKEY permission to modify the memory mapping. + */ + if (syscall && + arch_check_pkey_enforce_api(current->mm, start, end) < 0) { + char comm[TASK_COMM_LEN]; + + pr_warn_ratelimited( + "munmap was denied on PKEY_ENFORCE_API memory, pid=%d '%s'\n", + task_pid_nr(current), get_task_comm(comm, current)); + error = -EACCES; + goto out; + } + prev = vma_prev(&vmi); if (start > vma->vm_start) prev = vma; @@ -878,7 +897,7 @@ static int do_mprotect_pkey(unsigned long start, size_t len, SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len, unsigned long, prot) { - return do_mprotect_pkey(start, len, prot, -1); + return do_mprotect_pkey(start, len, prot, -1, true); } #ifdef CONFIG_ARCH_HAS_PKEYS @@ -886,7 +905,7 @@ SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len, SYSCALL_DEFINE4(pkey_mprotect, unsigned long, start, size_t, len, unsigned long, prot, int, pkey) { - return do_mprotect_pkey(start, len, prot, pkey); + return do_mprotect_pkey(start, len, prot, pkey, true); } SYSCALL_DEFINE2(pkey_alloc, unsigned long, flags, unsigned long, init_val) From patchwork Mon May 15 13:05:50 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Xu X-Patchwork-Id: 13241398 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 F2529C7EE23 for ; Mon, 15 May 2023 13:06:58 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 525A0900005; Mon, 15 May 2023 09:06:58 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 4D355900002; Mon, 15 May 2023 09:06:58 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 2D7F2900005; Mon, 15 May 2023 09:06:58 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0014.hostedemail.com [216.40.44.14]) by kanga.kvack.org (Postfix) with ESMTP id 14C90900002 for ; Mon, 15 May 2023 09:06:58 -0400 (EDT) Received: from smtpin14.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay08.hostedemail.com (Postfix) with ESMTP id 77AEC1412C3 for ; Mon, 15 May 2023 13:06:57 +0000 (UTC) X-FDA: 80792514474.14.AA9FB4E Received: from mail-pf1-f182.google.com (mail-pf1-f182.google.com [209.85.210.182]) by imf04.hostedemail.com (Postfix) with ESMTP id D5121400AB for ; Mon, 15 May 2023 13:06:05 +0000 (UTC) Authentication-Results: imf04.hostedemail.com; dkim=pass header.d=chromium.org header.s=google header.b=aGoNmDGs; spf=pass (imf04.hostedemail.com: domain of jeffxu@chromium.org designates 209.85.210.182 as permitted sender) smtp.mailfrom=jeffxu@chromium.org; dmarc=pass (policy=none) header.from=chromium.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1684155966; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=qzO3EawE44DmDL2RDFGxHbI+J47AsuGzE5x/fc5YRSs=; b=hVHfxt1yoQzU+dJY9RitIzzv/0eR+YDYifm3o54mb5PSPZyGJVFSEB8bOJJcCx20nGUX34 SBuUCjBOiYHWFhll7LCKjkSGtS8LusozslWPmMgMpWI8rtHtsxTLgLG2tfqzcKdhiG5DiZ MCBd9WJy6Te6v80K/RwN6edoc/nmKv8= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1684155966; a=rsa-sha256; cv=none; b=iXNfiQ1E0bSV14JxGDK+e3GKxlv+A5fXd6ZzpX0UDj+gVo+ACmlEfgtgOPNXlPXcoSDT72 83Z3k6p40z+9f3woG2HOyWZ2QhSzOxT1xPb9ltI9EneeG0uFkcKcq1GQkuVyeIHtnpuS85 K8EBKfQ4ZO+JqPQ0x/prOmDR4QVj9N0= ARC-Authentication-Results: i=1; imf04.hostedemail.com; dkim=pass header.d=chromium.org header.s=google header.b=aGoNmDGs; spf=pass (imf04.hostedemail.com: domain of jeffxu@chromium.org designates 209.85.210.182 as permitted sender) smtp.mailfrom=jeffxu@chromium.org; dmarc=pass (policy=none) header.from=chromium.org Received: by mail-pf1-f182.google.com with SMTP id d2e1a72fcca58-643aad3bc41so12163797b3a.0 for ; Mon, 15 May 2023 06:06:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1684155964; x=1686747964; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=qzO3EawE44DmDL2RDFGxHbI+J47AsuGzE5x/fc5YRSs=; b=aGoNmDGsHMZQ2NOQ2cue8xdiDDbXfg574ntCOr0fKPPQnkqDRL5arkUu7ldufymOVe Kl+GAd6kpscPyyPa/VvDhi1rUnMulpN6nJ9nZiuxlqk2PqDpSvyS5zAzBXhi3NPW7QWr NxYWJh5ESLSGl12CHkobqGMOZZiaCmA0HqP1M= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684155964; x=1686747964; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=qzO3EawE44DmDL2RDFGxHbI+J47AsuGzE5x/fc5YRSs=; b=Ma4j775atP+MM2m+FMlV/0FJIKjCHCuWEvBPZOJFAhykqE+yB10ONTm90jlj8wPsp/ 1cjkbMGqboA7ALL186y26eyrI5bW6XidDN+vVglnBsjDbMoLJKOs973FrE3nlUpDeCeO 3WCR9vaiUwlZejmandhw/KgvXDHeFESYE4RYvZ2EDuQVhG1dLgaSFImQviC7iX06Q2us L+ffUNBkXize0nAcXjUxC5D2qPsfePwgNz6cgIG4B9IQxszGWu7MpVSNzyCB3+yAsyFP IzkO722bRhsuSkM5y8Thn7Upk8trnGu0e3lGOo3glWoUOrWCDIr1NE0S6QvzQ0hpQjBA D2MA== X-Gm-Message-State: AC+VfDzrwXedc/LDDBcuUYsj1CBCP9S47t8v3zZoDkzZNSAEuAAXmXii 48iD17QCIxDLfVkM2OqUTidUuQ== X-Google-Smtp-Source: ACHHUZ5oeSI5OJJe1UmE9B9/a6W7y2Q2NX78qVUBaVchfp8CJy5bY/W6p0kp8AW04oe76HXZRK41AQ== X-Received: by 2002:a05:6a00:1a8e:b0:64a:9090:5147 with SMTP id e14-20020a056a001a8e00b0064a90905147mr16698628pfv.10.1684155964232; Mon, 15 May 2023 06:06:04 -0700 (PDT) Received: from localhost (183.43.230.35.bc.googleusercontent.com. [35.230.43.183]) by smtp.gmail.com with UTF8SMTPSA id e4-20020aa78244000000b0064928cb5f03sm2475090pfn.69.2023.05.15.06.06.03 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 15 May 2023 06:06:03 -0700 (PDT) From: jeffxu@chromium.org To: dave.hansen@intel.com, luto@kernel.org, jorgelo@chromium.org, keescook@chromium.org, groeck@chromium.org, jannh@google.com, sroettger@google.com Cc: akpm@linux-foundation.org, jeffxu@google.com, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org, linux-hardening@vger.kernel.org Subject: [PATCH 4/6] PKEY:selftest pkey_enforce_api for mprotect Date: Mon, 15 May 2023 13:05:50 +0000 Message-ID: <20230515130553.2311248-5-jeffxu@chromium.org> X-Mailer: git-send-email 2.40.1.606.ga4b1b128d6-goog In-Reply-To: <20230515130553.2311248-1-jeffxu@chromium.org> References: <20230515130553.2311248-1-jeffxu@chromium.org> MIME-Version: 1.0 X-Stat-Signature: ngb4wnxfqufegs6xmerj7etwfok8uexm X-Rspamd-Server: rspam04 X-Rspamd-Queue-Id: D5121400AB X-Rspam-User: X-HE-Tag: 1684155965-616414 X-HE-Meta: U2FsdGVkX18QxzzltQuA6/S2coF/ixbjUaEMCu0TigBlDvWRbRHlbKvYb9BtcJQ/EJ1C/e/mBL9A7UjPBAMYK3JEx4YY6V0oEKkQBrUPcohvNhpw98CJbDSvrZmhV9w1hcJLOGnsmir0iNMtQ6ki2E4ODotmOqi5eqHWRaGpTHyaUxiwi6HtTAz99BB+YBS79egE+uf+iN0MaArIbDSXr4IDBv3bZDLxYmjWlA/hKJa+vPdiFG4tMY/uz97ciAFnI2IIagORCd6u7SEGldSOPRSw1vQPk7oo9YUgIbtYL4gGgUFiwauXEC73sr0Gum21iWHMjpz3hCH6Pwktie2hvCINuODozJpUI8ZTRmJNmm9va2Gt9CmaGAqEw7rFA5wzgZnmlIf+BwGz3emAddIK7O1Ituv91PySLqFpEJHRS84jrzhFHQmAChRRaDmOzLBjYPcfQ8hPH/wSpXGrnIRRN50pWtTc5MqNoGojS2w2ziipvUXHJ+DYaGxjcbr/ZMUJNmJ2XOKZ202hxVqXKY7IuSgnc5zsNlROdpFTe0wuJ8EUmwpbfh1YyJ+AxM5loQ2SZUpYkqylSlFx46gMwhHa+7crVkpP+SE2girZkTrXfp87eH3wiPH0kahz7b1Hzz1xn7m7Jn1V6sO1B80BO9rPwuNLVkTkdG1/xAdBfWau+uIO4GNj4X1be0To2ZQ+K8LtlHksSH9M3h8+1gWKcjrWr790Nwf52J4VwaXmPygiBMr8pXpWOR71YHH/cNtLj8PSLou9KiZODzSPxIpOw3qosEq85cNq3ySWluFvmn6nTipYEws1D21M1fAv7rGGBsMaxW2g1kJhEyBigbG1JKBv+FP6PTmbKEMj/1W6Cl1eF3OTiAHPoJ6hCdOcvMH18FCn00eTts8xb8BSmfLi9X876AcYEkvUP/ebJl0ci0cmCF0Z+t+UtghoPA7GjuZFIf6yO3K5fXjulKKMEhYbKDs 9eI0PsCm N+i0dLxtHfT/cGlbVoOtgJafepWR3FVStpCTnfiytgoQKyVG6cyP+7UFr+quXGLFWVq5Q1ndhlriEygHVGKTAjD0AWErPlSd7gESvDss+82aRGBqfWJERn8ppzPuFosPFa5uuMK/HhSGYEzDvyVzj9VgZiWPPkdm/3neBnpC5kxKXwje6/iuzbOKVcFjcCCHRzO1Ibc2rwx9Jc8BOkeiTRI860yLXxfzY12RYc4zxnlHHD1dCMIEG4FtckGNZSBV6jt9/UU1gDot9G83vMFsqgXJI+jGgrp0sEoKpKXAff/eYhv1+0GIfzMJasmE62N2MlfqOz3Ltq88lROcH1eAuk7/NwNqEiBEPt7Ccnw1czYlWE/Ig/tPk2TzKIA== 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: From: Jeff Xu Add selftest for pkey_enforce_api for mprotect. Signed-off-by: Jeff Xu --- tools/testing/selftests/mm/Makefile | 1 + tools/testing/selftests/mm/pkey_enforce_api.c | 875 ++++++++++++++++++ 2 files changed, 876 insertions(+) create mode 100644 tools/testing/selftests/mm/pkey_enforce_api.c diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/mm/Makefile index 23af4633f0f4..93437a394128 100644 --- a/tools/testing/selftests/mm/Makefile +++ b/tools/testing/selftests/mm/Makefile @@ -71,6 +71,7 @@ CAN_BUILD_X86_64 := $(shell ./../x86/check_cc.sh "$(CC)" ../x86/trivial_64bit_pr CAN_BUILD_WITH_NOPIE := $(shell ./../x86/check_cc.sh "$(CC)" ../x86/trivial_program.c -no-pie) VMTARGETS := protection_keys +VMTARGETS += pkey_enforce_api BINARIES_32 := $(VMTARGETS:%=%_32) BINARIES_64 := $(VMTARGETS:%=%_64) diff --git a/tools/testing/selftests/mm/pkey_enforce_api.c b/tools/testing/selftests/mm/pkey_enforce_api.c new file mode 100644 index 000000000000..23663c89bc9c --- /dev/null +++ b/tools/testing/selftests/mm/pkey_enforce_api.c @@ -0,0 +1,875 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Tests pkey_enforce_api + * + * Compile like this: + * gcc -mxsave -o pkey_enforce_api -O2 -g -std=gnu99 -pthread -Wall pkey_enforce_api.c \ + * -lrt -ldl -lm + * gcc -mxsave -m32 -o pkey_enforce_api_32 -O2 -g -std=gnu99 -pthread -Wall pkey_enforce_api.c \ + * -lrt -ldl -lm + */ +#define _GNU_SOURCE +#define __SANE_USERSPACE_TYPES__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../kselftest.h" +#include + +#if defined(__i386__) || defined(__x86_64__) /* arch */ + +#define dprintf0(args...) +#define dprintf1(args...) +#define dprintf2(args...) +#define dprintf3(args...) +#define dprintf4(args...) + +#ifndef u16 +#define u16 __u16 +#endif + +#ifndef u32 +#define u32 __u32 +#endif + +#ifndef u64 +#define u64 __u64 +#endif + +#ifndef PTR_ERR_ENOTSUP +#define PTR_ERR_ENOTSUP ((void *)-ENOTSUP) +#endif + +int read_ptr(int *ptr) +{ + return *ptr; +} + +void expected_pkey_fault(int pkey) +{ +} + +#include "pkey-x86.h" + +#ifndef PKEY_ENFORCE_API +#define PKEY_ENFORCE_API 1 +#endif + +#define PKEY_MASK (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE) + +#define LOG_TEST_ENTER(x) \ + { \ + printf("%s, enforce=%d\n", __func__, x); \ + } +static inline u64 set_pkey_bits(u64 reg, int pkey, u64 flags) +{ + u32 shift = pkey_bit_position(pkey); + /* mask out bits from pkey in old value */ + reg &= ~((u64)PKEY_MASK << shift); + /* OR in new bits for pkey */ + reg |= (flags & PKEY_MASK) << shift; + return reg; +} + +static inline u64 get_pkey_bits(u64 reg, int pkey) +{ + u32 shift = pkey_bit_position(pkey); + /* + * shift down the relevant bits to the lowest two, then + * mask off all the other higher bits + */ + return ((reg >> shift) & PKEY_MASK); +} + +static u32 get_pkey(int pkey) +{ + return (u32)get_pkey_bits(__read_pkey_reg(), pkey); +} + +static void set_pkey(int pkey, unsigned long pkey_value) +{ + u32 mask = (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE); + u64 new_pkey_reg; + + assert(!(pkey_value & ~mask)); + new_pkey_reg = set_pkey_bits(__read_pkey_reg(), pkey, pkey_value); + __write_pkey_reg(new_pkey_reg); +} + +void pkey_disable_set(int pkey, int value) +{ + int pkey_new; + + assert(value & (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE)); + + pkey_new = get_pkey(pkey); + pkey_new |= value; + set_pkey(pkey, pkey_new); +} + +void pkey_disable_clear(int pkey, int value) +{ + int pkey_new; + + assert(value & (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE)); + + pkey_new = get_pkey(pkey); + pkey_new &= ~value; + + set_pkey(pkey, pkey_new); +} + +void pkey_write_allow(int pkey) +{ + pkey_disable_clear(pkey, PKEY_DISABLE_WRITE); +} +void pkey_write_deny(int pkey) +{ + pkey_disable_set(pkey, PKEY_DISABLE_WRITE); +} +void pkey_access_allow(int pkey) +{ + pkey_disable_clear(pkey, PKEY_DISABLE_ACCESS); +} +void pkey_access_deny(int pkey) +{ + pkey_disable_set(pkey, PKEY_DISABLE_ACCESS); +} + +int sys_mprotect(void *ptr, size_t size, unsigned long prot) +{ + int sret; + + errno = 0; + sret = syscall(SYS_mprotect, ptr, size, prot); + return sret; +} + +int sys_mprotect_pkey(void *ptr, size_t size, unsigned long orig_prot, + unsigned long pkey) +{ + int sret; + + errno = 0; + sret = syscall(SYS_mprotect_key, ptr, size, orig_prot, pkey); + return sret; +} + +int sys_pkey_alloc(unsigned long flags, unsigned long init_val) +{ + int ret = syscall(SYS_pkey_alloc, flags, init_val); + return ret; +} + +int sys_pkey_free(unsigned long pkey) +{ + int ret = syscall(SYS_pkey_free, pkey); + return ret; +} + +bool can_create_pkey(void) +{ + int pkey; + + pkey = sys_pkey_alloc(0, 0); + if (pkey <= 0) + return false; + + sys_pkey_free(pkey); + return true; +} + +static inline int is_pkeys_supported(void) +{ + /* check if the cpu supports pkeys */ + if (!cpu_has_pkeys() || !can_create_pkey()) + return 0; + return 1; +} + +int pkey_alloc_with_check(bool enforce) +{ + int pkey; + + if (enforce) + pkey = sys_pkey_alloc(PKEY_ENFORCE_API, 0); + else + pkey = sys_pkey_alloc(0, 0); + + assert(pkey > 0); + return pkey; +} + +void *addr1 = (void *)0x5000000; +void *addr2 = (void *)0x5001000; +void *addr3 = (void *)0x5002000; +void *addr4 = (void *)0x5003000; + +void setup_single_address_with_pkey(bool enforce, int size, int *pkeyOut, + void **ptrOut) +{ + int pkey; + void *ptr; + int ret; + + pkey = pkey_alloc_with_check(enforce); + + ptr = mmap(NULL, size, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + assert(ptr != (void *)-1); + + // assign pkey to the memory. + ret = sys_mprotect_pkey((void *)ptr, size, PROT_READ, pkey); + assert(!ret); + + *pkeyOut = pkey; + *ptrOut = ptr; +} + +void setup_single_fixed_address_with_pkey(bool enforce, int size, int *pkeyOut, + void **ptrOut) +{ + int pkey; + void *ptr; + int ret; + + pkey = pkey_alloc_with_check(enforce); + + ptr = mmap(addr1, size, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + assert(ptr == (void *)addr1); + + // assign pkey to the memory. + ret = sys_mprotect_pkey((void *)ptr, size, PROT_READ, pkey); + assert(!ret); + + *pkeyOut = pkey; + *ptrOut = ptr; +} + +void clean_single_address_with_pkey(int pkey, void *ptr, int size) +{ + int ret; + + ret = munmap(ptr, size); + assert(!ret); + + ret = sys_pkey_free(pkey); + assert(ret == 0); +} + +void setup_two_continues_fixed_address_with_pkey(bool enforce, int size, + int *pkeyOut, void **ptrOut, + void **ptr2Out) +{ + void *ptr; + void *ptr2; + int pkey; + int ret; + + pkey = pkey_alloc_with_check(enforce); + + ptr = mmap(addr1, size, PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); + assert(ptr == addr1); + + ptr2 = mmap(addr2, size, PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); + assert(ptr2 == addr2); + + // assign pkey to both addresses in the same call (merged) + ret = sys_mprotect_pkey(ptr, size * 2, + PROT_READ | PROT_WRITE | PROT_EXEC, pkey); + assert(!ret); + *pkeyOut = pkey; + *ptrOut = ptr; + *ptr2Out = ptr2; +} + +void clean_two_address_with_pkey(int size, int pkey, void *ptr, void *ptr2) +{ + int ret; + + ret = munmap(ptr, size); + assert(!ret); + + ret = munmap(ptr2, size); + assert(!ret); + + ret = sys_pkey_free(pkey); + assert(ret == 0); +} + +// pkey_alloc with flags. +void test_pkey_alloc(bool enforce) +{ + int ret; + + LOG_TEST_ENTER(enforce); + + ret = sys_pkey_alloc(0, 0); + assert(ret > 0); + ret = sys_pkey_free(ret); + assert(ret == 0); + + if (enforce) { + ret = sys_pkey_alloc(PKEY_ENFORCE_API, 0); + assert(ret > 0); + ret = sys_pkey_free(ret); + assert(ret == 0); + + // invalid flag. + ret = sys_pkey_alloc(0x4, 0); + assert(ret != 0); + } +} + +// mmap one address. +// assign pkey on the address. +// mprotect is denied when no-writeable PKRU in enforce mode. +void test_mprotect_single_address(bool enforce) +{ + int pkey; + int ret; + void *ptr; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_single_fixed_address_with_pkey(enforce, size, &pkey, &ptr); + + // disable write access. + pkey_write_deny(pkey); + + ret = sys_mprotect_pkey(ptr, size, PROT_READ | PROT_WRITE, pkey); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + ret = sys_mprotect(ptr, size, PROT_READ | PROT_WRITE); + if (enforce) + assert(ret < 0); + else + assert(ret == 0); + + pkey_write_allow(pkey); + + ret = sys_mprotect_pkey(ptr, size, PROT_READ, pkey); + assert(!ret); + + ret = sys_mprotect(ptr, size, PROT_READ); + assert(ret == 0); + + clean_single_address_with_pkey(pkey, ptr, size); +} + +// mmap two address (continuous two pages). +// assign PKEY to them with one mprotect_pkey call (merged address). +// mprotect is denied when non-writeable PKRU in enforce mode. +void test_mprotect_two_address_merge(bool enforce) +{ + int pkey; + int ret; + void *ptr; + void *ptr2; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_two_continues_fixed_address_with_pkey(enforce, size, &pkey, &ptr, + &ptr2); + + // disable write. + pkey_write_deny(pkey); + + // modify the protection on both addresses (merged). + ret = sys_mprotect(ptr, size * 2, PROT_READ | PROT_WRITE | PROT_EXEC); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + ret = sys_mprotect_pkey(ptr, size * 2, + PROT_READ | PROT_WRITE | PROT_EXEC, pkey); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + pkey_write_allow(pkey); + + // modify the protection on both addresses (merged). + ret = sys_mprotect(ptr, size * 2, PROT_READ | PROT_WRITE | PROT_EXEC); + assert(!ret); + + ret = sys_mprotect_pkey(ptr, size * 2, + PROT_READ | PROT_WRITE | PROT_EXEC, pkey); + assert(!ret); + + clean_two_address_with_pkey(size, pkey, ptr, ptr2); +} + +void setup_two_continues_fixed_address_protect_second_with_pkey( + bool enforce, int size, int *pkeyOut, void **ptrOut, void **ptr2Out) +{ + void *ptr; + void *ptr2; + int pkey; + int ret; + + LOG_TEST_ENTER(enforce); + + pkey = pkey_alloc_with_check(enforce); + + // mmap two addresses (continuous two pages). + ptr = mmap(addr1, size, PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); + assert(ptr == addr1); + + ptr2 = mmap(addr2, size, PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); + assert(ptr2 == addr2); + + // assign pkey to the second page. + ret = sys_mprotect_pkey(addr2, size, PROT_READ | PROT_WRITE | PROT_EXEC, + pkey); + assert(!ret); + + *pkeyOut = pkey; + *ptrOut = ptr; + *ptr2Out = ptr2; +} + +// mmap two address (continuous two pages). +// assign PKEY to the second address. +// mprotect on the second address is denied properly. +// mprotect on both addresses (merged) is denied properly. +void test_mprotect_two_address_deny_second(bool enforce) +{ + int pkey; + int ret; + void *ptr; + void *ptr2; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_two_continues_fixed_address_protect_second_with_pkey( + enforce, size, &pkey, &ptr, &ptr2); + + // disable write through pkey. + pkey_write_deny(pkey); + + // modify the first addr is allowed. + ret = sys_mprotect(ptr, size, PROT_READ | PROT_WRITE | PROT_EXEC); + assert(!ret); + + // modify the second mmap is protected by pkey. + ret = sys_mprotect(ptr2, size, PROT_READ | PROT_WRITE | PROT_EXEC); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + // mprotect both addresses (merged). + ret = sys_mprotect_pkey(ptr, size * 2, + PROT_READ | PROT_WRITE | PROT_EXEC, pkey); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + ret = sys_mprotect(ptr, size * 2, PROT_READ | PROT_WRITE | PROT_EXEC); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + pkey_write_allow(pkey); + + ret = sys_mprotect_pkey(ptr, size * 2, PROT_READ, pkey); + assert(!ret); + + ret = sys_mprotect(ptr, size * 2, PROT_READ); + assert(!ret); + + clean_two_address_with_pkey(size, pkey, ptr, ptr2); +} + +void setup_4pages_fixed_protect_second_page(bool enforce, int size, + int *pkeyOut, void **ptrOut, + void **ptr2Out, void **ptr3Out) +{ + int pkey; + int ret; + void *ptr; + + pkey = pkey_alloc_with_check(enforce); + + // allocate 4 pages. + ptr = mmap(addr1, size * 4, PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); + assert(ptr == addr1); + + // assign pkey to the second address. + ret = sys_mprotect_pkey(addr2, size, PROT_READ | PROT_WRITE | PROT_EXEC, + pkey); + assert(!ret); + + *pkeyOut = pkey; + *ptrOut = ptr; + *ptr2Out = addr2; + *ptr3Out = addr3; +} + +// mmap one address with 4 pages. +// assign PKEY to the second page only. +// mprotect on the first page is allowed. +// mprotect on the second page is protected in enforce mode. +// mprotect on memory range that includes the second pages is protected. +void test_mprotect_vma_middle_addr(bool enforce) +{ + int pkey; + int ret; + void *ptr, *ptr2, *ptr3; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_4pages_fixed_protect_second_page(enforce, size, &pkey, &ptr, + &ptr2, &ptr3); + + // disable write through pkey. + pkey_write_deny(pkey); + + // modify to the first page is allowed. + ret = sys_mprotect(ptr, size, PROT_READ | PROT_WRITE | PROT_EXEC); + assert(!ret); + + // modify to the third page is allowed. + ret = sys_mprotect(ptr3, size, PROT_READ | PROT_WRITE | PROT_EXEC); + assert(!ret); + + // modify to the second page is protected by pkey. + ret = sys_mprotect(ptr2, size, PROT_READ | PROT_WRITE | PROT_EXEC); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + // modify to memory range that includes the second page is protected. + ret = sys_mprotect_pkey(ptr, size * 4, + PROT_READ | PROT_WRITE | PROT_EXEC, pkey); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + ret = sys_mprotect(ptr, size * 4, PROT_READ | PROT_WRITE | PROT_EXEC); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + pkey_write_allow(pkey); + + ret = sys_mprotect(addr2, size, PROT_READ | PROT_WRITE | PROT_EXEC); + assert(!ret); + + ret = sys_mprotect_pkey(ptr, size * 4, + PROT_READ | PROT_WRITE | PROT_EXEC, pkey); + assert(!ret); + + clean_single_address_with_pkey(pkey, ptr, size * 4); +} + +// mmap one address with 4 pages. +// assign PKEY to the second page only. +// mprotect on the second page, but size is unaligned. +void test_mprotect_unaligned(bool enforce) +{ + int pkey; + int ret; + void *ptr, *ptr2, *ptr3; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_4pages_fixed_protect_second_page(enforce, size, &pkey, &ptr, + &ptr2, &ptr3); + + // disable write through pkey. + pkey_write_deny(pkey); + + // modify to the first page is allowed. + ret = sys_mprotect(ptr, size, PROT_READ | PROT_WRITE | PROT_EXEC); + assert(!ret); + + // modify to the second page is protected by pkey. + ret = sys_mprotect(ptr2, size - 1, PROT_READ | PROT_WRITE | PROT_EXEC); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + pkey_write_allow(pkey); + + ret = sys_mprotect(addr2, size - 1, PROT_READ | PROT_WRITE | PROT_EXEC); + assert(!ret); + + clean_single_address_with_pkey(pkey, ptr, size * 4); +} + +// mmap one address with 4 pages. +// assign PKEY to the second page only. +// mprotect on the second page, but size is unaligned. +void test_mprotect_unaligned2(bool enforce) +{ + int pkey; + int ret; + void *ptr, *ptr2, *ptr3; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_4pages_fixed_protect_second_page(enforce, size, &pkey, &ptr, + &ptr2, &ptr3); + + // disable write through pkey. + pkey_write_deny(pkey); + + // modify to the first page is allowed. + ret = sys_mprotect(ptr, size, PROT_READ | PROT_WRITE | PROT_EXEC); + assert(!ret); + + // modify to the second page is protected by pkey. + ret = sys_mprotect(ptr2, size + 1, PROT_READ | PROT_WRITE | PROT_EXEC); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + pkey_write_allow(pkey); + + ret = sys_mprotect(addr2, size + 1, PROT_READ | PROT_WRITE | PROT_EXEC); + assert(!ret); + + clean_single_address_with_pkey(pkey, ptr, size * 4); +} + +void setup_address_with_gap_two_pkeys(bool enforce, int size, int *pkeyOut, + int *pkey2Out, void **ptrOut, + void **ptr2Out) +{ + int pkey, pkey2; + void *ptr, *ptr2; + int ret; + + pkey = pkey_alloc_with_check(enforce); + pkey2 = pkey_alloc_with_check(enforce); + + ptr = mmap(addr1, size, PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); + assert(ptr == (void *)addr1); + + ptr2 = mmap(addr3, size, PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); + assert(ptr2 == (void *)addr3); + + // assign pkey to the memory. + ret = sys_mprotect_pkey((void *)ptr, size, PROT_READ, pkey); + assert(!ret); + + // assign pkey to the memory. + ret = sys_mprotect_pkey((void *)ptr2, size, PROT_READ, pkey2); + assert(!ret); + + *pkeyOut = pkey; + *ptrOut = ptr; + + *pkey2Out = pkey2; + *ptr2Out = ptr2; +} + +void clean_address_with_pag_two_pkeys(int pkey, void *ptr, int pkey2, + void *ptr2, int size) +{ + int ret; + + ret = munmap(ptr, size); + assert(!ret); + + ret = sys_pkey_free(pkey); + assert(ret == 0); + + ret = munmap(ptr2, size); + assert(!ret); + + ret = sys_pkey_free(pkey2); + assert(ret == 0); +} + +// mmap two addresses, with a page gap between two. +// assign pkeys on both address. +// disable access to the second address. +// mprotect from start of address1 to the end of address 2, +// because there is a gap in the memory range, mprotect will fail. +void test_mprotect_gapped_address_with_two_pkeys(bool enforce) +{ + int pkey, pkey2; + int ret; + void *ptr, *ptr2; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_address_with_gap_two_pkeys(enforce, size, &pkey, &pkey2, &ptr, + &ptr2); + + // disable write access. + pkey_write_deny(pkey2); + + ret = sys_mprotect_pkey(ptr, size * 3, PROT_READ | PROT_WRITE, pkey); + assert(ret < 0); + + ret = sys_mprotect(ptr, size * 3, PROT_READ | PROT_WRITE); + assert(ret < 0); + + pkey_write_allow(pkey2); + + ret = sys_mprotect_pkey(ptr, size * 3, PROT_READ, pkey); + assert(ret < 0); + + ret = sys_mprotect(ptr, size * 3, PROT_READ); + assert(ret < 0); + + clean_address_with_pag_two_pkeys(pkey, ptr, pkey2, ptr2, size); +} + +struct thread_info { + int pkey; + void *addr; + int size; + bool enforce; +}; + +void *thread_mprotect(void *arg) +{ + struct thread_info *tinfo = arg; + void *ptr = tinfo->addr; + int size = tinfo->size; + bool enforce = tinfo->enforce; + int pkey = tinfo->pkey; + int ret; + + // disable write access. + pkey_write_deny(pkey); + ret = sys_mprotect_pkey(ptr, size, PROT_READ | PROT_WRITE, pkey); + + if (enforce) + assert(ret < 0); + else + assert(!ret); + + ret = sys_mprotect(ptr, size, PROT_READ | PROT_WRITE); + if (enforce) + assert(ret < 0); + else + assert(ret == 0); + + pkey_write_allow(pkey); + + ret = sys_mprotect_pkey(ptr, size, PROT_READ, pkey); + assert(!ret); + + ret = sys_mprotect(ptr, size, PROT_READ); + assert(ret == 0); + return NULL; +} + +// mmap one address. +// assign pkey on the address. +// in child thread, mprotect is denied when no-writeable PKRU in enforce mode. +void test_mprotect_child_thread(bool enforce) +{ + int pkey; + int ret; + void *ptr; + int size = PAGE_SIZE; + pthread_t thread; + struct thread_info tinfo; + + LOG_TEST_ENTER(enforce); + + setup_single_fixed_address_with_pkey(enforce, size, &pkey, &ptr); + tinfo.size = size; + tinfo.addr = ptr; + tinfo.enforce = enforce; + tinfo.pkey = pkey; + + ret = pthread_create(&thread, NULL, thread_mprotect, (void *)&tinfo); + assert(ret == 0); + pthread_join(thread, NULL); + + clean_single_address_with_pkey(pkey, ptr, size); +} + +void test_enforce_api(void) +{ + for (int i = 0; i < 2; i++) { + bool enforce = (i == 1); + + test_pkey_alloc(enforce); + + test_mprotect_single_address(enforce); + test_mprotect_two_address_merge(enforce); + test_mprotect_two_address_deny_second(enforce); + test_mprotect_vma_middle_addr(enforce); + test_mprotect_unaligned(enforce); + test_mprotect_unaligned2(enforce); + test_mprotect_child_thread(enforce); + test_mprotect_gapped_address_with_two_pkeys(enforce); + } +} + +int main(void) +{ + int pkeys_supported = is_pkeys_supported(); + + printf("pid: %d\n", getpid()); + printf("has pkeys: %d\n", pkeys_supported); + if (!pkeys_supported) { + printf("PKEY not supported, skip the test.\n"); + exit(0); + } + + test_enforce_api(); + printf("done (all tests OK)\n"); + return 0; +} +#else /* arch */ +int main(void) +{ + printf("SKIP: not supported arch\n"); + return 0; +} +#endif /* arch */ From patchwork Mon May 15 13:05:51 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Xu X-Patchwork-Id: 13241399 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 05390C77B75 for ; Mon, 15 May 2023 13:07:10 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 744D5900006; Mon, 15 May 2023 09:07:10 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 6F4FF900002; Mon, 15 May 2023 09:07:10 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 5E3BC900006; Mon, 15 May 2023 09:07:10 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0011.hostedemail.com [216.40.44.11]) by kanga.kvack.org (Postfix) with ESMTP id 488A8900002 for ; Mon, 15 May 2023 09:07:10 -0400 (EDT) Received: from smtpin18.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay09.hostedemail.com (Postfix) with ESMTP id 01DFC8126F for ; Mon, 15 May 2023 13:07:09 +0000 (UTC) X-FDA: 80792515020.18.5DE699A Received: from mail-pl1-f176.google.com (mail-pl1-f176.google.com [209.85.214.176]) by imf02.hostedemail.com (Postfix) with ESMTP id 7AF6380188 for ; Mon, 15 May 2023 13:06:06 +0000 (UTC) Authentication-Results: imf02.hostedemail.com; dkim=pass header.d=chromium.org header.s=google header.b=AE5TPYdJ; spf=pass (imf02.hostedemail.com: domain of jeffxu@chromium.org designates 209.85.214.176 as permitted sender) smtp.mailfrom=jeffxu@chromium.org; dmarc=pass (policy=none) header.from=chromium.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1684155966; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=lhTOrV9Ep9418v/k9QWjv1EjLbKrSL2Q0hL/MSOj6fE=; b=etpamlidbIGDav2U2W4fEdmhFF2ON4gxTjpa0YqJk1MDYW4l+QyGozVuiPd7WqKNA+PPDb fR7qJsbn1hOChWTaK+/uIuZOopmqdWmW3CRnXF/LWdYR8CiAmzqD662gBRq23d3rPC8Lzr oFG6GIC01wnD5b3wkea/ryxQhO97znU= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1684155966; a=rsa-sha256; cv=none; b=FdcEgjakLG//5+YJrHYAN8H58q0kA3rcedU+xVHnoG9FqaHdZEtbGfwCP3e+3Z+HSFfeXW 4dmBCK8jW0VbSnR+FMpC9olIEtqc8hBKtWxQ+sfdbR3JYEw+GwRwRsLhL7l7bRiBkSlKe1 hLq0e++NYAvYH9lo0+6LFZaCiBL5f3Q= ARC-Authentication-Results: i=1; imf02.hostedemail.com; dkim=pass header.d=chromium.org header.s=google header.b=AE5TPYdJ; spf=pass (imf02.hostedemail.com: domain of jeffxu@chromium.org designates 209.85.214.176 as permitted sender) smtp.mailfrom=jeffxu@chromium.org; dmarc=pass (policy=none) header.from=chromium.org Received: by mail-pl1-f176.google.com with SMTP id d9443c01a7336-1aaef97652fso87518365ad.0 for ; Mon, 15 May 2023 06:06:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1684155965; x=1686747965; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=lhTOrV9Ep9418v/k9QWjv1EjLbKrSL2Q0hL/MSOj6fE=; b=AE5TPYdJKh+upwVCJh3G8m4CCCGvl07nH8DA+I/nklujQ9YNY+5+hrzRPCyiIGbHCd /G3dlUxrCo3tGgXlYHwHpAnY3srtCMkn2jHsUMg6pylapAZdL3XF43Ekl+CjStZbtfNz qtYa8TABInHSPUkJf4aHK+0vNIdvP6UNEHHos= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684155965; x=1686747965; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=lhTOrV9Ep9418v/k9QWjv1EjLbKrSL2Q0hL/MSOj6fE=; b=JL83gfX+VyA2LGWK/o+kjRi9MRjZWtpzIS1Xe9oXhR2ru3JUa/fIOM87Wxjy15nWhQ ORIYe3IBSlNriFJ9duyBie3+IyT1JT7rKJajQ3ODFxHdlkpdTLxBQy+Nu0z0hROujbPD zRv/LxY3O1K4GBHYkg3ge2Ma92QXZfYbv8ifLwL06iAHdJ3Uq8oNmDRQmYZxXAOB7UV/ nYnz/+fNnPqCrg4Fw1HaAEC/CIl0Ci7+CO72ZLsnivSZtHp4LKx/na/TI+PVuV11Mif9 smhykAx0BzsX0KSyNJu7yA9U7X3awy+1K+rVPhCUDnOMWILFtEvhVU+v85O1xoTKlOfx 2BbQ== X-Gm-Message-State: AC+VfDxALZscyG0BLjgkwaix5gG2OIKCqromyqcuVE6gKfcRBlIZvoOQ n2Xd9sX6CutpuHf4oN3/jVKk2g== X-Google-Smtp-Source: ACHHUZ4pDHGfCKYoQ6o3ND+tn3Cpa2PwKLfI3Rj7SdWtOItCYzvZZqHrfIDR9pXglq7oDkkVfGKQ/Q== X-Received: by 2002:a17:902:da84:b0:1ac:a28e:4b29 with SMTP id j4-20020a170902da8400b001aca28e4b29mr29799652plx.26.1684155965066; Mon, 15 May 2023 06:06:05 -0700 (PDT) Received: from localhost (183.43.230.35.bc.googleusercontent.com. [35.230.43.183]) by smtp.gmail.com with UTF8SMTPSA id z6-20020a170902834600b001a980a23802sm13465239pln.111.2023.05.15.06.06.04 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 15 May 2023 06:06:04 -0700 (PDT) From: jeffxu@chromium.org To: dave.hansen@intel.com, luto@kernel.org, jorgelo@chromium.org, keescook@chromium.org, groeck@chromium.org, jannh@google.com, sroettger@google.com Cc: akpm@linux-foundation.org, jeffxu@google.com, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org, linux-hardening@vger.kernel.org Subject: [PATCH 5/6] KEY: Apply PKEY_ENFORCE_API to munmap Date: Mon, 15 May 2023 13:05:51 +0000 Message-ID: <20230515130553.2311248-6-jeffxu@chromium.org> X-Mailer: git-send-email 2.40.1.606.ga4b1b128d6-goog In-Reply-To: <20230515130553.2311248-1-jeffxu@chromium.org> References: <20230515130553.2311248-1-jeffxu@chromium.org> MIME-Version: 1.0 X-Rspamd-Queue-Id: 7AF6380188 X-Rspam-User: X-Rspamd-Server: rspam06 X-Stat-Signature: h5guuhzn7qs41yyoitexn14yqjgja45e X-HE-Tag: 1684155966-755795 X-HE-Meta: U2FsdGVkX1/F5lehs03wEEEKgCnq4gTuAJGKYMxJiPyz6dXhojZLtq9fdrnQ/+dCMP29MriAwV1EdJJOqnB9RNtGW/mdq/k+PEg42zIDVjNFzablvQo6dpqUKlfAFmHgOUczMo/aXI4FSPE/jm230cFsnc+CqazTQKXoURAqoHr/7HZzP2VWz3F+y5B6wZe5SvT2Pk8UAoJ9Un/e2MMss5DUMoNdvCLKwrM7fTxXzoiQ5PYRL8Hv+RjKgQIne7Zc/NCcRvkdQqmqAhOl7SkM5tfbvmAHaRLq7ykUssjKg2hja2Pn10yRBxEsnr0Dy0qEX1/NXNZQjtoEcEJ9tI0FCZ8CCdibcNc4dsVjC+8IAMcKia7OzOqH/kZQSw3KmGh8rcqmPcDNO2Uc454aqNOQer1LNuLCuKts1qZFoUi9vj5CLa1nm8PRMUNO468Aq+xKq2WpWjn/JDGFirev46MC4hrUe7+5W2KEDyaQhsHQzxiogmlCxbCITL5IiDQMKrOuW9gLKE7CJeo1AcJemq7tXvqobvqt/8yLY5T602zDHpXu51zSl2iCGOWUzObWjNJqs01NJKKQFWg0YHhl+VfuB+x107frveEEMpldt7Zk93EwZYa36wA46UnHfCgyqkWsWHyTlmtaEQolCk7PKLD6v2JWC6T+9fB1hhLbY9TjjoNy37yqGUd2IKC508zRFsCkDvqKabw6RvSmgnSOcx9+j3r4nlS6vApGFP52fX1xnKDchvU71MvEVnK0dUavTkbndDz16pj1i5I5yiO0o40/HBjQOu+ZUCIDv1/6aRlvz/j2zDbL+tMsU4A5JLVJFsEK8NNeCcbgc1xo2cKnfeMk7p8MQwfNX96dLwBpyCZaSZ5Dryghj8nmNBCutqqHHaiL+tWQ8cgU5UN0LofuN+wlxTKe7GX+WpYr0gzjJ+eJGk1NFCn9ntsAVXLWqg2lQv7k3b3NPfcCMphfn13qKbd dD9PxVK/ xcnDslQDCDoMlq+x1OwEY+LMuC2wK6Ii4lqBrJ1azAFFh6xYHO752VzecL/TESXyLlDl7/iZygJAHY5m+h/zJ+ryWQw/rdZluoghf968yFUSjjoIcm9u6R3kePI15MjqQ5pVd2wkjraOR7zch/2YeB8V2pfEVNuxrRqrgux9whnqRLTLDkrBOGOqP0vARmgA60OtmlCLL33U0VmYVSm219pHWbtuj4u0n+uDNqoaRFD5K7siwCnXOpB8MUJf3AAc/VSC9hRHF6enKOVVogTnEUXYc92Duw4Syt7n1M1t8vlLA0G27iuV6GtfJ/P+K/5QHTWjZRH6l08tEeotlvCUoXiAUZ8A+988Dt6VNWTwNtt6p3DyjSHvS/iMAew== 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: From: Jeff Xu This patch enables PKEY_ENFORCE_API for the munmap syscall. Signed-off-by: Jeff Xu --- include/linux/mm.h | 2 +- mm/mmap.c | 34 ++++++++++++++++++++++++++-------- mm/mremap.c | 6 ++++-- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 27ce77080c79..48076e845d53 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -3136,7 +3136,7 @@ extern unsigned long do_mmap(struct file *file, unsigned long addr, unsigned long pgoff, unsigned long *populate, struct list_head *uf); extern int do_vmi_munmap(struct vma_iterator *vmi, struct mm_struct *mm, unsigned long start, size_t len, struct list_head *uf, - bool downgrade); + bool downgrade, bool syscall); extern int do_munmap(struct mm_struct *, unsigned long, size_t, struct list_head *uf); extern int do_madvise(struct mm_struct *mm, unsigned long start, size_t len_in, int behavior); diff --git a/mm/mmap.c b/mm/mmap.c index 13678edaa22c..29329aa794a6 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -2498,6 +2498,7 @@ do_vmi_align_munmap(struct vma_iterator *vmi, struct vm_area_struct *vma, * @uf: The userfaultfd list_head * @downgrade: set to true if the user wants to attempt to write_downgrade the * mmap_lock + * @syscall: set to true if this is called from syscall entry * * This function takes a @mas that is either pointing to the previous VMA or set * to MA_START and sets it up to remove the mapping(s). The @len will be @@ -2507,7 +2508,7 @@ do_vmi_align_munmap(struct vma_iterator *vmi, struct vm_area_struct *vma, */ int do_vmi_munmap(struct vma_iterator *vmi, struct mm_struct *mm, unsigned long start, size_t len, struct list_head *uf, - bool downgrade) + bool downgrade, bool syscall) { unsigned long end; struct vm_area_struct *vma; @@ -2519,6 +2520,19 @@ int do_vmi_munmap(struct vma_iterator *vmi, struct mm_struct *mm, if (end == start) return -EINVAL; + /* + * When called by syscall from userspace, check if the calling + * thread has the PKEY permission to modify the memory mapping. + */ + if (syscall && arch_check_pkey_enforce_api(mm, start, end) < 0) { + char comm[TASK_COMM_LEN]; + + pr_warn_ratelimited( + "munmap was denied on PKEY_ENFORCE_API memory, pid=%d '%s'\n", + task_pid_nr(current), get_task_comm(comm, current)); + return -EACCES; + } + /* arch_unmap() might do unmaps itself. */ arch_unmap(mm, start, end); @@ -2541,7 +2555,7 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len, { VMA_ITERATOR(vmi, mm, start); - return do_vmi_munmap(&vmi, mm, start, len, uf, false); + return do_vmi_munmap(&vmi, mm, start, len, uf, false, false); } unsigned long mmap_region(struct file *file, unsigned long addr, @@ -2575,7 +2589,7 @@ unsigned long mmap_region(struct file *file, unsigned long addr, } /* Unmap any existing mapping in the area */ - if (do_vmi_munmap(&vmi, mm, addr, len, uf, false)) + if (do_vmi_munmap(&vmi, mm, addr, len, uf, false, false)) return -ENOMEM; /* @@ -2792,7 +2806,11 @@ unsigned long mmap_region(struct file *file, unsigned long addr, return error; } -static int __vm_munmap(unsigned long start, size_t len, bool downgrade) +/* + * @syscall: set to true if this is called from syscall entry + */ +static int __vm_munmap(unsigned long start, size_t len, bool downgrade, + bool syscall) { int ret; struct mm_struct *mm = current->mm; @@ -2802,7 +2820,7 @@ static int __vm_munmap(unsigned long start, size_t len, bool downgrade) if (mmap_write_lock_killable(mm)) return -EINTR; - ret = do_vmi_munmap(&vmi, mm, start, len, &uf, downgrade); + ret = do_vmi_munmap(&vmi, mm, start, len, &uf, downgrade, syscall); /* * Returning 1 indicates mmap_lock is downgraded. * But 1 is not legal return value of vm_munmap() and munmap(), reset @@ -2820,14 +2838,14 @@ static int __vm_munmap(unsigned long start, size_t len, bool downgrade) int vm_munmap(unsigned long start, size_t len) { - return __vm_munmap(start, len, false); + return __vm_munmap(start, len, false, false); } EXPORT_SYMBOL(vm_munmap); SYSCALL_DEFINE2(munmap, unsigned long, addr, size_t, len) { addr = untagged_addr(addr); - return __vm_munmap(addr, len, true); + return __vm_munmap(addr, len, true, true); } @@ -3055,7 +3073,7 @@ int vm_brk_flags(unsigned long addr, unsigned long request, unsigned long flags) if (ret) goto limits_failed; - ret = do_vmi_munmap(&vmi, mm, addr, len, &uf, 0); + ret = do_vmi_munmap(&vmi, mm, addr, len, &uf, 0, false); if (ret) goto munmap_failed; diff --git a/mm/mremap.c b/mm/mremap.c index b11ce6c92099..768e5bd4e8b5 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -703,7 +703,8 @@ static unsigned long move_vma(struct vm_area_struct *vma, } vma_iter_init(&vmi, mm, old_addr); - if (do_vmi_munmap(&vmi, mm, old_addr, old_len, uf_unmap, false) < 0) { + if (do_vmi_munmap(&vmi, mm, old_addr, old_len, uf_unmap, false, false) < + 0) { /* OOM: unable to split vma, just get accounts right */ if (vm_flags & VM_ACCOUNT && !(flags & MREMAP_DONTUNMAP)) vm_acct_memory(old_len >> PAGE_SHIFT); @@ -993,7 +994,8 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len, VMA_ITERATOR(vmi, mm, addr + new_len); retval = do_vmi_munmap(&vmi, mm, addr + new_len, - old_len - new_len, &uf_unmap, true); + old_len - new_len, &uf_unmap, true, + false); /* Returning 1 indicates mmap_lock is downgraded to read. */ if (retval == 1) { downgraded = true; From patchwork Mon May 15 13:05:52 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Xu X-Patchwork-Id: 13241400 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 08BCFC77B75 for ; Mon, 15 May 2023 13:07:22 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 7B913900007; Mon, 15 May 2023 09:07:22 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 769BB900002; Mon, 15 May 2023 09:07:22 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 60B5B900007; Mon, 15 May 2023 09:07:22 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0010.hostedemail.com [216.40.44.10]) by kanga.kvack.org (Postfix) with ESMTP id 49E37900002 for ; Mon, 15 May 2023 09:07:22 -0400 (EDT) Received: from smtpin21.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay07.hostedemail.com (Postfix) with ESMTP id B7C64161251 for ; Mon, 15 May 2023 13:07:21 +0000 (UTC) X-FDA: 80792515482.21.CDC67CE Received: from mail-pl1-f172.google.com (mail-pl1-f172.google.com [209.85.214.172]) by imf02.hostedemail.com (Postfix) with ESMTP id E2E0380003 for ; Mon, 15 May 2023 13:06:07 +0000 (UTC) Authentication-Results: imf02.hostedemail.com; dkim=pass header.d=chromium.org header.s=google header.b=Md2uy27i; dmarc=pass (policy=none) header.from=chromium.org; spf=pass (imf02.hostedemail.com: domain of jeffxu@chromium.org designates 209.85.214.172 as permitted sender) smtp.mailfrom=jeffxu@chromium.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1684155968; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=oD0d2al7XFldRkjYP37ZWtTdhmPaRGV8lU2SKIN3qFc=; b=5B/jbuiSapxDaZDY1n61yF9wdiznCh6BtnIGYZPlfcdcabmaH+HOP1joBo9CLiu57uX1Wl QYgYSoeZA17x+ig8OdhC1lIRoyhHegNfD9xqQxt7YsoUIHEQOdQYw6NRolFKhOPiukMkPY Kij1ESN86eCCAqGwKhwlh+iojBOWk4Y= ARC-Authentication-Results: i=1; imf02.hostedemail.com; dkim=pass header.d=chromium.org header.s=google header.b=Md2uy27i; dmarc=pass (policy=none) header.from=chromium.org; spf=pass (imf02.hostedemail.com: domain of jeffxu@chromium.org designates 209.85.214.172 as permitted sender) smtp.mailfrom=jeffxu@chromium.org ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1684155968; a=rsa-sha256; cv=none; b=6unCaXrIF73vZh8HCZIEIKSBzjqxzFrz0HYK6xJhTTC2tW4qcLxurVpL7TKR1gaFDnxuQS LN0i+2of+idTnUKgO5TRHvFthVlmBo5FRQK0B4HkfsE7nNZwhECpD/Z3pI/iB0LrqMJJ7j XjK5k2qCe8PRy4e45hdAtlAgHSaXHM0= Received: by mail-pl1-f172.google.com with SMTP id d9443c01a7336-1aaf70676b6so90626255ad.3 for ; Mon, 15 May 2023 06:06:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1684155966; x=1686747966; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=oD0d2al7XFldRkjYP37ZWtTdhmPaRGV8lU2SKIN3qFc=; b=Md2uy27iyG56QmAk/eMUrPY9FgIbjWQ34NOlHqHXzvq/n+f6KFeUNnAfHdTfIROgpr i+HrFD3SDGN7cdg0bpeMPna+t3GxvzduQzy5yue646dWIIdgWqwFvGeyeP2WvGuBIaf9 lca9gTUHWxnlNULGlhCBRARLT0/pk0Uz/OAmw= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684155966; x=1686747966; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=oD0d2al7XFldRkjYP37ZWtTdhmPaRGV8lU2SKIN3qFc=; b=aEXmFaG8IVtJOwOgzKB3etF0UNib7EaN/K0oVRVD0xoCgEwTPxRH7RD3C/c/SXYPXF 4ZsQCqB71iYd6yS7edgysJzE8Xkpix/pfHCV4MyJUmX6bhFqpDh3+/YuOFS7/01cZdSq g0be1NXpb8pE75ARu68s2gMRZY7sJvT7iL8dxSw0kAUye1+cHbhEOy40bMVOYaU9gUWj kHshbdfVJqwbbOWDKnfUVrtq8DVgOXLI9T9z0sfVqUYyr53tozEqpOXcZU32xkb2uXfd SuY6gjmwwypUSmWPXUmRzRzOLlilGb7iY9g7DiEUja3YBzdNCfYuOnMGTV17kzmnVUqm jlmg== X-Gm-Message-State: AC+VfDzRaSNKoYZtB1w5MCxMZtsCrgHbrfPGGc3qyfcS7SGIpAq2wWcU cNDSKOwlE7eRNAPp3GdIkJSC3g== X-Google-Smtp-Source: ACHHUZ7kRs6SmTa1z+RVcotvr+mhyGciDo5UlpdWfWoFRJZOmx9Unzfl0FpNuZrj13ngH72aAGPZ1g== X-Received: by 2002:a17:903:234f:b0:1ae:bf5:7b5 with SMTP id c15-20020a170903234f00b001ae0bf507b5mr6078985plh.34.1684155966087; Mon, 15 May 2023 06:06:06 -0700 (PDT) Received: from localhost (183.43.230.35.bc.googleusercontent.com. [35.230.43.183]) by smtp.gmail.com with UTF8SMTPSA id g13-20020a170902c38d00b0019f9fd10f62sm13454823plg.70.2023.05.15.06.06.05 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 15 May 2023 06:06:05 -0700 (PDT) From: jeffxu@chromium.org To: dave.hansen@intel.com, luto@kernel.org, jorgelo@chromium.org, keescook@chromium.org, groeck@chromium.org, jannh@google.com, sroettger@google.com Cc: akpm@linux-foundation.org, jeffxu@google.com, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org, linux-hardening@vger.kernel.org Subject: [PATCH 6/6] PKEY:selftest pkey_enforce_api for munmap Date: Mon, 15 May 2023 13:05:52 +0000 Message-ID: <20230515130553.2311248-7-jeffxu@chromium.org> X-Mailer: git-send-email 2.40.1.606.ga4b1b128d6-goog In-Reply-To: <20230515130553.2311248-1-jeffxu@chromium.org> References: <20230515130553.2311248-1-jeffxu@chromium.org> MIME-Version: 1.0 X-Stat-Signature: pe3b4xhynp1udiqma6whahfm65gpdp9p X-Rspam-User: X-Rspamd-Queue-Id: E2E0380003 X-Rspamd-Server: rspam07 X-HE-Tag: 1684155967-562415 X-HE-Meta: U2FsdGVkX1+qotQtGKGbbKpkG84NKlmpjBOCzxPAkK4r/LmKxfKxUO1hGfNdy7GCY2PjNBCxeunUp/Mpj49Av7e+pGu5liy+3zQPfM9xQZqBEyoxGH5ZJk7vgeuDSpt6+qizWbPp7qMatcQclvTIMOoVZep6uUMJWJHEKEbklMME7dFOvdNmIgRIfOlENCVzT2tn4dCEGvvYebxthIlasb8HX07fqWeFv3BEm2lfQN/GNubtQ4NxONm0AryXizt+mgC6pReGrtVpOJ5IY1GeQtSwAbl4EIHZaV0qIEg3ce56qxV+QrrN5PuRI5zN6Q+Sv5uKJptY5N+G1eUXwJtp9exUfAS8AaBj73bq0SZqBBU2PhwqcPGQdtWFsliAnKQvXzUxNkN34cs+h7yjuy8wvw3Qnl0qPyw4Z7ak/3+6VhRHpjoSIZoSjwPhGbZ/pBcSiXVPSNwzQPmbm5kftvPg3RneTxJj8IgpnoAuJGCEDdfs/HJzQXeFlgZwkbLazB2Xc7sfdpA1tKuV6LXF6hOiNR8nrwyilmil0lJHAn127eHOfj/AYIL7yR+hVONUvp4u4SQkPVuz5CNRIWaxWqyxkkdzPqLqYFJw71H0hlX63K18Wj6fDR5AbTbxTJf2c6zX1j3Gb5D71MUfRnS5W+68GjgfZm+iXfabDqNO6jE2pOWSxAhzZJG2x4YOY28HZ36Lb+jRfkgSTfGDOFOlP5aTzehGZhH+bbl3OWMUvRAy7Ckpgx8vMMsMTUWLBhsW0YAVLi0tx/MuUTzJ/Iu6ZXS8oRFVNKVYp5vnw6Ztoy2V63ZOSBF26KXpd5kLKQJ1l5i3l/e5qEi+8SVVcq8hEnMMsUhNoluunII9VT2ztzVR5SNOgh7SoKqzPsmdQMRtBWuen+W70TUoDrp70Q/7hfETlentSRhPlWfsyygrjKjbc+U8Ww9eoOD9UOlh8KawqWIygbU99ZUmkeEmcOZBB1n NohGaeje urF8+QEoBMnnoIlCdh7FatAw6TIGZb4fRTJfibsG/8AcpREvqDoV0eXKrcmKYXXW0McpN7Iyn+272gXl56B1w/Ear9slZMgXRBhVQxr+zrwOw1DIZMDZML9UJJppI4qS1bqOHvSC7TFy/4xjGd8gsQ1OXzAdgdGMpZN+OT8FdPnphnixdXB71lpRBHfXOoK+eidD8WFTg4NRkUJLbQUdoyaU0p1l3AS0c2vG3ahrvYMfOWxg/wPUCGIlG9nFTByo40xqN7E9GgwgenyJd1zDeV/1LotFjALj+qB5aodbAvIhd7Yjr3iU00ced4ptyeWPykYCzMSFrXKSx+cLjhP+fHhL34qKUjYjLMIZoLu/vCJHJleCzn/T/Ceg+5Q== 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: From: Jeff Xu Add selftest for pkey_enforce_api for mprotect Signed-off-by: Jeff Xu --- tools/testing/selftests/mm/pkey_enforce_api.c | 437 ++++++++++++++++++ 1 file changed, 437 insertions(+) diff --git a/tools/testing/selftests/mm/pkey_enforce_api.c b/tools/testing/selftests/mm/pkey_enforce_api.c index 23663c89bc9c..92aa29248e1f 100644 --- a/tools/testing/selftests/mm/pkey_enforce_api.c +++ b/tools/testing/selftests/mm/pkey_enforce_api.c @@ -833,6 +833,429 @@ void test_mprotect_child_thread(bool enforce) clean_single_address_with_pkey(pkey, ptr, size); } +// mmap one address with one page. +// assign PKEY to the address. +// munmap on the address is protected. +void test_munmap_single_address(bool enforce) +{ + int pkey; + int ret; + void *ptr; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_single_address_with_pkey(enforce, size, &pkey, &ptr); + + // disable write access. + pkey_write_deny(pkey); + + ret = munmap(ptr, size); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + pkey_write_allow(pkey); + + if (enforce) { + ret = munmap(ptr, size); + assert(!ret); + } + + clean_single_address_with_pkey(pkey, ptr, size); +} + +// mmap two address (continuous two pages). +// assign PKEY to them with one mprotect_pkey call (merged address). +// munmap two address in one call (merged address). +void test_munmap_two_address_merge(bool enforce) +{ + int pkey; + int ret; + void *ptr; + void *ptr2; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_two_continues_fixed_address_with_pkey(enforce, size, &pkey, &ptr, + &ptr2); + + // disable write. + pkey_write_deny(pkey); + + // munmap on both addresses with one call (merged). + ret = munmap(ptr, size * 2); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + pkey_write_allow(pkey); + + if (enforce) { + ret = munmap(ptr, size * 2); + assert(!ret); + } + + ret = sys_pkey_free(pkey); + assert(ret == 0); +} + +// mmap two address (continuous two pages). +// assign PKEY to the second address. +// munmap on the second address is protected. +void test_munmap_two_address_deny_second(bool enforce) +{ + int pkey; + int ret; + void *ptr; + void *ptr2; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_two_continues_fixed_address_protect_second_with_pkey( + enforce, size, &pkey, &ptr, &ptr2); + + // disable write through pkey. + pkey_write_deny(pkey); + + ret = munmap(ptr2, size); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + ret = munmap(ptr, size); + assert(!ret); + + pkey_write_allow(pkey); + + if (enforce) { + ret = munmap(ptr2, size); + assert(!ret); + } + + ret = sys_pkey_free(pkey); + assert(ret == 0); +} + +// mmap two address (continuous two pages). +// assign PKEY to the second address. +// munmap on the range that includes the second address. +void test_munmap_two_address_deny_range(bool enforce) +{ + int pkey; + int ret; + void *ptr; + void *ptr2; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_two_continues_fixed_address_protect_second_with_pkey( + enforce, size, &pkey, &ptr, &ptr2); + + // disable write through pkey. + pkey_write_deny(pkey); + + ret = munmap(ptr, size * 2); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + pkey_write_allow(pkey); + + if (enforce) { + ret = munmap(ptr, size * 2); + assert(!ret); + } + + ret = sys_pkey_free(pkey); + assert(ret == 0); +} + +// mmap one address with 4 pages. +// assign PKEY to the second page only. +// munmap on memory range that includes the second pages is protected. +void test_munmap_vma_middle_addr(bool enforce) +{ + int pkey; + int ret; + void *ptr, *ptr2, *ptr3; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_4pages_fixed_protect_second_page(enforce, size, &pkey, &ptr, + &ptr2, &ptr3); + + // disable write through pkey. + pkey_write_deny(pkey); + + // munmap support merge, we are going to make sure we don't regress. + ret = munmap(addr1, size * 4); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + pkey_write_allow(pkey); + + if (enforce) { + ret = munmap(ptr, size * 4); + assert(!ret); + } + + ret = sys_pkey_free(pkey); + assert(ret == 0); +} + +// mmap one address with 4 pages. +// assign PKEY to the second page only. +// munmap from 2nd page. +void test_munmap_shrink(bool enforce) +{ + int pkey; + int ret; + void *ptr, *ptr2, *ptr3; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_4pages_fixed_protect_second_page(enforce, size, &pkey, &ptr, + &ptr2, &ptr3); + + // disable write through pkey. + pkey_write_deny(pkey); + + // munmap support merge, we are going to make sure we don't regress. + ret = munmap(ptr2, size * 3); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + pkey_write_allow(pkey); + + if (enforce) { + ret = munmap(ptr2, size * 3); + assert(!ret); + } + + ret = munmap(ptr, size); + assert(!ret); + + ret = sys_pkey_free(pkey); + assert(ret == 0); +} + +// mmap one address with 4 pages. +// assign PKEY to the second page only. +// munmap from 2nd page but size is less than one page +void test_munmap_unaligned(bool enforce) +{ + int pkey; + int ret; + void *ptr, *ptr2, *ptr3; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_4pages_fixed_protect_second_page(enforce, size, &pkey, &ptr, + &ptr2, &ptr3); + + // disable write through pkey. + pkey_write_deny(pkey); + + // munmap support merge, we are going to make sure we don't regress. + ret = munmap(ptr2, size - 1); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + pkey_write_allow(pkey); + + if (enforce) { + ret = munmap(ptr2, size - 1); + assert(!ret); + } + + ret = munmap(ptr, size * 4); + assert(!ret); + + ret = sys_pkey_free(pkey); + assert(ret == 0); +} + +// mmap one address with 4 pages. +// assign PKEY to the second page only. +// munmap from 2nd page but size is less than one page +void test_munmap_unaligned2(bool enforce) +{ + int pkey; + int ret; + void *ptr, *ptr2, *ptr3; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_4pages_fixed_protect_second_page(enforce, size, &pkey, &ptr, + &ptr2, &ptr3); + + // disable write through pkey. + pkey_write_deny(pkey); + + // munmap support merge, we are going to make sure we don't regress. + ret = munmap(ptr2, size + 1); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + pkey_write_allow(pkey); + + if (enforce) { + ret = munmap(ptr2, size + 1); + assert(!ret); + } + + ret = munmap(ptr, size * 4); + assert(!ret); + + ret = sys_pkey_free(pkey); + assert(ret == 0); +} + +// mmap one address with one page. +// assign PKEY to the address. +// munmap on the address but with size of 4 pages(should OK). +void test_munmap_outbound_addr(bool enforce) +{ + int pkey; + int ret; + void *ptr; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_single_fixed_address_with_pkey(enforce, size, &pkey, &ptr); + + // disable write through pkey. + pkey_write_deny(pkey); + + // Interesting enough, this is allowed, even the other 3 pages are not allocated. + ret = munmap(addr1, size * 4); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + pkey_write_allow(pkey); + + if (enforce) { + ret = munmap(addr1, size * 4); + assert(!ret); + } + + clean_single_address_with_pkey(pkey, ptr, size); +} +// mmap two addresses, with a page gap between two. +// assign pkeys on both address. +// disable access to the second address. +// munmap from start of address1 to the end of address 2, +// because there is a gap in the memory range, mprotect will fail. +void test_munmap_gapped_address_with_two_pkeys(bool enforce) +{ + int pkey, pkey2; + int ret; + void *ptr, *ptr2; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_address_with_gap_two_pkeys(enforce, size, &pkey, &pkey2, &ptr, + &ptr2); + + // disable write access. + pkey_write_deny(pkey2); + + // Interesting enough, this is allowed, even there is a gap beween address 1 and 2. + ret = munmap(addr1, size * 3); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + pkey_write_allow(pkey2); + if (enforce) { + ret = munmap(addr1, size * 3); + assert(!ret); + } +} + +// use write-deny pkey and see if program can exit properly. +// This is manual test, run it at end if needed. +void test_exit_munmap_disable_write(void) +{ + int pkey; + int ret; + void *ptr; + int size = PAGE_SIZE; + + pkey = sys_pkey_alloc(PKEY_ENFORCE_API, 0); + assert(pkey > 0); + + // allocate 1 page. + ptr = mmap(addr1, size, PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); + assert(ptr == addr1); + + // assign pkey to the first address. + ret = sys_mprotect_pkey(ptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, + pkey); + assert(!ret); + + // disable write through pkey. + pkey_write_deny(pkey); + + ret = munmap(ptr, size); + assert(ret < 0); +} + +// use disable-all pkey and see if program can exit properly. +// This is manual test, run it at end if needed. +void test_exit_munmap_disable_all(void) +{ + int pkey; + int ret; + void *ptr; + int size = PAGE_SIZE; + + pkey = sys_pkey_alloc(PKEY_ENFORCE_API, 0); + assert(pkey > 0); + + // allocate 1 page. + ptr = mmap(addr2, size, PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); + assert(ptr == addr2); + + // assign pkey to the first address. + ret = sys_mprotect_pkey(ptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, + pkey); + assert(!ret); + + // disable write through pkey. + pkey_access_deny(pkey); + + ret = munmap(addr1, size); + assert(ret < 0); +} + void test_enforce_api(void) { for (int i = 0; i < 2; i++) { @@ -848,7 +1271,21 @@ void test_enforce_api(void) test_mprotect_unaligned2(enforce); test_mprotect_child_thread(enforce); test_mprotect_gapped_address_with_two_pkeys(enforce); + + test_munmap_single_address(enforce); + test_munmap_two_address_merge(enforce); + test_munmap_two_address_deny_second(enforce); + test_munmap_two_address_deny_range(enforce); + test_munmap_vma_middle_addr(enforce); + test_munmap_outbound_addr(enforce); + test_munmap_shrink(enforce); + test_munmap_unaligned(enforce); + test_munmap_unaligned2(enforce); + test_munmap_gapped_address_with_two_pkeys(enforce); } + + test_exit_munmap_disable_write(); + test_exit_munmap_disable_all(); } int main(void)