From 809cbe72ace890f75a9b126eb6a8b533081666d8 Mon Sep 17 00:00:00 2001 From: "David Hildenbrand (Arm)" Date: Thu, 22 Oct 2026 11:45:42 +0800 Subject: [PATCH] mm/hugetlb: disable PMD sharing for UFFD missing mode For UFFDIO_POISON to install a poison marker in a hugetlb mapping, it is sufficient to have the VMA registered for missing mode. However, UFFD missing mode does currently not block PMD table sharing, so installing the marker will be visible to everyone using the shared PMD table, which is wrong as UFFDIO_POISON must stay local to the process. To fix it, make uffd_disable_huge_pmd_share() cover VM_UFFD_MISSING as well. With missing mode covered, hugetlb PMD sharing is disabled for all userfaultfd registered VMAs, so the helper can simply return whether the VMA has a userfaultfd context instead of testing individual UFFD mode flags. Add a debug check on the marker installation path. The existing registration path will then unshare PMD tables, and subsequent faults will not share them while the mapping remains registered. The alternative would be to unshare PMD tables selectively when installing poison markers, which results in way more complexity. Or alternatively, simply failing the marker installation, which might break some use cases. This also disables PMD sharing for userfaultfd registrations that never use UFFDIO_POISON. Link: https://lore.kernel.org/20261022034543.51226-3-lizhe.67@bytedance.com Fixes: 8a13897fb0da ("mm: userfaultfd: support UFFDIO_POISON for hugetlbfs") Signed-off-by: David Hildenbrand (Arm) Signed-off-by: Li Zhe Signed-off-by: Andrew Morton Suggested-by: Li Zhe Suggested-by: Mike Rapoport Acked-by: Mike Rapoport (Microsoft) Cc: Muchun Song Cc: Oscar Salvador Cc: Peter Xu Cc: Jose A. Perez de Azpillaga --- include/linux/userfaultfd_k.h | 16 +++------------- mm/hugetlb.c | 1 + 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h index a14b8a9ffb7b..ebd86677b052 100644 --- a/include/linux/userfaultfd_k.h +++ b/include/linux/userfaultfd_k.h @@ -168,22 +168,12 @@ static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma, } /* - * Never enable huge pmd sharing on some uffd registered vmas: - * - * - VM_UFFD_WP and VM_UFFD_RWP VMAs, because the write protect / access - * tracking information is per pgtable entry. - * - * - VM_UFFD_MINOR VMAs, because otherwise we would never get minor faults for - * VMAs which share huge pmds. (If you have two mappings to the same - * underlying pages, and fault in the non-UFFD-registered one with a write, - * with huge pmd sharing this would *also* setup the second UFFD-registered - * mapping, and we'd not get minor faults.) + * Never enable huge pmd sharing on userfaultfd registered VMAs, because + * userfaultfd state can be tracked per VMA or per page table entry. */ static inline bool uffd_disable_huge_pmd_share(struct vm_area_struct *vma) { - return vma_test_any_mask(vma, - mk_vma_flags_from_masks(VMA_UFFD_WP, VMA_UFFD_RWP, - VMA_UFFD_MINOR)); + return vma->vm_userfaultfd_ctx.ctx; } /* diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 506729ebaee7..8995f4cc4e65 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -6388,6 +6388,7 @@ int hugetlb_mfill_atomic_pte(pte_t *dst_pte, return -EEXIST; } + VM_WARN_ON_ONCE(size == PMD_SIZE && hugetlb_pmd_shared(dst_pte)); _dst_pte = make_pte_marker(PTE_MARKER_POISONED); set_huge_pte_at(dst_mm, dst_addr, dst_pte, _dst_pte, size);