madvise_collapse() setting "mmap_locked = true" after calling collapse_pte_mapped_thp() looked good but was wrong. If the loop then moves on to the next extent, mmap_locked assures it that "vma" has been revalidated under mmap_lock, which was not the case: and led to UAFs, crashes in __fput() or task_work_run(), even collapse_file()'s VM_BUG_ON(start & (HPAGE_PMD_NR - 1)) - all detected by syzbot. (collapse_pte_mapped_thp() does validate the vma that it works on: but it's not passed in as an argument, collapse_pte_mapped_thp() finds the vma for mm and addr by itself - which may by this time have changed from the vma saved in madvise_collapse().) Reported-by: syzbot+fe7b1487405295d29268@xxxxxxxxxxxxxxxxxxxxxxxxx Closes: https://lore.kernel.org/lkml/000000000000f9de430600ae05db@xxxxxxxxxx/ Reported-by: syzbot+173cc8cfdfbbef6dd755@xxxxxxxxxxxxxxxxxxxxxxxxx Closes: https://lore.kernel.org/linux-mm/000000000000e4b0f0060123ca40@xxxxxxxxxx/ Signed-off-by: Hugh Dickins <hughd@xxxxxxxxxx> --- mm/khugepaged.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/khugepaged.c b/mm/khugepaged.c index 6bad69c0e4bd..1c773db26e88 100644 --- a/mm/khugepaged.c +++ b/mm/khugepaged.c @@ -2747,7 +2747,7 @@ int madvise_collapse(struct vm_area_struct *vma, struct vm_area_struct **prev, BUG_ON(*prev); mmap_read_lock(mm); result = collapse_pte_mapped_thp(mm, addr, true); - mmap_locked = true; + mmap_read_unlock(mm); goto handle_result; /* Whitelisted set of results where continuing OK */ case SCAN_PMD_NULL: -- 2.35.3