Commit 7329e3eb authored by Liam Howlett's avatar Liam Howlett Committed by Andrew Morton

mm/mempolicy: fix mbind_range() arguments to vma_merge()

Fuzzing produced an invalid argument to vma_merge() which was caught by
the newly added verification of the number of VMAs being removed on
process exit.  Analyzing the failure eventually resulted in finding an
issue with the search of a VMA that started at address 0, which caused an
underflow and thus the loss of many VMAs being tracked in the tree.  Fix
the underflow by changing the search of the maple tree to use the start
address directly.

Link: https://lkml.kernel.org/r/20221015021135.2816178-1-Liam.Howlett@oracle.com
Fixes: 66850be5 ("mm/mempolicy: use vma iterator & maple state instead of vma linked list")
Signed-off-by: default avatarLiam R. Howlett <Liam.Howlett@oracle.com>
Reported-by: default avatarkernel test robot <oliver.sang@intel.com>
  Link: https://lore.kernel.org/r/202210052318.5ad10912-oliver.sang@intel.com
Cc: Yu Zhao <yuzhao@google.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent cef408e7
...@@ -787,17 +787,22 @@ static int vma_replace_policy(struct vm_area_struct *vma, ...@@ -787,17 +787,22 @@ static int vma_replace_policy(struct vm_area_struct *vma,
static int mbind_range(struct mm_struct *mm, unsigned long start, static int mbind_range(struct mm_struct *mm, unsigned long start,
unsigned long end, struct mempolicy *new_pol) unsigned long end, struct mempolicy *new_pol)
{ {
MA_STATE(mas, &mm->mm_mt, start - 1, start - 1); MA_STATE(mas, &mm->mm_mt, start, start);
struct vm_area_struct *prev; struct vm_area_struct *prev;
struct vm_area_struct *vma; struct vm_area_struct *vma;
int err = 0; int err = 0;
pgoff_t pgoff; pgoff_t pgoff;
prev = mas_find_rev(&mas, 0); prev = mas_prev(&mas, 0);
if (prev && (start < prev->vm_end)) if (unlikely(!prev))
vma = prev; mas_set(&mas, start);
else
vma = mas_next(&mas, end - 1); vma = mas_find(&mas, end - 1);
if (WARN_ON(!vma))
return 0;
if (start > vma->vm_start)
prev = vma;
for (; vma; vma = mas_next(&mas, end - 1)) { for (; vma; vma = mas_next(&mas, end - 1)) {
unsigned long vmstart = max(start, vma->vm_start); unsigned long vmstart = max(start, vma->vm_start);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment