linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: Brendan Jackman <jackmanb@google.com>
To: jackmanb@google.com, Andy Lutomirski <luto@kernel.org>,
	 Lorenzo Stoakes <lorenzo.stoakes@oracle.com>,
	"Liam R. Howlett" <Liam.Howlett@oracle.com>,
	 Suren Baghdasaryan <surenb@google.com>,
	Michal Hocko <mhocko@suse.com>,
	 Johannes Weiner <hannes@cmpxchg.org>, Zi Yan <ziy@nvidia.com>,
	 Axel Rasmussen <axelrasmussen@google.com>,
	Yuanchu Xie <yuanchu@google.com>,
	 Roman Gushchin <roman.gushchin@linux.dev>
Cc: peterz@infradead.org, bp@alien8.de, dave.hansen@linux.intel.com,
	 mingo@redhat.com, tglx@linutronix.de, akpm@linux-foundation.org,
	 david@redhat.com, derkling@google.com, junaids@google.com,
	 linux-kernel@vger.kernel.org, linux-mm@kvack.org,
	reijiw@google.com,  rientjes@google.com, rppt@kernel.org,
	vbabka@suse.cz, x86@kernel.org,  yosry.ahmed@linux.dev
Subject: [PATCH 19/21] mm/asi: bad_page() when ASI mappings are wrong
Date: Wed, 24 Sep 2025 14:59:54 +0000	[thread overview]
Message-ID: <20250924-b4-asi-page-alloc-v1-19-2d861768041f@google.com> (raw)
In-Reply-To: <20250924-b4-asi-page-alloc-v1-0-2d861768041f@google.com>

Add bad_page() checks that fire when the page allocator thinks a page is
mapped/unmapped in ASI restricted address space, but the pagetables
disagree.

This requires adding an accessor for set_memory.c to walk the page
tables and report the state.

This is implemented with the assumption that the mapping is at pageblock
granularity. That means it doesn't need to be repeated for each order-0
page. As a result of this special order-awareness, it can't go into
free_page_is_bad() and needs to be separately integrated into
free_pages_prepare(). The alloc side is easier - there it just goes into
check_new_pages().

Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
 arch/x86/include/asm/set_memory.h |  3 +++
 arch/x86/mm/pat/set_memory.c      | 31 +++++++++++++++++++++++++++
 include/linux/set_memory.h        |  2 ++
 mm/page_alloc.c                   | 45 ++++++++++++++++++++++++++++++++++-----
 4 files changed, 76 insertions(+), 5 deletions(-)

diff --git a/arch/x86/include/asm/set_memory.h b/arch/x86/include/asm/set_memory.h
index 396580693e7d1317537148c0c219296e2b7c13fd..3870fa8cf51c0ece0dedf4d7876c4d14111deffd 100644
--- a/arch/x86/include/asm/set_memory.h
+++ b/arch/x86/include/asm/set_memory.h
@@ -94,12 +94,15 @@ bool kernel_page_present(struct page *page);
 
 #ifdef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
 int set_direct_map_sensitive(struct page *page, int num_pageblocks, bool sensitive);
+bool direct_map_sensitive(struct page *page);
 #else /* CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION */
 static inline
 int set_direct_map_sensitive(struct page *page, int num_pageblocks, bool sensitive)
 {
 	return 0;
 }
+
+static inline bool direct_map_sensitive(struct page *page) { return false; }
 #endif /* CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION */
 
 extern int kernel_set_to_readonly;
diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
index 88fb65574d4fa0089fa31a9a06fe096c408991e6..d4c3219374f889f9a60c459f0559e5ffb472073d 100644
--- a/arch/x86/mm/pat/set_memory.c
+++ b/arch/x86/mm/pat/set_memory.c
@@ -2721,6 +2721,37 @@ int set_direct_map_sensitive(struct page *page, int num_pageblocks, bool sensiti
 
 	return __change_page_attr_set_clr(&cpa, 1);
 }
+
+/*
+ * Walk the pagetable to check if the page is mapped into all ASI restricted
+ * address spaces.
+ */
+bool direct_map_sensitive(struct page *page)
+{
+	unsigned long addr = (unsigned long)page_address(page);
+	pgd_t *pgd = pgd_offset_pgd(asi_nonsensitive_pgd, addr);
+	unsigned int level;
+	bool nx, rw;
+	pte_t *pte = lookup_address_in_pgd_attr(pgd, addr, &level, &nx, &rw);
+
+	switch (level) {
+	case PG_LEVEL_4K:
+		/*
+		 * lookup_address_in_pgd_attr() still returns the PTE for
+		 * non-present 4K pages.
+		 */
+		return !pte_present(*pte);
+	case PG_LEVEL_2M:
+		/*
+		 * pmd_present() checks PSE to deal with some hugetlb
+		 * logic. That's not relevant for the direct map so just
+		 * explicitly check the real P bit.
+		 */
+		return !(pmd_flags(*(pmd_t *)pte) & _PAGE_PRESENT);
+	default:
+		return !pte;
+	}
+}
 #endif /* CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION */
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
diff --git a/include/linux/set_memory.h b/include/linux/set_memory.h
index db4225c046c47c114293af8b504886b103dc94ce..6f42d6a35feceeae4623c2da50cfac54e3533228 100644
--- a/include/linux/set_memory.h
+++ b/include/linux/set_memory.h
@@ -50,6 +50,8 @@ static inline int set_direct_map_sensitive(struct page *page,
 	return 0;
 }
 
+static inline bool direct_map_sensitive(struct page *page) { return false; }
+
 #else /* CONFIG_ARCH_HAS_SET_DIRECT_MAP */
 /*
  * Some architectures, e.g. ARM64 can disable direct map modifications at
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index a8e3556643b0ff2fe1d35a678937270356006d34..68bc3cc5ed7e7f1adb8dda90edc2e001f9a1c3c5 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -15,6 +15,7 @@
  *          (lots of bits borrowed from Ingo Molnar & Andrew Morton)
  */
 
+#include <linux/asi.h>
 #include <linux/stddef.h>
 #include <linux/mm.h>
 #include <linux/highmem.h>
@@ -1161,6 +1162,33 @@ static const char *page_bad_reason(struct page *page, unsigned long flags)
 	return bad_reason;
 }
 
+static bool page_asi_mapping_bad(struct page *page, unsigned int order, bool sensitive)
+{
+#ifdef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
+	if (asi_enabled_static()) {
+		struct page *block_page = page;
+
+		/*
+		 * ASI mappings are at pageblock granularity. Check they match
+		 * the requested sensitivity.
+		 */
+		while (block_page < page + (1 << order)) {
+			if (direct_map_sensitive(block_page) != sensitive) {
+				bad_page(page,
+					sensitive ?
+					"page unexpectedly nonsensitive" :
+					"page unexpectedly sensitive");
+				return true;
+			}
+
+			block_page += pageblock_nr_pages;
+		}
+	}
+#endif /* CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION */
+
+	return false;
+}
+
 static inline bool free_page_is_bad(struct page *page)
 {
 	if (likely(page_expected_state(page, PAGE_FLAGS_CHECK_AT_FREE)))
@@ -1471,8 +1499,14 @@ __always_inline bool free_pages_prepare(struct page *page,
 		page->page_type = UINT_MAX;
 
 	if (is_check_pages_enabled()) {
+		freetype_t ft = get_pageblock_freetype(page);
+
 		if (free_page_is_bad(page))
 			bad++;
+
+		if (!bad)
+			bad += page_asi_mapping_bad(page, order,
+						    freetype_sensitive(ft));
 		if (bad)
 			return false;
 	}
@@ -1840,7 +1874,8 @@ static bool check_new_page(struct page *page)
 	return true;
 }
 
-static inline bool check_new_pages(struct page *page, unsigned int order)
+static inline bool check_new_pages(struct page *page, unsigned int order,
+				   bool sensitive)
 {
 	if (!is_check_pages_enabled())
 		return false;
@@ -1852,7 +1887,7 @@ static inline bool check_new_pages(struct page *page, unsigned int order)
 			return true;
 	}
 
-	return false;
+	return page_asi_mapping_bad(page, order, sensitive);
 }
 
 static inline bool should_skip_kasan_unpoison(gfp_t flags)
