From: Alistair Popple <apopple@xxxxxxxxxx> commit 60bae73708963de4a17231077285bd9ff2f41c44 upstream. When clearing a PTE the TLB should be flushed whilst still holding the PTL to avoid a potential race with madvise/munmap/etc. For example consider the following sequence: CPU0 CPU1 ---- ---- migrate_vma_collect_pmd() pte_unmap_unlock() madvise(MADV_DONTNEED) -> zap_pte_range() pte_offset_map_lock() [ PTE not present, TLB not flushed ] pte_unmap_unlock() [ page is still accessible via stale TLB ] flush_tlb_range() In this case the page may still be accessed via the stale TLB entry after madvise returns. Fix this by flushing the TLB while holding the PTL. Fixes: 8c3328f1f36a ("mm/migrate: migrate_vma() unmap page from vma while collecting pages") Link: https://lkml.kernel.org/r/9f801e9d8d830408f2ca27821f606e09aa856899.1662078528.git-series.apopple@xxxxxxxxxx Signed-off-by: Alistair Popple <apopple@xxxxxxxxxx> Reported-by: Nadav Amit <nadav.amit@xxxxxxxxx> Reviewed-by: "Huang, Ying" <ying.huang@xxxxxxxxx> Acked-by: David Hildenbrand <david@xxxxxxxxxx> Acked-by: Peter Xu <peterx@xxxxxxxxxx> Cc: Alex Sierra <alex.sierra@xxxxxxx> Cc: Ben Skeggs <bskeggs@xxxxxxxxxx> Cc: Felix Kuehling <Felix.Kuehling@xxxxxxx> Cc: huang ying <huang.ying.caritas@xxxxxxxxx> Cc: Jason Gunthorpe <jgg@xxxxxxxxxx> Cc: John Hubbard <jhubbard@xxxxxxxxxx> Cc: Karol Herbst <kherbst@xxxxxxxxxx> Cc: Logan Gunthorpe <logang@xxxxxxxxxxxx> Cc: Lyude Paul <lyude@xxxxxxxxxx> Cc: Matthew Wilcox <willy@xxxxxxxxxxxxx> Cc: Paul Mackerras <paulus@xxxxxxxxxx> Cc: Ralph Campbell <rcampbell@xxxxxxxxxx> Cc: <stable@xxxxxxxxxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- mm/migrate.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) --- a/mm/migrate.c +++ b/mm/migrate.c @@ -2422,13 +2422,14 @@ next: migrate->dst[migrate->npages] = 0; migrate->src[migrate->npages++] = mpfn; } - arch_leave_lazy_mmu_mode(); - pte_unmap_unlock(ptep - 1, ptl); /* Only flush the TLB if we actually modified any entries */ if (unmapped) flush_tlb_range(walk->vma, start, end); + arch_leave_lazy_mmu_mode(); + pte_unmap_unlock(ptep - 1, ptl); + return 0; }