* [PATCH v2 1/3] mmap: Fix vma_iterator in error path of vma_merge()
2023-09-28 17:16 [PATCH 0/3] Fixes for vma_merge() error path Liam R. Howlett
@ 2023-09-28 17:16 ` Liam R. Howlett
2023-09-28 17:16 ` [PATCH v2 2/3] mmap: Fix error paths with dup_anon_vma() Liam R. Howlett
2023-09-28 17:16 ` [PATCH v2 3/3] mmap: Add clarifying comment to vma_merge() code Liam R. Howlett
2 siblings, 0 replies; 5+ messages in thread
From: Liam R. Howlett @ 2023-09-28 17:16 UTC (permalink / raw)
To: Andrew Morton
Cc: maple-tree, linux-mm, linux-kernel, Jann Horn, Lorenzo Stoakes,
Vlastimil Babka, Suren Baghdasaryan, Matthew Wilcox, stable,
Liam R. Howlett
When merging of the previous VMA fails after the vma iterator has been
moved to the previous entry, the vma iterator must be advanced to ensure
the caller takes the correct action on the next vma iterator event. Fix
this by adding a vma_next() call to the error path.
Users would not notice the effects as it would result in an extra
vma_merge() call if the first call ended due to an out-of-memory event.
Link: https://lore.kernel.org/linux-mm/CAG48ez12VN1JAOtTNMY+Y2YnsU45yL5giS-Qn=ejtiHpgJAbdQ@mail.gmail.com/
Closes: https://lore.kernel.org/linux-mm/CAG48ez12VN1JAOtTNMY+Y2YnsU45yL5giS-Qn=ejtiHpgJAbdQ@mail.gmail.com/
Fixes: 18b098af2890 ("vma_merge: set vma iterator to correct position.")
Cc: stable@vger.kernel.org
Cc: Jann Horn <jannh@google.com>
Signed-off-by: Liam R. Howlett <Liam.Howlett@oracle.com>
---
mm/mmap.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/mm/mmap.c b/mm/mmap.c
index b56a7f0c9f85..a4eb5a5626bb 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -975,7 +975,7 @@ struct vm_area_struct *vma_merge(struct vma_iterator *vmi, struct mm_struct *mm,
/* Error in anon_vma clone. */
if (err)
- return NULL;
+ goto anon_vma_fail;
if (vma_start < vma->vm_start || vma_end > vma->vm_end)
vma_expanded = true;
@@ -988,7 +988,7 @@ struct vm_area_struct *vma_merge(struct vma_iterator *vmi, struct mm_struct *mm,
}
if (vma_iter_prealloc(vmi, vma))
- return NULL;
+ goto prealloc_fail;
init_multi_vma_prep(&vp, vma, adjust, remove, remove2);
VM_WARN_ON(vp.anon_vma && adjust && adjust->anon_vma &&
@@ -1016,6 +1016,12 @@ struct vm_area_struct *vma_merge(struct vma_iterator *vmi, struct mm_struct *mm,
vma_complete(&vp, vmi, mm);
khugepaged_enter_vma(res, vm_flags);
return res;
+
+prealloc_fail:
+anon_vma_fail:
+ if (merge_prev)
+ vma_next(vmi);
+ return NULL;
}
/*
--
2.40.1
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH v2 2/3] mmap: Fix error paths with dup_anon_vma()
2023-09-28 17:16 [PATCH 0/3] Fixes for vma_merge() error path Liam R. Howlett
2023-09-28 17:16 ` [PATCH v2 1/3] mmap: Fix vma_iterator in error path of vma_merge() Liam R. Howlett
@ 2023-09-28 17:16 ` Liam R. Howlett
2023-09-28 17:16 ` [PATCH v2 3/3] mmap: Add clarifying comment to vma_merge() code Liam R. Howlett
2 siblings, 0 replies; 5+ messages in thread
From: Liam R. Howlett @ 2023-09-28 17:16 UTC (permalink / raw)
To: Andrew Morton
Cc: maple-tree, linux-mm, linux-kernel, Jann Horn, Lorenzo Stoakes,
Vlastimil Babka, Suren Baghdasaryan, Matthew Wilcox, stable,
Liam R. Howlett
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.
Fixes: d4af56c5c7c6 ("mm: start tracking VMAs with maple tree")
Cc: stable@vger.kernel.org
Cc: Jann Horn <jannh@google.com>
Signed-off-by: Liam R. Howlett <Liam.Howlett@oracle.com>
---
mm/mmap.c | 22 +++++++++++++++-------
1 file changed, 15 insertions(+), 7 deletions(-)
diff --git a/mm/mmap.c b/mm/mmap.c
index a4eb5a5626bb..2f0ee489db8a 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -587,7 +587,7 @@ static inline void vma_complete(struct vma_prepare *vp,
* Returns: 0 on success.
*/
static inline int dup_anon_vma(struct vm_area_struct *dst,
- struct vm_area_struct *src)
+ struct vm_area_struct *src, struct vm_area_struct **dup)
{
/*
* Easily overlooked: when mprotect shifts the boundary, make sure the
@@ -597,6 +597,7 @@ static inline int dup_anon_vma(struct vm_area_struct *dst,
if (src->anon_vma && !dst->anon_vma) {
vma_assert_write_locked(dst);
dst->anon_vma = src->anon_vma;
+ *dup = dst;
return anon_vma_clone(dst, src);
}
@@ -624,6 +625,7 @@ int vma_expand(struct vma_iterator *vmi, struct vm_area_struct *vma,
unsigned long start, unsigned long end, pgoff_t pgoff,
struct vm_area_struct *next)
{
+ struct vm_area_struct *anon_dup = NULL;
bool remove_next = false;
struct vma_prepare vp;
@@ -633,7 +635,7 @@ int vma_expand(struct vma_iterator *vmi, struct vm_area_struct *vma,
remove_next = true;
vma_start_write(next);
- ret = dup_anon_vma(vma, next);
+ ret = dup_anon_vma(vma, next, &anon_dup);
if (ret)
return ret;
}
@@ -661,6 +663,8 @@ int vma_expand(struct vma_iterator *vmi, struct vm_area_struct *vma,
return 0;
nomem:
+ if (anon_dup)
+ unlink_anon_vmas(anon_dup);
return -ENOMEM;
}
@@ -860,6 +864,7 @@ struct vm_area_struct *vma_merge(struct vma_iterator *vmi, struct mm_struct *mm,
{
struct vm_area_struct *curr, *next, *res;
struct vm_area_struct *vma, *adjust, *remove, *remove2;
+ struct vm_area_struct *anon_dup = NULL;
struct vma_prepare vp;
pgoff_t vma_pgoff;
int err = 0;
@@ -927,18 +932,18 @@ struct vm_area_struct *vma_merge(struct vma_iterator *vmi, struct mm_struct *mm,
vma_start_write(next);
remove = next; /* case 1 */
vma_end = next->vm_end;
- err = dup_anon_vma(prev, next);
+ err = dup_anon_vma(prev, next, &anon_dup);
if (curr) { /* case 6 */
vma_start_write(curr);
remove = curr;
remove2 = next;
if (!next->anon_vma)
- err = dup_anon_vma(prev, curr);
+ err = dup_anon_vma(prev, curr, &anon_dup);
}
} else if (merge_prev) { /* case 2 */
if (curr) {
vma_start_write(curr);
- err = dup_anon_vma(prev, curr);
+ err = dup_anon_vma(prev, curr, &anon_dup);
if (end == curr->vm_end) { /* case 7 */
remove = curr;
} else { /* case 5 */
@@ -954,7 +959,7 @@ struct vm_area_struct *vma_merge(struct vma_iterator *vmi, struct mm_struct *mm,
vma_end = addr;
adjust = next;
adj_start = -(prev->vm_end - addr);
- err = dup_anon_vma(next, prev);
+ err = dup_anon_vma(next, prev, &anon_dup);
} else {
/*
* Note that cases 3 and 8 are the ONLY ones where prev
@@ -968,7 +973,7 @@ struct vm_area_struct *vma_merge(struct vma_iterator *vmi, struct mm_struct *mm,
vma_pgoff = curr->vm_pgoff;
vma_start_write(curr);
remove = curr;
- err = dup_anon_vma(next, curr);
+ err = dup_anon_vma(next, curr, &anon_dup);
}
}
}
@@ -1018,6 +1023,9 @@ struct vm_area_struct *vma_merge(struct vma_iterator *vmi, struct mm_struct *mm,
return res;
prealloc_fail:
+ if (anon_dup)
+ unlink_anon_vmas(anon_dup);
+
anon_vma_fail:
if (merge_prev)
vma_next(vmi);
--
2.40.1
^ permalink raw reply [flat|nested] 5+ messages in thread