[PATCH RFC v3 20/21] mm/pgtable: disallow calling folded set_pgd/set_p4d/set_pud with dummy
From: Yeoreum Yun
Date: Wed Sep 02 2026 - 08:42:29 EST
From: "David Hildenbrand (Arm)" <david@xxxxxxxxxx>
pXdp_get() could return a dummy value for a page-table level folded at
compile time. Passing this value to set_pXd() could cause unexpected
behavior.
Prevent this at compile time by ensuring that all calls to
set_pgd()/set_p4d()/set_pud() are compiled out for folded page-table
levels. Make the compiler complain if these helpers are called with
dummy values.
Since there are places where set_pXd() is called even when
the corresponding page-table level is folded at compile time,
drop the incorrect comments for set_pXd().
Signed-off-by: David Hildenbrand (Arm) <david@xxxxxxxxxx>
Co-developed-by: Yeoreum Yun <yeoreum.yun@xxxxxxx>
Signed-off-by: Yeoreum Yun <yeoreum.yun@xxxxxxx>
---
include/asm-generic/pgtable-nop4d.h | 11 ++++++-----
include/asm-generic/pgtable-nopmd.h | 10 +++++-----
include/asm-generic/pgtable-nopud.h | 12 +++++++-----
3 files changed, 18 insertions(+), 15 deletions(-)
diff --git a/include/asm-generic/pgtable-nop4d.h b/include/asm-generic/pgtable-nop4d.h
index d2dccf7542da..12b01768134b 100644
--- a/include/asm-generic/pgtable-nop4d.h
+++ b/include/asm-generic/pgtable-nop4d.h
@@ -28,11 +28,12 @@ static inline bool pgd_leaf(pgd_t pgd) { return false; }
#define pgd_populate(mm, pgd, p4d) do { } while (0)
#define pgd_populate_safe(mm, pgd, p4d) do { } while (0)
-/*
- * (p4ds are folded into pgds so this doesn't get actually called,
- * but the define is needed for a generic inline function.)
- */
-#define set_pgd(pgdptr, pgdval) set_p4d((p4d_t *)(pgdptr), (p4d_t) { pgdval })
+
+#define set_pgd(pgdptr, pgdval) \
+({ \
+ pgd_check_dummy(pgdval); \
+ set_p4d((p4d_t *)(pgdptr), (p4d_t) { pgdval }); \
+})
static __always_inline pgd_t pgdp_get(pgd_t *pgdp)
{
diff --git a/include/asm-generic/pgtable-nopmd.h b/include/asm-generic/pgtable-nopmd.h
index 2afbf2d8659d..11b04c107129 100644
--- a/include/asm-generic/pgtable-nopmd.h
+++ b/include/asm-generic/pgtable-nopmd.h
@@ -37,11 +37,11 @@ static inline void pud_clear(pud_t *pud) { }
#define pud_populate(mm, pmd, pte) do { } while (0)
-/*
- * (pmds are folded into puds so this doesn't get actually called,
- * but the define is needed for a generic inline function.)
- */
-#define set_pud(pudptr, pudval) set_pmd((pmd_t *)(pudptr), (pmd_t) { pudval })
+#define set_pud(pudptr, pudval) \
+({ \
+ pud_check_dummy(pudval); \
+ set_pmd((pmd_t *)(pudptr), (pmd_t) { pudval }); \
+})
static __always_inline pud_t pudp_get(pud_t *pudp)
{
diff --git a/include/asm-generic/pgtable-nopud.h b/include/asm-generic/pgtable-nopud.h
index 3264673c0c38..5ee8f1852cd8 100644
--- a/include/asm-generic/pgtable-nopud.h
+++ b/include/asm-generic/pgtable-nopud.h
@@ -35,11 +35,13 @@ static inline bool p4d_leaf(p4d_t p4d) { return false; }
#define p4d_populate(mm, p4d, pud) do { } while (0)
#define p4d_populate_safe(mm, p4d, pud) do { } while (0)
-/*
- * (puds are folded into p4ds so this doesn't get actually called,
- * but the define is needed for a generic inline function.)
- */
-#define set_p4d(p4dptr, p4dval) set_pud((pud_t *)(p4dptr), (pud_t) { p4dval })
+
+#define set_p4d(p4dptr, p4dval) \
+({ \
+ p4d_check_dummy(p4dval); \
+ set_pud((pud_t *)(p4dptr), (pud_t) { p4dval }); \
+})
+
static __always_inline p4d_t p4dp_get(p4d_t *p4dp)
{
--
2.43.0