Re: [PATCH 5/5] mm/mprotect: use huge_ptep_get() for hugetlb
From: Muchun Song
Date: Thu Jun 25 2026 - 23:40:39 EST
On 2026/6/25 19:29, Dev Jain wrote:
prot_none_hugetlb_entry() is the hugetlb callback for the early
mprotect(PROT_NONE) PFN permission walk on x86.
The callback passes the decoded PFN to pfn_modify_allowed(). For a
hugetlb callback, the pte pointer refers to a hugetlb entry. On
architectures where hugetlb entries need huge_ptep_get(), reading that
entry with ptep_get() can make the permission check use the wrong PFN.
Use huge_ptep_get() before decoding the hugetlb PFN.
Currently there is no path which can trigger a bug: huge_ptep_get() is a
simple ptep_get() for x86, and the prot_none walk occurs only for x86.
But use the correct helper anyways.
Fixes: 42e4089c7890 ("x86/speculation/l1tf: Disallow non privileged high MMIO PROT_NONE mappings")
Signed-off-by: Dev Jain <dev.jain@xxxxxxx>
---
mm/mprotect.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/mm/mprotect.c b/mm/mprotect.c
index 9cbf932b028cf..23779632d18bf 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -699,14 +699,20 @@ static int prot_none_pte_entry(pte_t *pte, unsigned long addr,
0 : -EACCES;
}
+#ifdef CONFIG_HUGETLB_PAGE
static int prot_none_hugetlb_entry(pte_t *pte, unsigned long hmask,
unsigned long addr, unsigned long next,
struct mm_walk *walk)
{
- return pfn_modify_allowed(pte_pfn(ptep_get(pte)),
+ pte_t entry = huge_ptep_get(walk->mm, addr, pte);
+
+ return pfn_modify_allowed(pte_pfn(entry),
*(pgprot_t *)(walk->private)) ?
0 : -EACCES;
}
+#else
+#define prot_none_hugetlb_entry NULL
This is very strange, because we defined a stub as NULL for a helper
function. How about the following diff?
diff --git a/mm/mprotect.c b/mm/mprotect.c
index 9cbf932b028c..4d8c1551fbce 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -716,7 +716,9 @@ static int prot_none_test(unsigned long addr, unsigned long next,
static const struct mm_walk_ops prot_none_walk_ops = {
.pte_entry = prot_none_pte_entry,
+#ifdef CONFIG_HUGETLB_PAGE
.hugetlb_entry = prot_none_hugetlb_entry,
+#endif
.test_walk = prot_none_test,
.walk_lock = PGWALK_WRLOCK,
};
Thanks,
Muchun
+#endif
static int prot_none_test(unsigned long addr, unsigned long next,
struct mm_walk *walk)