@@ -3393,7 +3428,7 @@ struct page *rmqueue_buddy(struct zone *preferred_zone, struct zone *zone,
 		if (!page)
 			return NULL;
 
-	} while (check_new_pages(page, order));
+	} while (check_new_pages(page, order, freetype_sensitive(freetype)));
 
 	__count_zid_vm_events(PGALLOC, page_zonenum(page), 1 << order);
 	zone_statistics(preferred_zone, zone, 1);
@@ -3478,7 +3513,7 @@ struct page *__rmqueue_pcplist(struct zone *zone, unsigned int order,
 		page = list_first_entry(list, struct page, pcp_list);
 		list_del(&page->pcp_list);
 		pcp->count -= 1 << order;
-	} while (check_new_pages(page, order));
+	} while (check_new_pages(page, order, freetype_sensitive(freetype)));
 
 	return page;
 }
@@ -7231,7 +7266,7 @@ int alloc_contig_range_noprof(unsigned long start, unsigned long end,
 	} else if (start == outer_start && end == outer_end && is_power_of_2(end - start)) {
 		struct page *head = pfn_to_page(start);
 
-		check_new_pages(head, order);
+		check_new_pages(head, order, gfp_mask & __GFP_SENSITIVE);
 		prep_new_page(head, order, gfp_mask, 0);
 		set_page_refcounted(head);
 	} else {

-- 
2.50.1



  parent reply	other threads:[~2025-09-24 15:01 UTC|newest]

Thread overview: 65+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-09-24 14:59 [PATCH 00/21] mm: ASI direct map management Brendan Jackman
2025-09-24 14:59 ` [PATCH 01/21] x86/mm/asi: Add CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION Brendan Jackman
2025-10-24 22:37   ` Borislav Petkov
2025-10-24 23:32     ` Brendan Jackman
2025-10-25  9:57       ` Borislav Petkov
2025-09-24 14:59 ` [PATCH 02/21] x86/mm/asi: add X86_FEATURE_ASI and asi= Brendan Jackman
2025-10-25 10:06   ` Borislav Petkov
2025-10-26 22:24     ` Brendan Jackman
2025-11-10 11:26       ` Borislav Petkov
2025-11-10 12:15         ` Brendan Jackman
2025-09-24 14:59 ` [PATCH 03/21] x86/mm: factor out phys_pgd_init() Brendan Jackman
2025-09-27 19:29   ` kernel test robot
2025-10-01 12:26     ` Brendan Jackman
2025-10-25 11:48   ` Borislav Petkov
2025-10-26 22:29     ` Brendan Jackman
2025-11-10 11:38       ` Borislav Petkov
2025-11-10 12:36         ` Brendan Jackman
2025-09-24 14:59 ` [PATCH 04/21] x86/mm/asi: set up asi_nonsensitive_pgd Brendan Jackman
2025-10-01 20:28   ` Dave Hansen
2025-10-02 14:05     ` Brendan Jackman
2025-10-02 16:14       ` Dave Hansen
2025-10-02 17:19         ` Brendan Jackman
2025-11-12 19:39           ` Dave Hansen
2025-11-11 14:55   ` Borislav Petkov
2025-11-11 17:53     ` Brendan Jackman
2025-09-24 14:59 ` [PATCH 05/21] x86/mm/pat: mirror direct map changes to ASI Brendan Jackman
2025-09-25 13:36   ` kernel test robot
2025-10-01 20:50   ` Dave Hansen
2025-10-02 14:31     ` Brendan Jackman
2025-10-02 16:40       ` Dave Hansen
2025-10-02 17:08         ` Brendan Jackman
2025-09-24 14:59 ` [PATCH 06/21] mm/page_alloc: add __GFP_SENSITIVE and always set it Brendan Jackman
2025-10-01 21:18   ` Dave Hansen
2025-10-02 14:34     ` Brendan Jackman
2025-09-24 14:59 ` [PATCH 07/21] mm: introduce for_each_free_list() Brendan Jackman
2025-09-24 14:59 ` [PATCH 08/21] mm: rejig pageblock mask definitions Brendan Jackman
2025-09-24 14:59 ` [PATCH 09/21] mm/page_alloc: Invert is_check_pages_enabled() check Brendan Jackman
2025-09-24 14:59 ` [PATCH 10/21] mm/page_alloc: remove ifdefs from pindex helpers Brendan Jackman
2025-09-24 14:59 ` [PATCH 11/21] mm: introduce freetype_t Brendan Jackman
2025-09-25 13:15   ` kernel test robot
2025-10-01 21:20   ` Dave Hansen
2025-10-02 14:39     ` Brendan Jackman
2025-09-24 14:59 ` [PATCH 12/21] mm/asi: encode sensitivity in freetypes and pageblocks Brendan Jackman
2025-09-24 14:59 ` [PATCH 13/21] mm/page_alloc_test: unit test pindex helpers Brendan Jackman
2025-09-25 13:36   ` kernel test robot
2025-09-24 14:59 ` [PATCH 14/21] x86/mm/pat: introduce cpa_fault option Brendan Jackman
2025-09-24 14:59 ` [PATCH 15/21] mm/page_alloc: rename ALLOC_NON_BLOCK back to _HARDER Brendan Jackman
2025-09-24 14:59 ` [PATCH 16/21] mm/page_alloc: introduce ALLOC_NOBLOCK Brendan Jackman
2025-09-24 14:59 ` [PATCH 17/21] mm/slub: defer application of gfp_allowed_mask Brendan Jackman
2025-09-24 14:59 ` [PATCH 18/21] mm/asi: support changing pageblock sensitivity Brendan Jackman
2025-09-24 14:59 ` Brendan Jackman [this message]
2025-09-24 14:59 ` [PATCH 20/21] x86/mm/asi: don't use global pages when ASI enabled Brendan Jackman
2025-09-24 14:59 ` [PATCH 21/21] mm: asi_test: smoke test for [non]sensitive page allocs Brendan Jackman
2025-09-25 17:51 ` [PATCH 00/21] mm: ASI direct map management Brendan Jackman
2025-09-30 19:51 ` Konrad Rzeszutek Wilk
2025-10-01  7:12   ` Brendan Jackman
2025-10-01 19:54 ` Dave Hansen
2025-10-01 20:22   ` Yosry Ahmed
2025-10-01 20:30     ` Dave Hansen
2025-10-02 11:05       ` Brendan Jackman
2025-10-01 20:59 ` Dave Hansen
2025-10-02  7:34   ` David Hildenbrand
2025-10-02 11:23   ` Brendan Jackman
2025-10-02 17:01     ` Dave Hansen
2025-10-02 19:19       ` Brendan Jackman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250924-b4-asi-page-alloc-v1-19-2d861768041f@google.com \
    --to=jackmanb@google.com \
    --cc=Liam.Howlett@oracle.com \
    --cc=akpm@linux-foundation.org \
    --cc=axelrasmussen@google.com \
    --cc=bp@alien8.de \
    --cc=dave.hansen@linux.intel.com \
    --cc=david@redhat.com \
    --cc=derkling@google.com \
    --cc=hannes@cmpxchg.org \
    --cc=junaids@google.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=lorenzo.stoakes@oracle.com \
    --cc=luto@kernel.org \
    --cc=mhocko@suse.com \
    --cc=mingo@redhat.com \
    --cc=peterz@infradead.org \
    --cc=reijiw@google.com \
    --cc=rientjes@google.com \
    --cc=roman.gushchin@linux.dev \
    --cc=rppt@kernel.org \
    --cc=surenb@google.com \
    --cc=tglx@linutronix.de \
    --cc=vbabka@suse.cz \
    --cc=x86@kernel.org \
    --cc=yosry.ahmed@linux.dev \
    --cc=yuanchu@google.com \
    --cc=ziy@nvidia.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox