Skip to content

Commit 824135c

Browse files
howlettakpm00
authored andcommitted
mmap: fix error paths with dup_anon_vma()
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/[email protected] Fixes: d4af56c ("mm: start tracking VMAs with maple tree") Signed-off-by: Liam R. Howlett <[email protected]> Reviewed-by: Lorenzo Stoakes <[email protected]> Acked-by: Vlastimil Babka <[email protected]> Cc: Jann Horn <[email protected]> Cc: Matthew Wilcox (Oracle) <[email protected]> Cc: Suren Baghdasaryan <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 1419430 commit 824135c

File tree

1 file changed

+22
-8
lines changed

1 file changed

+22
-8
lines changed

mm/mmap.c

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -583,21 +583,28 @@ static inline void vma_complete(struct vma_prepare *vp,
583583
* dup_anon_vma() - Helper function to duplicate anon_vma
584584
* @dst: The destination VMA
585585
* @src: The source VMA
586+
* @dup: Pointer to the destination VMA when successful.
586587
*
587588
* Returns: 0 on success.
588589
*/
589590
static inline int dup_anon_vma(struct vm_area_struct *dst,
590-
struct vm_area_struct *src)
591+
struct vm_area_struct *src, struct vm_area_struct **dup)
591592
{
592593
/*
593594
* Easily overlooked: when mprotect shifts the boundary, make sure the
594595
* expanding vma has anon_vma set if the shrinking vma had, to cover any
595596
* anon pages imported.
596597
*/
597598
if (src->anon_vma && !dst->anon_vma) {
599+
int ret;
600+
598601
vma_assert_write_locked(dst);
599602
dst->anon_vma = src->anon_vma;
600-
return anon_vma_clone(dst, src);
603+
ret = anon_vma_clone(dst, src);
604+
if (ret)
605+
return ret;
606+
607+
*dup = dst;
601608
}
602609

603610
return 0;
@@ -624,6 +631,7 @@ int vma_expand(struct vma_iterator *vmi, struct vm_area_struct *vma,
624631
unsigned long start, unsigned long end, pgoff_t pgoff,
625632
struct vm_area_struct *next)
626633
{
634+
struct vm_area_struct *anon_dup = NULL;
627635
bool remove_next = false;
628636
struct vma_prepare vp;
629637

@@ -633,7 +641,7 @@ int vma_expand(struct vma_iterator *vmi, struct vm_area_struct *vma,
633641

634642
remove_next = true;
635643
vma_start_write(next);
636-
ret = dup_anon_vma(vma, next);
644+
ret = dup_anon_vma(vma, next, &anon_dup);
637645
if (ret)
638646
return ret;
639647
}
@@ -661,6 +669,8 @@ int vma_expand(struct vma_iterator *vmi, struct vm_area_struct *vma,
661669
return 0;
662670

663671
nomem:
672+
if (anon_dup)
673+
unlink_anon_vmas(anon_dup);
664674
return -ENOMEM;
665675
}
666676

@@ -860,6 +870,7 @@ struct vm_area_struct *vma_merge(struct vma_iterator *vmi, struct mm_struct *mm,
860870
{
861871
struct vm_area_struct *curr, *next, *res;
862872
struct vm_area_struct *vma, *adjust, *remove, *remove2;
873+
struct vm_area_struct *anon_dup = NULL;
863874
struct vma_prepare vp;
864875
pgoff_t vma_pgoff;
865876
int err = 0;
@@ -927,18 +938,18 @@ struct vm_area_struct *vma_merge(struct vma_iterator *vmi, struct mm_struct *mm,
927938
vma_start_write(next);
928939
remove = next; /* case 1 */
929940
vma_end = next->vm_end;
930-
err = dup_anon_vma(prev, next);
941+
err = dup_anon_vma(prev, next, &anon_dup);
931942
if (curr) { /* case 6 */
932943
vma_start_write(curr);
933944
remove = curr;
934945
remove2 = next;
935946
if (!next->anon_vma)
936-
err = dup_anon_vma(prev, curr);
947+
err = dup_anon_vma(prev, curr, &anon_dup);
937948
}
938949
} else if (merge_prev) { /* case 2 */
939950
if (curr) {
940951
vma_start_write(curr);
941-
err = dup_anon_vma(prev, curr);
952+
err = dup_anon_vma(prev, curr, &anon_dup);
942953
if (end == curr->vm_end) { /* case 7 */
943954
remove = curr;
944955
} else { /* case 5 */
@@ -954,7 +965,7 @@ struct vm_area_struct *vma_merge(struct vma_iterator *vmi, struct mm_struct *mm,
954965
vma_end = addr;
955966
adjust = next;
956967
adj_start = -(prev->vm_end - addr);
957-
err = dup_anon_vma(next, prev);
968+
err = dup_anon_vma(next, prev, &anon_dup);
958969
} else {
959970
/*
960971
* Note that cases 3 and 8 are the ONLY ones where prev
@@ -968,7 +979,7 @@ struct vm_area_struct *vma_merge(struct vma_iterator *vmi, struct mm_struct *mm,
968979
vma_pgoff = curr->vm_pgoff;
969980
vma_start_write(curr);
970981
remove = curr;
971-
err = dup_anon_vma(next, curr);
982+
err = dup_anon_vma(next, curr, &anon_dup);
972983
}
973984
}
974985
}
@@ -1018,6 +1029,9 @@ struct vm_area_struct *vma_merge(struct vma_iterator *vmi, struct mm_struct *mm,
10181029
return res;
10191030

10201031
prealloc_fail:
1032+
if (anon_dup)
1033+
unlink_anon_vmas(anon_dup);
1034+
10211035
anon_vma_fail:
10221036
vma_iter_set(vmi, addr);
10231037
vma_iter_load(vmi);

0 commit comments

Comments
 (0)