From: "Kiryl Shutsemau (Meta)" <[email protected]>

make_uffd_wp_huge_pte() arms the UFFD_WP bit on a present HugeTLB PTE by
calling huge_ptep_modify_prot_commit() with a ptent snapshot that was
fetched without the corresponding huge_ptep_modify_prot_start(). The
start helper is what atomically clears the entry so the kernel-owned
snapshot stays consistent until the commit; without it, the hardware
may set Dirty or Accessed in the live PTE between the original read
and the commit, and huge_ptep_modify_prot_commit() (whose generic
implementation just calls set_huge_pte_at()) then writes the stale
snapshot back over the live hardware bits, losing the update.

The non-hugetlb sibling make_uffd_wp_pte() does this correctly via
ptep_modify_prot_start() / ptep_modify_prot_commit(). Mirror that
pattern for the present-PTE branch. The migration case stays as-is --
migration entries are non-present, so there's no hardware update to
race against.

Fixes: 52526ca7fdb9 ("fs/proc/task_mmu: implement IOCTL to get and optionally 
clear info about PTEs")
Cc: [email protected]
Reported-by: Sashiko AI review <[email protected]>
Signed-off-by: Kiryl Shutsemau <[email protected]>
---
 fs/proc/task_mmu.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 1e3a15bf46f4..e21a38ac745b 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -2610,12 +2610,16 @@ static void make_uffd_wp_huge_pte(struct vm_area_struct 
*vma,
        if (softleaf_is_hwpoison(entry) || softleaf_is_marker(entry))
                return;
 
-       if (softleaf_is_migration(entry))
+       if (softleaf_is_migration(entry)) {
                set_huge_pte_at(vma->vm_mm, addr, ptep,
                                pte_swp_mkuffd_wp(ptent), psize);
-       else
-               huge_ptep_modify_prot_commit(vma, addr, ptep, ptent,
-                                            huge_pte_mkuffd_wp(ptent));
+       } else {
+               pte_t old_pte, new_pte;
+
+               old_pte = huge_ptep_modify_prot_start(vma, addr, ptep);
+               new_pte = huge_pte_mkuffd_wp(old_pte);
+               huge_ptep_modify_prot_commit(vma, addr, ptep, old_pte, new_pte);
+       }
 }
 #endif /* CONFIG_HUGETLB_PAGE */
 
-- 
2.54.0


Reply via email to