6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Liam R. Howlett Liam.Howlett@oracle.com
commit 824135c46b00df7fb369ec7f1f8607427bbebeb0 upstream.
When the calling function fails after the dup_anon_vma(), the duplication of the anon_vma is not being undone. Add the necessary unlink_anon_vma() call to the error paths that are missing them.
This issue showed up during inspection of the error path in vma_merge() for an unrelated vma iterator issue.
Users may experience increased memory usage, which may be problematic as the failure would likely be caused by a low memory situation.
Link: https://lkml.kernel.org/r/20230929183041.2835469-3-Liam.Howlett@oracle.com Fixes: d4af56c5c7c6 ("mm: start tracking VMAs with maple tree") Signed-off-by: Liam R. Howlett Liam.Howlett@oracle.com Reviewed-by: Lorenzo Stoakes lstoakes@gmail.com Acked-by: Vlastimil Babka vbabka@suse.cz Cc: Jann Horn jannh@google.com Cc: Matthew Wilcox (Oracle) willy@infradead.org Cc: Suren Baghdasaryan surenb@google.com Cc: stable@vger.kernel.org Signed-off-by: Andrew Morton akpm@linux-foundation.org Signed-off-by: Liam R. Howlett Liam.Howlett@oracle.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- mm/mmap.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)
--- a/mm/mmap.c +++ b/mm/mmap.c @@ -519,6 +519,7 @@ inline int vma_expand(struct ma_state *m struct anon_vma *anon_vma = vma->anon_vma; struct file *file = vma->vm_file; bool remove_next = false; + struct vm_area_struct *anon_dup = NULL;
if (next && (vma != next) && (end == next->vm_end)) { remove_next = true; @@ -530,6 +531,8 @@ inline int vma_expand(struct ma_state *m error = anon_vma_clone(vma, next); if (error) return error; + + anon_dup = vma; } }
@@ -602,6 +605,9 @@ inline int vma_expand(struct ma_state *m return 0;
nomem: + if (anon_dup) + unlink_anon_vmas(anon_dup); + return -ENOMEM; }
@@ -629,6 +635,7 @@ int __vma_adjust(struct vm_area_struct * int remove_next = 0; MA_STATE(mas, &mm->mm_mt, 0, 0); struct vm_area_struct *exporter = NULL, *importer = NULL; + struct vm_area_struct *anon_dup = NULL;
if (next && !insert) { if (end >= next->vm_end) { @@ -709,11 +716,17 @@ int __vma_adjust(struct vm_area_struct * error = anon_vma_clone(importer, exporter); if (error) return error; + + anon_dup = importer; } }
- if (mas_preallocate(&mas, vma, GFP_KERNEL)) + if (mas_preallocate(&mas, vma, GFP_KERNEL)) { + if (anon_dup) + unlink_anon_vmas(anon_dup); + return -ENOMEM; + }
vma_adjust_trans_huge(orig_vma, start, end, adjust_next); if (file) {