From mboxrd@z Thu Jan 1 00:00:00 1970 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 61570C02196 for ; Mon, 3 Feb 2025 10:20:55 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 9CA8B28001A; Mon, 3 Feb 2025 05:20:51 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 95153280017; Mon, 3 Feb 2025 05:20:51 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 50AE228001A; Mon, 3 Feb 2025 05:20:51 -0500 (EST) 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 1D2CC280018 for ; Mon, 3 Feb 2025 05:20:51 -0500 (EST) Received: from smtpin12.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay09.hostedemail.com (Postfix) with ESMTP id F3853825A5 for ; Mon, 3 Feb 2025 10:20:14 +0000 (UTC) X-FDA: 83078238432.12.97C9D4E Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by imf30.hostedemail.com (Postfix) with ESMTP id 5C75C80002 for ; Mon, 3 Feb 2025 10:20:13 +0000 (UTC) Authentication-Results: imf30.hostedemail.com; dkim=none; dmarc=pass (policy=none) header.from=arm.com; spf=pass (imf30.hostedemail.com: domain of kevin.brodsky@arm.com designates 217.140.110.172 as permitted sender) smtp.mailfrom=kevin.brodsky@arm.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1738578013; 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=hMHebzscLOUd5of8jcCqK/oKCbj1tqbVmE+gDk9lCiQ=; b=5Lwtd538c5cSeXpG5013fTfo7FwHMgUgFO5cBzwRsenYV6HNhMyEs/yEYfUaFRQYatoDWg /EyJnCuF2cbHdwfFcoOC5cWHuPQxVlI/kNwHWFwCkh/7XZBm8B7kyZ1zDsx7YHdzl5CtQN i9r3Yj7vTg4/oLpQe4p1iU4k9AcTv4A= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1738578013; a=rsa-sha256; cv=none; b=ItrhavKfhfgEm6e0jTjf9QU/Drl7lEa0nUX9CHDWzmX/f310oVWo6IONw1W9dQ2Z0mMPLq DjqdSZkG6GiOwz1OYrxrdkFlD/nAGZZLyztG4uJ8/2Uf5PrbhMNIQiIL58b6TbJ9D5Vp+s H+IP7XqwKd6vdZmGUl+sx0H83Mx2Yqk= ARC-Authentication-Results: i=1; imf30.hostedemail.com; dkim=none; dmarc=pass (policy=none) header.from=arm.com; spf=pass (imf30.hostedemail.com: domain of kevin.brodsky@arm.com designates 217.140.110.172 as permitted sender) smtp.mailfrom=kevin.brodsky@arm.com 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 0F1A111FB; Mon, 3 Feb 2025 02:20:37 -0800 (PST) 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 1D2BF3F63F; Mon, 3 Feb 2025 02:20:08 -0800 (PST) From: Kevin Brodsky To: linux-hardening@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Kevin Brodsky , Andrew Morton , Mark Brown , Catalin Marinas , Dave Hansen , Jann Horn , Jeff Xu , Joey Gouly , Kees Cook , Linus Walleij , Andy Lutomirski , Marc Zyngier , Peter Zijlstra , Pierre Langlois , Quentin Perret , "Mike Rapoport (IBM)" , Ryan Roberts , Thomas Gleixner , Will Deacon , Matthew Wilcox , Qi Zheng , linux-arm-kernel@lists.infradead.org, linux-mm@kvack.org, x86@kernel.org Subject: [RFC PATCH v3 08/15] mm: Introduce kernel_pgtables_set_pkey() Date: Mon, 3 Feb 2025 10:18:32 +0000 Message-ID: <20250203101839.1223008-9-kevin.brodsky@arm.com> X-Mailer: git-send-email 2.47.0 In-Reply-To: <20250203101839.1223008-1-kevin.brodsky@arm.com> References: <20250203101839.1223008-1-kevin.brodsky@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Stat-Signature: nj73oh8tesptedm5edix9q3c9b5p15ux X-Rspam-User: X-Rspamd-Queue-Id: 5C75C80002 X-Rspamd-Server: rspam03 X-HE-Tag: 1738578013-437478 X-HE-Meta: U2FsdGVkX19VB0X6qe5p5XM0aVHjUmk1pbdQ+mf+2hFl5wzklhlCtewk7sWsBtiQu8a8H9ElTbVXi9oowe6SpSR5Nnaswd16yckZy4l6oTmkctZftrovoPMg/eHoz54my5ECD/pUwBCVOnUvVffAf6h01rSIE8URpTBPW2+Vp/8pr83KwR8wFVY+28cSdIJNEpYKc9e6bR0yjGh0nhXRTnzVwcxzFLDORP9W+twv/915vhEVKaDduvv27Md57H5HG8lah9bidXkpWUGlAzVm1FegHcrNP6YoZK8RSSWrMFA15nVNodE0X6XerRhK1ISdLOIkPsxP8MM+S9iZYMYwUBVsCgK40RfV8V77CP0ummEACrvf7RBYDeZR7+Wi+lDL/MR4drYTk/p7BZoXmnWqziEps77yJ8qiMQJtmJ9RqaTK73KM4VChirp4B5SxyOB5YyGWQsL8c/uXkmZCGuI1iFJBRSmvbPGLYcF4AcwWlbP16X6JbuH7cA+62s/XiQFffyfJixZ18dmfITWxGEGiY5jbNITxaJHNniw4/zof/NZBBpmZrInJ8TsfQsQ5jxwQmcLOTqxQdb+pJTmwJh8j9OrDsjTmrD6nrxy4BR922wKIDJbAXuL6hvHLoibO0fyOs2wo7yoRzXSZ9oyX70WjAea80AuqPZqjOPDJ03sbOG+VisV3ufDqJUQp3uchIau9HGqMZp0+sdXs2c217mTPboLatRXjtHjcMtrUthLPhgKgfUFPuYh2KjIJUa83x7KGZ1UEb6sullpNHeigAZQlgc0tjqIhMPTrQvglwFma8vg1w1/SE6ArvGMUSyphg+W2wOPO65sQkuxQ3k1xOizUoTLa7iABimaWKuA4z4RlZW0M2EEZvLVgLa+4mwJS7GFCG0T1N1CvxlsWF64mD/6VckzGPgrGPV4S+Rq6cEuVQG91VF1wndvSysvUZuZ5p/1X0X4h3Pty7hxs8I37Z+p Jh9DkjHT Kl8tG2yzUlTyPLkb3f5wRFQug2g9/BK88aLV8a9Mj7UvlwiNXM7bFa53u8vT5vdlCAYOva2nWtxpDCNTU6eFZ06UcwJoB9Hx1hGzY+ucwhcBli+8QoqkUgAIwvpcgSrWFPWlEI59Nok6fAWF9iVS1xBEmNx7UmY1AYcNanfKObfKuOaLIqebNnNDAll111ju6j5X658Hxoc4L++0= 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: kernel_pgtables_set_pkey() allows setting the pkey of all page table pages in swapper_pg_dir, recursively. This will be needed by kpkeys_hardened_pgtables, as it relies on all PTPs being mapped with a non-default pkey. Those initial kernel page tables cannot practically be assigned a non-default pkey right when they are allocated, so mutating them during (early) boot is required. Signed-off-by: Kevin Brodsky --- include/linux/mm.h | 2 + mm/memory.c | 137 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+) diff --git a/include/linux/mm.h b/include/linux/mm.h index 7b1068ddcbb7..c3998b78f6a5 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -4155,4 +4155,6 @@ int arch_get_shadow_stack_status(struct task_struct *t, unsigned long __user *st int arch_set_shadow_stack_status(struct task_struct *t, unsigned long status); int arch_lock_shadow_stack_status(struct task_struct *t, unsigned long status); +int kernel_pgtables_set_pkey(int pkey); + #endif /* _LINUX_MM_H */ diff --git a/mm/memory.c b/mm/memory.c index 539c0f7c6d54..1386b9cfb459 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -77,6 +77,8 @@ #include #include #include +#include +#include #include @@ -7066,3 +7068,138 @@ void vma_pgtable_walk_end(struct vm_area_struct *vma) if (is_vm_hugetlb_page(vma)) hugetlb_vma_unlock_read(vma); } + +static int set_page_pkey(void *p, int pkey) +{ + unsigned long addr = (unsigned long)p; + + /* + * swapper_pg_dir itself will be made read-only by mark_rodata_ro() + * so there is no point in changing its pkey. + */ + if (p == swapper_pg_dir) + return 0; + + return set_memory_pkey(addr, 1, pkey); +} + +static int set_pkey_pte(pmd_t *pmd, int pkey) +{ + pte_t *pte; + int err; + + pte = pte_offset_kernel(pmd, 0); + err = set_page_pkey(pte, pkey); + + return err; +} + +static int set_pkey_pmd(pud_t *pud, int pkey) +{ + pmd_t *pmd; + int i, err = 0; + + pmd = pmd_offset(pud, 0); + + err = set_page_pkey(pmd, pkey); + if (err) + return err; + + for (i = 0; i < PTRS_PER_PMD; i++) { + if (pmd_none(pmd[i]) || pmd_bad(pmd[i]) || pmd_leaf(pmd[i])) + continue; + err = set_pkey_pte(&pmd[i], pkey); + if (err) + break; + } + + return err; +} + +static int set_pkey_pud(p4d_t *p4d, int pkey) +{ + pud_t *pud; + int i, err = 0; + + if (mm_pmd_folded(&init_mm)) + return set_pkey_pmd((pud_t *)p4d, pkey); + + pud = pud_offset(p4d, 0); + + err = set_page_pkey(pud, pkey); + if (err) + return err; + + for (i = 0; i < PTRS_PER_PUD; i++) { + if (pud_none(pud[i]) || pud_bad(pud[i]) || pud_leaf(pud[i])) + continue; + err = set_pkey_pmd(&pud[i], pkey); + if (err) + break; + } + + return err; +} + +static int set_pkey_p4d(pgd_t *pgd, int pkey) +{ + p4d_t *p4d; + int i, err = 0; + + if (mm_pud_folded(&init_mm)) + return set_pkey_pud((p4d_t *)pgd, pkey); + + p4d = p4d_offset(pgd, 0); + + err = set_page_pkey(p4d, pkey); + if (err) + return err; + + for (i = 0; i < PTRS_PER_P4D; i++) { + if (p4d_none(p4d[i]) || p4d_bad(p4d[i]) || p4d_leaf(p4d[i])) + continue; + err = set_pkey_pud(&p4d[i], pkey); + if (err) + break; + } + + return err; +} + +/** + * kernel_pgtables_set_pkey - set pkey for all kernel page table pages + * @pkey: pkey to set the page table pages to + * + * Walks swapper_pg_dir setting the protection key of every page table page (at + * all levels) to @pkey. swapper_pg_dir itself is left untouched as it is + * expected to be mapped read-only by mark_rodata_ro(). + * + * No-op if the architecture does not support kpkeys. + */ +int kernel_pgtables_set_pkey(int pkey) +{ + pgd_t *pgd = swapper_pg_dir; + int i, err = 0; + + if (!arch_kpkeys_enabled()) + return 0; + + spin_lock(&init_mm.page_table_lock); + + if (mm_p4d_folded(&init_mm)) { + err = set_pkey_p4d(pgd, pkey); + goto out; + } + + for (i = 0; i < PTRS_PER_PGD; i++) { + if (pgd_none(pgd[i]) || pgd_bad(pgd[i]) || pgd_leaf(pgd[i])) + continue; + err = set_pkey_p4d(&pgd[i], pkey); + if (err) + break; + } + +out: + spin_unlock(&init_mm.page_table_lock); + return err; +} -- 2.47.0