From f6605fc6b14bd5fc0fea90fc8226573adcec352b Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Thu, 15 Oct 2026 18:07:15 +0200 Subject: [PATCH] mm/hugetlb: don't leave a uffd-wp marker when zapping an RWP entry An entry that is protected with UFFDIO_RWPROTECT is PAGE_NONE with the uffd bit set, the bit that userfaultfd write protection uses too. When __unmap_hugepage_range() zaps an entry with that bit it leaves a PTE_MARKER_UFFD_WP behind, whatever the VMA is registered for. In a VMA registered with UFFDIO_REGISTER_MODE_RWP that marker means nothing. The next fault has hugetlb_no_page() turn it into a present, read-only entry with the uffd bit. That is not an RWP entry, since it is not PAGE_NONE, and the VMA has no VM_UFFD_WP (the two modes can not be registered together). An earlier fix solved some side effects, now just stop the zap from wrongly installing a marker. Leave a marker only if the VMA is registered for write protection, both for present and for non-present entries. The zap of ordinary page tables has the same test, in cond_install_uffd_wp_ptes(), and hugetlb_change_protection() says that "uffd_rwp does not install markers". After a zap the range of an RWP VMA is simply empty, as it is for anonymous memory and shmem. Nothing changes for VMAs with VM_UFFD_WP. In a VMA that is not registered at all a leftover uffd bit or marker is now dropped by the zap and no longer kept alive. Original fix generated by an LLM and sent in private by Josef. [david@kernel.org: a bit of description overhaul+simplification] Link: https://lore.kernel.org/20261015-urgent_fixes-v1-9-42796911043b@kernel.org Fixes: 2d427bb01639 ("mm/userfaultfd: add RWP fault delivery and expose UFFDIO_REGISTER_MODE_RWP") Signed-off-by: Josef Bacik Signed-off-by: David Hildenbrand (Arm) Signed-off-by: Andrew Morton Reported-by: Chris Mason Acked-by: Lorenzo Stoakes (ARM) Reviewed-by: Lance Yang Acked-by: Kiryl Shutsemau (Meta) Cc: Liam R. Howlett Cc: Vlastimil Babka Cc: Jann Horn Cc: Pedro Falcato Cc: Muchun Song Cc: Oscar Salvador Cc: Miaohe Lin Cc: Naoya Horiguchi Cc: Adam Litke Cc: Mel Gorman Cc: Rik van Riel Cc: Peter Xu Cc: Mike Rapoport Cc: --- mm/hugetlb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index c6c45de147d2..a949b446cbea 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -5309,7 +5309,7 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma, * drop the uffd-wp bit in this zap, then replace the * pte with a marker. */ - if (pte_swp_uffd_any(pte) && + if (userfaultfd_wp(vma) && pte_swp_uffd_any(pte) && !(zap_flags & ZAP_FLAG_DROP_MARKER)) set_huge_pte_at(mm, address, ptep, make_pte_marker(PTE_MARKER_UFFD_WP), @@ -5345,7 +5345,7 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma, if (huge_pte_dirty(pte)) folio_mark_dirty(folio); /* Leave a uffd-wp pte marker if needed */ - if (huge_pte_uffd(pte) && + if (userfaultfd_wp(vma) && huge_pte_uffd(pte) && !(zap_flags & ZAP_FLAG_DROP_MARKER)) set_huge_pte_at(mm, address, ptep, make_pte_marker(PTE_MARKER_UFFD_WP),