Re: [PATCH] mm/vma: avoid broken uffd merge on mremap

From: David Hildenbrand (Arm)

Date: Tue Oct 20 2026 - 11:56:15 EST


On 10/20/26 16:55, Lorenzo Stoakes (ARM) wrote:
> Userfaultfd often causes unexpected interactions within mm, and does so at
> the intersection of uffd, mremap() and VMA merging.
>
> When an mremap of a VMA occurs, copy_vma_and_data() calls
> mremap_userfaultfd_prep() to notify uffd of this.
>
> However, mremap_userfaultfd_prep() simply drops the UFFD context for the
> VMA if the user did not register it for remap, i.e. didn't specify the
> UFFD_FEATURE_EVENT_REMAP flag.
>
> This is OK for the VMA itself, as upon page table move, move_ptes() clears
> UFFD page table flags, using vma_has_uffd_without_event_remap() to
> determine whether to do so.
>
> However, this doesn't account for merging with adjacent VMAs, whose page
> tables won't have received this treatment, and thus latent UFFD markers
> will be left around.
>
> Worse, it'll break UFFD for any VMAs it is merged with. This is very
> surprising behaviour for a user, who will then simply not receive UFFD
> events for VMAs they ought to.
>
> Resolve the issue by explicitly checking for this case via
> vma_has_uffd_without_event_remap() in vma_merge_copied_range(), the merge
> function explicitly designated for mremap() operations.
>
> Also update the userland VMA tests accordingly.
>
> Reported-by: shaos <shawnq1@xxxxxxx>
> Closes: https://lore.kernel.org/all/20261020110748.959870-1-shawnq1@xxxxxxx/
> Fixes: 3cfd22be0ad6 ("userfaultfd: clear flag if remap event not enabled")
> Cc: stable@xxxxxxxxxxxxxxx
> Signed-off-by: Lorenzo Stoakes (ARM) <ljs@xxxxxxxxxx>
> ---
> mm/vma.c | 5 +++++
> tools/testing/vma/include/stubs.h | 5 +++++
> 2 files changed, 10 insertions(+)
>
> diff --git a/mm/vma.c b/mm/vma.c
> index de5ebc57e7a5..1be613044b4a 100644
> --- a/mm/vma.c
> +++ b/mm/vma.c
> @@ -1211,6 +1211,11 @@ static struct vm_area_struct *vma_merge_copied_range(struct vma_merge_struct *vm
>
> vmg->copied_from = vmg->middle;
> vmg->middle = NULL;
> +
> + /* If not registered for remap, uffd context will be cleared. */
> + if (vma_has_uffd_without_event_remap(vmg->copied_from))
> + return NULL;
> +
> return vma_merge_new_range(vmg);
> }
>
> diff --git a/tools/testing/vma/include/stubs.h b/tools/testing/vma/include/stubs.h
> index be8f5161f92a..f786a585caf0 100644
> --- a/tools/testing/vma/include/stubs.h
> +++ b/tools/testing/vma/include/stubs.h
> @@ -386,6 +386,11 @@ static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
> return true;
> }
>
> +static inline bool vma_has_uffd_without_event_remap(struct vm_area_struct *vma)
> +{
> + return false;
> +}
> +
> static inline bool anon_vma_name_eq(struct anon_vma_name *anon_name1,
> struct anon_vma_name *anon_name2)
> {
>

@Kiryl that should solve the issue I was raising the other day with leftover
uffd PTE bits outside of uffd areas? Can you review?

--
Cheers,

David