mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: "Jose A. Perez de Azpillaga" <azpijr@gmail.com>
To: "Mike Rapoport (Microsoft)" <rppt@kernel.org>,
	Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Xu <peterx@redhat.com>,
	linux-mm@kvack.org, linux-kernel@vger.kernel.org,
	stable@vger.kernel.org
Subject: Re: [PATCH] userfaultfd: clear uffd state in child PTEs if uffd is released during fork
Date: Sat, 31 Oct 2026 14:40:16 +0100	[thread overview]
Message-ID: <2c132a52-1118-4773-866b-a8c713c4933e@gmail.com> (raw)
In-Reply-To: <20261031-uffd-prot-bits-fork-event-v1-1-3572921c2111@kernel.org>

On 10/31/26 1:35 PM, Mike Rapoport (Microsoft) wrote:
> With UFFD_FEATURE_EVENT_FORK the userfaultfd context is duplicated for the
> child process, the child VMAs are registered with the new context, and uffd
> protection state from the parent PTEs is copied into the child.
> 
> If the parent's userfaultfd is released before the fork event is read,
> userfaultfd_release_new() resets the VMA flags but keeps uffd state in the
> child PTEs.
> 
> This leaves the child's VMAs in an inconsistent state: they are not
> registered with userfaultfd but their mappings carry uffd protection state.
> 
> If the child registers the range with userfaultfd again, the stale state
> turns into protection the child never asked for.
> 
> When a write fault makes such a PTE writable without copying the page, the
> uffd bit remains set and page_table_check_pte_flags() warns about it.
> 
> Split resolving of the uffd PTE state out of userfaultfd_clear_vma() and
> call it from userfaultfd_release_new() before resetting the VMA.
> 
> Fixes: f369b07c8614 ("mm/uffd: reset write protection when unregister with wp-mode")
> Cc: stable@vger.kernel.org
> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> ---
>  mm/userfaultfd.c | 43 ++++++++++++++++++++++++++-----------------
>  1 file changed, 26 insertions(+), 17 deletions(-)
> 
> diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
> index 3b71712edab4c..2c11ac5dad3d5 100644
> --- a/mm/userfaultfd.c
> +++ b/mm/userfaultfd.c
> @@ -2220,6 +2220,28 @@ static void userfaultfd_reset_ctx(struct vm_area_struct *vma)
>  	userfaultfd_set_ctx(vma, NULL, 0);
>  }
>  
> +/* Clear the uffd bit and/or restore protnone PTEs */
> +static void userfaultfd_clear_ptes(struct vm_area_struct *vma,
> +		unsigned long start, unsigned long end)
> +{
> +	unsigned int mm_cp_flags = 0;
> +	struct mmu_gather tlb;
> +
> +	if (!userfaultfd_protected(vma))
> +		return;
> +
> +	if (userfaultfd_wp(vma))
> +		mm_cp_flags |= MM_CP_UFFD_WP_RESOLVE;
> +	if (userfaultfd_rwp(vma))
> +		mm_cp_flags |= MM_CP_UFFD_RWP_RESOLVE;
> +	if (vma_wants_manual_pte_write_upgrade(vma))
> +		mm_cp_flags |= MM_CP_TRY_CHANGE_WRITABLE;
> +
> +	tlb_gather_mmu(&tlb, vma->vm_mm);
> +	change_protection(&tlb, vma, start, end, mm_cp_flags);
> +	tlb_finish_mmu(&tlb);
> +}
> +
>  static struct vm_area_struct *userfaultfd_clear_vma(struct vma_iterator *vmi,
>  					     struct vm_area_struct *prev,
>  					     struct vm_area_struct *vma,
> @@ -2239,22 +2261,7 @@ static struct vm_area_struct *userfaultfd_clear_vma(struct vma_iterator *vmi,
>  	if (start == vma->vm_start && end == vma->vm_end)
>  		give_up_on_oom = true;
>  
> -	/* Clear the uffd bit and/or restore protnone PTEs */
> -	if (userfaultfd_protected(vma)) {
> -		unsigned int mm_cp_flags = 0;
> -		struct mmu_gather tlb;
> -
> -		if (userfaultfd_wp(vma))
> -			mm_cp_flags |= MM_CP_UFFD_WP_RESOLVE;
> -		if (userfaultfd_rwp(vma))
> -			mm_cp_flags |= MM_CP_UFFD_RWP_RESOLVE;
> -		if (vma_wants_manual_pte_write_upgrade(vma))
> -			mm_cp_flags |= MM_CP_TRY_CHANGE_WRITABLE;
> -
> -		tlb_gather_mmu(&tlb, vma->vm_mm);
> -		change_protection(&tlb, vma, start, end, mm_cp_flags);
> -		tlb_finish_mmu(&tlb);
> -	}
> +	userfaultfd_clear_ptes(vma, start, end);
>  
>  	ret = vma_modify_flags_uffd(vmi, prev, vma, start, end,
>  				    &new_vma_flags, NULL_VM_UFFD_CTX,
> @@ -2353,8 +2360,10 @@ static void userfaultfd_release_new(struct userfaultfd_ctx *ctx)
>  	/* the various vma->vm_userfaultfd_ctx still points to it */
>  	mmap_write_lock(mm);
>  	for_each_vma(vmi, vma) {
> -		if (vma->vm_userfaultfd_ctx.ctx == ctx)
> +		if (vma->vm_userfaultfd_ctx.ctx == ctx) {
> +			userfaultfd_clear_ptes(vma, vma->vm_start, vma->vm_end);
>  			userfaultfd_reset_ctx(vma);
> +		}
>  	}
>  	mmap_write_unlock(mm);
>  }
> 

reproduced the leftover bits in the child with wp and rwp on all memory
types, and they're gone with this. tested on x86_64 in qemu. LGTM so:

Reviewed-by: Jose A. Perez de Azpillaga <azpijr@gmail.com>
Tested-by: Jose A. Perez de Azpillaga <azpijr@gmail.com>

-- 
cheers,
jose a. p-a

  reply	other threads:[~2026-10-31 13:40 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-31 12:35 Mike Rapoport (Microsoft)
2026-10-31 13:40 ` Jose A. Perez de Azpillaga [this message]
2026-10-31 14:58 ` Tal Zussman
2026-10-31 15:09   ` Mike Rapoport

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2c132a52-1118-4773-866b-a8c713c4933e@gmail.com \
    --to=azpijr@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=peterx@redhat.com \
    --cc=rppt@kernel.org \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®