From bfb4b24b642e2776dbfa0720fc57239386f9234e Mon Sep 17 00:00:00 2001 From: Qi Zheng Date: Thu, 22 Feb 2024 16:08:15 +0800 Subject: [PATCH] BACKPORT: mm: userfaultfd: fix unexpected change to src_folio when UFFDIO_MOVE fails After ptep_clear_flush(), if we find that src_folio is pinned we will fail UFFDIO_MOVE and put src_folio back to src_pte entry, but the change to src_folio->{mapping,index} is not restored in this process. This is not what we expected, so fix it. This can cause the rmap for that page to be invalid, possibly resulting in memory corruption. At least swapout+migration would no longer work, because we might fail to locate the mappings of that folio. Link: https://lkml.kernel.org/r/20240222080815.46291-1-zhengqi.arch@bytedance.com Fixes: adef440691ba ("userfaultfd: UFFDIO_MOVE uABI") Signed-off-by: Qi Zheng Reviewed-by: David Hildenbrand Reviewed-by: Suren Baghdasaryan Cc: Andrea Arcangeli Cc: Signed-off-by: Andrew Morton (cherry picked from commit d7a08838ab74652f2b53fee9763f0178278c3a4b) Conflicts: mm/userfaultfd.c 1. Replace folio_move_anon_rmap() with page_move_anon_rmap(). Bug: 274911254 Change-Id: Ie4bf5785244271ab233c6230ed71460fd571bd1a Signed-off-by: Lokesh Gidra --- mm/userfaultfd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c index 1f8e977e830e..9149a95282e0 100644 --- a/mm/userfaultfd.c +++ b/mm/userfaultfd.c @@ -852,9 +852,6 @@ static int move_present_pte(struct mm_struct *mm, goto out; } - page_move_anon_rmap(&src_folio->page, dst_vma); - WRITE_ONCE(src_folio->index, linear_page_index(dst_vma, dst_addr)); - orig_src_pte = ptep_clear_flush(src_vma, src_addr, src_pte); /* Folio got pinned from under us. Put it back and fail the move. */ if (folio_maybe_dma_pinned(src_folio)) { @@ -863,6 +860,9 @@ static int move_present_pte(struct mm_struct *mm, goto out; } + page_move_anon_rmap(&src_folio->page, dst_vma); + WRITE_ONCE(src_folio->index, linear_page_index(dst_vma, dst_addr)); + orig_dst_pte = mk_pte(&src_folio->page, dst_vma->vm_page_prot); /* Follow mremap() behavior and treat the entry dirty after the move */ orig_dst_pte = pte_mkwrite(pte_mkdirty(orig_dst_pte));