mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git
synced 2026-10-31 06:14:39 +01:00
mm/hugetlb: fix huge_pmd_unshare() vs GUP-fast race
huge_pmd_unshare() drops a reference on a page table that may have
previously been shared across processes, potentially turning it into a
normal page table used in another process in which unrelated VMAs can
afterwards be installed.
If this happens in the middle of a concurrent gup_fast(), gup_fast() could
end up walking the page tables of another process. While I don't see any
way in which that immediately leads to kernel memory corruption, it is
really weird and unexpected.
Fix it with an explicit broadcast IPI through tlb_remove_table_sync_one(),
just like we do in khugepaged when removing page tables for a THP
collapse.
Link: https://lkml.kernel.org/r/[email protected]
Link: https://lkml.kernel.org/r/[email protected]
Fixes: 39dde65c99 ("[PATCH] shared page table for hugetlb page")
Signed-off-by: Jann Horn <[email protected]>
Reviewed-by: Lorenzo Stoakes <[email protected]>
Cc: Liam Howlett <[email protected]>
Cc: Muchun Song <[email protected]>
Cc: Oscar Salvador <[email protected]>
Cc: Vlastimil Babka <[email protected]>
Cc: <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
This commit is contained in:
1 parent
081056dc00
commit
1013af4f58
1 file changed
+7
@@ -7629,6 +7629,13 @@ int huge_pmd_unshare(struct mm_struct *mm, struct vm_area_struct *vma,
|
||||
return 0;
|
||||
|
||||
pud_clear(pud);
|
||||
/*
|
||||
* Once our caller drops the rmap lock, some other process might be
|
||||
* using this page table as a normal, non-hugetlb page table.
|
||||
* Wait for pending gup_fast() in other threads to finish before letting
|
||||
* that happen.
|
||||
*/
|
||||
tlb_remove_table_sync_one();
|
||||
ptdesc_pmd_pts_dec(virt_to_ptdesc(ptep));
|
||||
mm_dec_nr_pmds(mm);
|
||||
return 1;
|
||||
|
||||
Reference in new issue
Block a user