From patchwork Fri Apr 11 09:16:30 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Brodsky X-Patchwork-Id: 14047915 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 23879C36010 for ; Fri, 11 Apr 2025 09:18:10 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id A6CF72801A6; Fri, 11 Apr 2025 05:18:08 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id A1D8F28019B; Fri, 11 Apr 2025 05:18:08 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 8BF842801A6; Fri, 11 Apr 2025 05:18:08 -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 69C2128019B for ; Fri, 11 Apr 2025 05:18:08 -0400 (EDT) Received: from smtpin20.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay03.hostedemail.com (Postfix) with ESMTP id 2154AB0F40 for ; Fri, 11 Apr 2025 09:18:09 +0000 (UTC) X-FDA: 83321211498.20.E7FA00C Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by imf01.hostedemail.com (Postfix) with ESMTP id 7A03040008 for ; Fri, 11 Apr 2025 09:18:07 +0000 (UTC) Authentication-Results: imf01.hostedemail.com; dkim=none; spf=pass (imf01.hostedemail.com: domain of kevin.brodsky@arm.com designates 217.140.110.172 as permitted sender) smtp.mailfrom=kevin.brodsky@arm.com; dmarc=pass (policy=none) header.from=arm.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1744363087; 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; bh=bdMqiFDP4vUIg95dX44Zi6HrmWZHm2nf87Jx6pv15M8=; b=ngY61SUfR1NBdG8cZH6l9ZYqz2MVgCK1ZL15K9aYSHnVOOzadLh268rXXOk98JZVDZnUmj 7fKgroGbTrhKdvwNyd7oCREyJMFtuwTLowfwpOt26dohWXylEYijm6IE5zPy/1yO8vnIQV NpOoNB76w26UrkNqwf7+bur3JFHt/kE= ARC-Authentication-Results: i=1; imf01.hostedemail.com; dkim=none; spf=pass (imf01.hostedemail.com: domain of kevin.brodsky@arm.com designates 217.140.110.172 as permitted sender) smtp.mailfrom=kevin.brodsky@arm.com; dmarc=pass (policy=none) header.from=arm.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1744363087; a=rsa-sha256; cv=none; b=qeLfKqrL5RTh/+ts/X0AZhrJXg1qkucMzC+MmvgPuXPwpWrR1OhrDOzDt//aIypSk8aO4I TMjuUl3JkpuhqyGRcdIu9Ntrkm3JMdV7jO2DN4U3PNdSGJsZpgYZ5qDSkLbY5cznDFRnel /Y1Agb9RHsvdwmX5mVCKJIBET98yXLk= Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 8E785106F; Fri, 11 Apr 2025 02:18:06 -0700 (PDT) Received: from e123572-lin.arm.com (e123572-lin.cambridge.arm.com [10.1.194.54]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 07A993F6A8; Fri, 11 Apr 2025 02:18:02 -0700 (PDT) From: Kevin Brodsky To: linux-mm@kvack.org Cc: linux-kernel@vger.kernel.org, Kevin Brodsky , Andrew Morton , Mark Brown , Catalin Marinas , Dave Hansen , David Hildenbrand , Ira Weiny , Jann Horn , Jeff Xu , Joey Gouly , Kees Cook , Linus Walleij , Andy Lutomirski , Marc Zyngier , Peter Zijlstra , Pierre Langlois , Quentin Perret , Rick Edgecombe , "Mike Rapoport (IBM)" , Ryan Roberts , Thomas Gleixner , Will Deacon , Matthew Wilcox , Qi Zheng , linux-arm-kernel@lists.infradead.org, x86@kernel.org Subject: [RFC PATCH v4 17/18] mm: Add basic tests for kpkeys_hardened_pgtables Date: Fri, 11 Apr 2025 10:16:30 +0100 Message-ID: <20250411091631.954228-18-kevin.brodsky@arm.com> X-Mailer: git-send-email 2.47.0 In-Reply-To: <20250411091631.954228-1-kevin.brodsky@arm.com> References: <20250411091631.954228-1-kevin.brodsky@arm.com> MIME-Version: 1.0 X-Rspamd-Server: rspam11 X-Rspamd-Queue-Id: 7A03040008 X-Stat-Signature: p37e9csdud53ckftxyxqm6z4bmzxr38z X-Rspam-User: X-HE-Tag: 1744363087-410357 X-HE-Meta: U2FsdGVkX18tIUbczjXLPRXHovavYQQvnH2zxpF7CIhmm3wVAXgVwpfcNthedrVU2QXVZMnl6Dgfm5PQ7c4BHDH/o5Z2fFk4dIWw8jptQ9UcctmiTcUG2wasUmw1oiCQRbB9doTW1ipQY24OMLeToC4VCo7eyhDmbVs5C+ZORogdounPudQFzJn9pkheCGQ/Nsb4qsI87yulAUomoWJGT3B/TFIonDP9QLPz8CkUeoP1APvKt9tC6fQ4a48qeKTeMqfh5KEXCUOMPHSd7TvylTohnPkziQjspf9Nkd5D9lfJsAmZ1B1Xq8EP4IN4SeIrmlQPIWTDVTJgmvtACBKOkzA3RA6Zo6k2WMVk2KTU998FCGEuqq59BV6VgEg8AOKyQWJBREJMAOuttrGNG8+kZe56LF4nmoNlBQjjOp+RJBxFARE+INLaB7LMPdDPO/l+qEpjaQQpOisNb5ulI0o/lOfa1uLfUhoc8ArDvM/zXXSVEGgKJoWaU6d4IJPCkhfVi3FS8TblFPgR7uOsTBJJb3hgjfpBSz+zdaWgB6yFKgCoq5jao7+Kq2fgtXJ1ASCRNlCswxIQy34Lc5iJg9WUVrNBNmHnJPuLFD9c5kw3iYci8mcH2Ba8zNuSSikIah4RhFNZweXdHFsDydrL3h5bLRkkgPEqCU+xkGqNu7mvPm/hDWmvM3kjK52TavrOMWiFSwE1d37f1dWJdOF59DPYm9kuUR1J51sgpLa98l+FqtGyNd+/zIqlPUkw3MS4s0f/qXXvlnXCSKpQ77RE8WPU4ThyYNae9uEtJrCn0rRg3vWQfAgGEsbO25R3uCEG5D0bRlllB5f5sI3451J7yC5AqHgk1DLJZvmQERMWLjdeQA9OJJYdPlJOONB7LQrrQ1o5TKW+tR7fB8kffzpGagIefJJqBu0xSoXgbqYHsOZYeiDS+Gu92NAqLBUKwufei55OyrDiy5HDDRoFtmG11Jc +XCYoz3v b84B/tqVusLqZqkukYghXkwlqdDdQcPrDa0YbjQBRS7AYyCNh3Xwz0RrpGYWzIRScHsPxB8bIRSqHaWy74h1w1LZKYkD4bII1kEw24pft8ZR51S+I3DK+prwUbJOdds6NEErW3JBdTXoVvE2r4e6z124YNmAPSx2RDhqT68ALf2Gor4cU46TyZL5oJqVyXha8s1Wf6nzh9Tc+DzM= 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: List-Subscribe: List-Unsubscribe: Add basic tests for the kpkeys_hardened_pgtables feature: try to perform a direct write to kernel and user page table entries and ensure it fails. Signed-off-by: Kevin Brodsky --- mm/Makefile | 1 + mm/tests/kpkeys_hardened_pgtables_kunit.c | 97 +++++++++++++++++++++++ security/Kconfig.hardening | 12 +++ 3 files changed, 110 insertions(+) create mode 100644 mm/tests/kpkeys_hardened_pgtables_kunit.c diff --git a/mm/Makefile b/mm/Makefile index 0f30cc85c6f1..778df78c65d5 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -149,3 +149,4 @@ obj-$(CONFIG_EXECMEM) += execmem.o obj-$(CONFIG_TMPFS_QUOTA) += shmem_quota.o obj-$(CONFIG_PT_RECLAIM) += pt_reclaim.o obj-$(CONFIG_KPKEYS_HARDENED_PGTABLES) += kpkeys_hardened_pgtables.o +obj-$(CONFIG_KPKEYS_HARDENED_PGTABLES_KUNIT_TEST) += tests/kpkeys_hardened_pgtables_kunit.o diff --git a/mm/tests/kpkeys_hardened_pgtables_kunit.c b/mm/tests/kpkeys_hardened_pgtables_kunit.c new file mode 100644 index 000000000000..6e29721262b2 --- /dev/null +++ b/mm/tests/kpkeys_hardened_pgtables_kunit.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include +#include + +KUNIT_DEFINE_ACTION_WRAPPER(vfree_wrapper, vfree, const void *); + +static void write_linear_map_pte(struct kunit *test) +{ + pte_t *ptep; + pte_t pte; + int ret; + + if (!arch_kpkeys_enabled()) + kunit_skip(test, "kpkeys are not supported"); + + /* + * The choice of address is mostly arbitrary - we just need something + * that falls in the linear mapping, such as the address of a global + * variable. + */ + ptep = virt_to_kpte((unsigned long)&init_mm); + KUNIT_ASSERT_NOT_NULL_MSG(test, ptep, "Failed to get PTE"); + + pte = ptep_get(ptep); + pte = set_pte_bit(pte, __pgprot(PTE_WRITE)); + ret = copy_to_kernel_nofault(ptep, &pte, sizeof(pte)); + KUNIT_EXPECT_EQ_MSG(test, ret, -EFAULT, + "Direct PTE write wasn't prevented"); +} + +static void write_kernel_vmalloc_pte(struct kunit *test) +{ + void *mem; + pte_t *ptep; + pte_t pte; + int ret; + + if (!arch_kpkeys_enabled()) + kunit_skip(test, "kpkeys are not supported"); + + mem = vmalloc(PAGE_SIZE); + KUNIT_ASSERT_NOT_NULL(test, mem); + ret = kunit_add_action_or_reset(test, vfree_wrapper, mem); + KUNIT_ASSERT_EQ(test, ret, 0); + + ptep = virt_to_kpte((unsigned long)mem); + KUNIT_ASSERT_NOT_NULL_MSG(test, ptep, "Failed to get PTE"); + + pte = ptep_get(ptep); + pte = set_pte_bit(pte, __pgprot(PTE_WRITE)); + ret = copy_to_kernel_nofault(ptep, &pte, sizeof(pte)); + KUNIT_EXPECT_EQ_MSG(test, ret, -EFAULT, + "Direct PTE write wasn't prevented"); +} + +static void write_user_pmd(struct kunit *test) +{ + pmd_t *pmdp; + pmd_t pmd; + unsigned long uaddr; + int ret; + + if (!arch_kpkeys_enabled()) + kunit_skip(test, "kpkeys are not supported"); + + uaddr = kunit_vm_mmap(test, NULL, 0, PAGE_SIZE, PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_POPULATE, 0); + KUNIT_ASSERT_NE_MSG(test, uaddr, 0, "Could not create userspace mm"); + + /* We passed MAP_POPULATE so a PMD should already be allocated */ + pmdp = pmd_off(current->mm, uaddr); + KUNIT_ASSERT_NOT_NULL_MSG(test, pmdp, "Failed to get PMD"); + + pmd = pmdp_get(pmdp); + pmd = set_pmd_bit(pmd, __pgprot(PROT_SECT_NORMAL)); + ret = copy_to_kernel_nofault(pmdp, &pmd, sizeof(pmd)); + KUNIT_EXPECT_EQ_MSG(test, ret, -EFAULT, + "Direct PMD write wasn't prevented"); +} + +static struct kunit_case kpkeys_hardened_pgtables_test_cases[] = { + KUNIT_CASE(write_linear_map_pte), + KUNIT_CASE(write_kernel_vmalloc_pte), + KUNIT_CASE(write_user_pmd), + {} +}; + +static struct kunit_suite kpkeys_hardened_pgtables_test_suite = { + .name = "Hardened pgtables using kpkeys", + .test_cases = kpkeys_hardened_pgtables_test_cases, +}; +kunit_test_suite(kpkeys_hardened_pgtables_test_suite); + +MODULE_DESCRIPTION("Tests for the kpkeys_hardened_pgtables feature"); +MODULE_LICENSE("GPL"); diff --git a/security/Kconfig.hardening b/security/Kconfig.hardening index c2b0987768ca..cc3458510e97 100644 --- a/security/Kconfig.hardening +++ b/security/Kconfig.hardening @@ -346,6 +346,18 @@ config KPKEYS_HARDENED_PGTABLES This option has no effect if the system does not support kernel pkeys. +config KPKEYS_HARDENED_PGTABLES_KUNIT_TEST + tristate "KUnit tests for kpkeys_hardened_pgtables" if !KUNIT_ALL_TESTS + depends on KPKEYS_HARDENED_PGTABLES + depends on KUNIT + default KUNIT_ALL_TESTS + help + Enable this option to check that the kpkeys_hardened_pgtables feature + functions as intended, i.e. prevents arbitrary writes to user and + kernel page tables. + + If unsure, say N. + endmenu config CC_HAS_RANDSTRUCT