* Re: [PATCH] userfaultfd: preserve write protection across UFFDIO_MOVE
2026-04-09 15:28 [PATCH] userfaultfd: preserve write protection across UFFDIO_MOVE Gregory Price
@ 2026-04-09 20:09 ` Suren Baghdasaryan
2026-04-10 7:55 ` Mike Rapoport
2026-04-12 18:18 ` Andrew Morton
2 siblings, 0 replies; 5+ messages in thread
From: Suren Baghdasaryan @ 2026-04-09 20:09 UTC (permalink / raw)
To: Gregory Price
Cc: linux-mm, linux-kernel, kernel-team, akpm, rppt, peterx, aarcange,
stable
On Thu, Apr 9, 2026 at 8:28 AM Gregory Price <gourry@gourry.net> wrote:
>
> move_present_ptes() unconditionally makes the destination PTE writable,
> dropping uffd-wp write-protection from the source PTE.
>
> The original intent was to follow mremap() behavior, but mremap()'s
> move_ptes() preserves the source write state unconditionally.
>
> Modify uffd to preserve the source write state and check the uffd-wp
> condition of the source before setting writable on the destination.
>
> Fixes: adef440691ba ("userfaultfd: UFFDIO_MOVE uABI")
> Cc: stable@vger.kernel.org
> Signed-off-by: Gregory Price <gourry@gourry.net>
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
> ---
> mm/userfaultfd.c | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
> index e6dfd5f28acd..783ca68aed88 100644
> --- a/mm/userfaultfd.c
> +++ b/mm/userfaultfd.c
> @@ -1123,7 +1123,10 @@ static long move_present_ptes(struct mm_struct *mm,
> orig_dst_pte = pte_mksoft_dirty(orig_dst_pte);
> if (pte_dirty(orig_src_pte))
> orig_dst_pte = pte_mkdirty(orig_dst_pte);
> - orig_dst_pte = pte_mkwrite(orig_dst_pte, dst_vma);
> + if (pte_write(orig_src_pte))
> + orig_dst_pte = pte_mkwrite(orig_dst_pte, dst_vma);
> + if (pte_uffd_wp(orig_src_pte))
> + orig_dst_pte = pte_mkuffd_wp(orig_dst_pte);
> set_pte_at(mm, dst_addr, dst_pte, orig_dst_pte);
>
> src_addr += PAGE_SIZE;
> --
> 2.52.0
>
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH] userfaultfd: preserve write protection across UFFDIO_MOVE
2026-04-09 15:28 [PATCH] userfaultfd: preserve write protection across UFFDIO_MOVE Gregory Price
2026-04-09 20:09 ` Suren Baghdasaryan
@ 2026-04-10 7:55 ` Mike Rapoport
2026-04-12 18:18 ` Andrew Morton
2 siblings, 0 replies; 5+ messages in thread
From: Mike Rapoport @ 2026-04-10 7:55 UTC (permalink / raw)
To: Gregory Price
Cc: linux-mm, linux-kernel, kernel-team, akpm, peterx, surenb,
aarcange, stable
On Thu, Apr 09, 2026 at 11:28:22AM -0400, Gregory Price wrote:
> move_present_ptes() unconditionally makes the destination PTE writable,
> dropping uffd-wp write-protection from the source PTE.
>
> The original intent was to follow mremap() behavior, but mremap()'s
> move_ptes() preserves the source write state unconditionally.
>
> Modify uffd to preserve the source write state and check the uffd-wp
> condition of the source before setting writable on the destination.
>
> Fixes: adef440691ba ("userfaultfd: UFFDIO_MOVE uABI")
> Cc: stable@vger.kernel.org
> Signed-off-by: Gregory Price <gourry@gourry.net>
Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> ---
> mm/userfaultfd.c | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
> index e6dfd5f28acd..783ca68aed88 100644
> --- a/mm/userfaultfd.c
> +++ b/mm/userfaultfd.c
> @@ -1123,7 +1123,10 @@ static long move_present_ptes(struct mm_struct *mm,
> orig_dst_pte = pte_mksoft_dirty(orig_dst_pte);
> if (pte_dirty(orig_src_pte))
> orig_dst_pte = pte_mkdirty(orig_dst_pte);
> - orig_dst_pte = pte_mkwrite(orig_dst_pte, dst_vma);
> + if (pte_write(orig_src_pte))
> + orig_dst_pte = pte_mkwrite(orig_dst_pte, dst_vma);
> + if (pte_uffd_wp(orig_src_pte))
> + orig_dst_pte = pte_mkuffd_wp(orig_dst_pte);
> set_pte_at(mm, dst_addr, dst_pte, orig_dst_pte);
>
> src_addr += PAGE_SIZE;
> --
> 2.52.0
>
--
Sincerely yours,
Mike.
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH] userfaultfd: preserve write protection across UFFDIO_MOVE
2026-04-09 15:28 [PATCH] userfaultfd: preserve write protection across UFFDIO_MOVE Gregory Price
2026-04-09 20:09 ` Suren Baghdasaryan
2026-04-10 7:55 ` Mike Rapoport
@ 2026-04-12 18:18 ` Andrew Morton
2026-04-13 5:36 ` Gregory Price
2 siblings, 1 reply; 5+ messages in thread
From: Andrew Morton @ 2026-04-12 18:18 UTC (permalink / raw)
To: Gregory Price
Cc: linux-mm, linux-kernel, kernel-team, rppt, peterx, surenb,
aarcange, stable
On Thu, 9 Apr 2026 11:28:22 -0400 Gregory Price <gourry@gourry.net> wrote:
> move_present_ptes() unconditionally makes the destination PTE writable,
> dropping uffd-wp write-protection from the source PTE.
>
> The original intent was to follow mremap() behavior, but mremap()'s
> move_ptes() preserves the source write state unconditionally.
>
> Modify uffd to preserve the source write state and check the uffd-wp
> condition of the source before setting writable on the destination.
Please can we have a description of the userspace-visible impact of the
bug.
> Fixes: adef440691ba ("userfaultfd: UFFDIO_MOVE uABI")
> Cc: stable@vger.kernel.org
especially when cc:stable, thanks.
> Signed-off-by: Gregory Price <gourry@gourry.net>
>
> ...
>
> --- a/mm/userfaultfd.c
> +++ b/mm/userfaultfd.c
> @@ -1123,7 +1123,10 @@ static long move_present_ptes(struct mm_struct *mm,
> orig_dst_pte = pte_mksoft_dirty(orig_dst_pte);
> if (pte_dirty(orig_src_pte))
> orig_dst_pte = pte_mkdirty(orig_dst_pte);
> - orig_dst_pte = pte_mkwrite(orig_dst_pte, dst_vma);
> + if (pte_write(orig_src_pte))
> + orig_dst_pte = pte_mkwrite(orig_dst_pte, dst_vma);
> + if (pte_uffd_wp(orig_src_pte))
> + orig_dst_pte = pte_mkuffd_wp(orig_dst_pte);
> set_pte_at(mm, dst_addr, dst_pte, orig_dst_pte);
>
(presently wondering if this is backward compatible)
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH] userfaultfd: preserve write protection across UFFDIO_MOVE
2026-04-12 18:18 ` Andrew Morton
@ 2026-04-13 5:36 ` Gregory Price
0 siblings, 0 replies; 5+ messages in thread
From: Gregory Price @ 2026-04-13 5:36 UTC (permalink / raw)
To: Andrew Morton
Cc: linux-mm, linux-kernel, kernel-team, rppt, peterx, surenb,
aarcange, stable
On Sun, Apr 12, 2026 at 11:18:07AM -0700, Andrew Morton wrote:
> On Thu, 9 Apr 2026 11:28:22 -0400 Gregory Price <gourry@gourry.net> wrote:
>
> > move_present_ptes() unconditionally makes the destination PTE writable,
> > dropping uffd-wp write-protection from the source PTE.
> >
> > The original intent was to follow mremap() behavior, but mremap()'s
> > move_ptes() preserves the source write state unconditionally.
> >
> > Modify uffd to preserve the source write state and check the uffd-wp
> > condition of the source before setting writable on the destination.
>
> Please can we have a description of the userspace-visible impact of the
> bug.
>
Simply:
UFFDIO_MOVE silently drops write protection from the source PTE when
moving pages to a destination, leading to missing write-protect faults
after the page has been moved.
I ran into this while futzing around with some user space management of
VM memory, and expecting a move to continue firing WP faults after.
But Sashiko actually made a useful (though obtuse) observation which
has made me realize _MOVE is actually ambiguous on what to do with
source region UFFD modes.
> > + if (pte_uffd_wp(orig_src_pte))
> > + orig_dst_pte = pte_mkuffd_wp(orig_dst_pte);
This line assumes the destination must have intended to be WP, and the
the result is essentially stale uffd wp bits in the opposite case (a
user not intending to carry over WP now carries it over).
tl;dr: this is more of a semantic change than I'd intended, and the
existing tests did not catch it.
The correct solution here is to make a UFFDIO_MOVE_MODE_WP flag to copy
the UFFDIO_COPY_MODE_WP pattern. Otherwise:
> (presently wondering if this is backward compatible)
Yes, you're right to wonder - this does break backward compatibilty.
Will come back around with UFFDIO_MOVE_MODE_WP.
~Gregory
^ permalink raw reply [flat|nested] 5+ messages in thread