summaryrefslogtreecommitdiff
path: root/mm
diff options
context:
space:
mode:
authorLiam R. Howlett <Liam.Howlett@oracle.com>2023-09-29 21:30:40 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2023-11-08 16:11:03 +0300
commit9411dbe2c66c37c6018947bdbe8d89bc6118b385 (patch)
treeda9fae8c39cc20cf01b38efff0887465765ed8f4 /mm
parent21ca008c53a50dd4cef9ebf646e1c74819e610ca (diff)
downloadlinux-9411dbe2c66c37c6018947bdbe8d89bc6118b385.tar.xz
mmap: fix error paths with dup_anon_vma()
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>
Diffstat (limited to 'mm')
-rw-r--r--mm/mmap.c15
1 files changed, 14 insertions, 1 deletions
diff --git a/mm/mmap.c b/mm/mmap.c
index 8ffe3f87f7ba..c0f9575493de 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -519,6 +519,7 @@ inline int vma_expand(struct ma_state *mas, struct vm_area_struct *vma,
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 *mas, struct vm_area_struct *vma,
error = anon_vma_clone(vma, next);
if (error)
return error;
+
+ anon_dup = vma;
}
}
@@ -602,6 +605,9 @@ inline int vma_expand(struct ma_state *mas, struct vm_area_struct *vma,
return 0;
nomem:
+ if (anon_dup)
+ unlink_anon_vmas(anon_dup);
+
return -ENOMEM;
}
@@ -629,6 +635,7 @@ int __vma_adjust(struct vm_area_struct *vma, unsigned long start,
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 *vma, unsigned long start,
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) {