Skip to content

Commit 0cf4b16

Browse files
lorenzo-stoakesakpm00
authored andcommitted
mm/vma: reset VMA iterator on commit_merge() OOM failure
While an OOM failure in commit_merge() isn't really feasible due to the allocation which might fail (a maple tree pre-allocation) being 'too small to fail', we do need to handle this case correctly regardless. In vma_merge_existing_range(), we can theoretically encounter failures which result in an OOM error in two ways - firstly dup_anon_vma() might fail with an OOM error, and secondly commit_merge() failing, ultimately, to pre-allocate a maple tree node. The abort logic for dup_anon_vma() resets the VMA iterator to the initial range, ensuring that any logic looping on this iterator will correctly proceed to the next VMA. However the commit_merge() abort logic does not do the same thing. This resulted in a syzbot report occurring because mlockall() iterates through VMAs, is tolerant of errors, but ended up with an incorrect previous VMA being specified due to incorrect iterator state. While making this change, it became apparent we are duplicating logic - the logic introduced in commit 41e6ddc ("mm/vma: add give_up_on_oom option on modify/merge, use in uffd release") duplicates the vmg->give_up_on_oom check in both abort branches. Additionally, we observe that we can perform the anon_dup check safely on dup_anon_vma() failure, as this will not be modified should this call fail. Finally, we need to reset the iterator in both cases, so now we can simply use the exact same code to abort for both. We remove the VM_WARN_ON(err != -ENOMEM) as it would be silly for this to be otherwise and it allows us to implement the abort check more neatly. Link: https://lkml.kernel.org/r/[email protected] Fixes: 47b16d0 ("mm: abort vma_modify() on merge out of memory failure") Signed-off-by: Lorenzo Stoakes <[email protected]> Reported-by: [email protected] Closes: https://lore.kernel.org/linux-mm/[email protected]/ Reviewed-by: Pedro Falcato <[email protected]> Reviewed-by: Vlastimil Babka <[email protected]> Reviewed-by: Liam R. Howlett <[email protected]> Cc: Jann Horn <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 1b8e409 commit 0cf4b16

File tree

1 file changed

+4
-18
lines changed

1 file changed

+4
-18
lines changed

mm/vma.c

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -967,26 +967,9 @@ static __must_check struct vm_area_struct *vma_merge_existing_range(
967967
err = dup_anon_vma(next, middle, &anon_dup);
968968
}
969969

970-
if (err)
970+
if (err || commit_merge(vmg))
971971
goto abort;
972972

973-
err = commit_merge(vmg);
974-
if (err) {
975-
VM_WARN_ON(err != -ENOMEM);
976-
977-
if (anon_dup)
978-
unlink_anon_vmas(anon_dup);
979-
980-
/*
981-
* We've cleaned up any cloned anon_vma's, no VMAs have been
982-
* modified, no harm no foul if the user requests that we not
983-
* report this and just give up, leaving the VMAs unmerged.
984-
*/
985-
if (!vmg->give_up_on_oom)
986-
vmg->state = VMA_MERGE_ERROR_NOMEM;
987-
return NULL;
988-
}
989-
990973
khugepaged_enter_vma(vmg->target, vmg->flags);
991974
vmg->state = VMA_MERGE_SUCCESS;
992975
return vmg->target;
@@ -995,6 +978,9 @@ static __must_check struct vm_area_struct *vma_merge_existing_range(
995978
vma_iter_set(vmg->vmi, start);
996979
vma_iter_load(vmg->vmi);
997980

981+
if (anon_dup)
982+
unlink_anon_vmas(anon_dup);
983+
998984
/*
999985
* This means we have failed to clone anon_vma's correctly, but no
1000986
* actual changes to VMAs have occurred, so no harm no foul - if the

0 commit comments

Comments
 (0)