FAILED: patch "[PATCH] mm/mempolicy: fix use-after-free of VMA iterator" failed to apply to 6.2-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 6.2-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.2.y
git checkout FETCH_HEAD
git cherry-pick -x f4e9e0e69468583c2c6d9d5c7bfc975e292bf188
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2023042437-profane-confidant-7987@gregkh' --subject-prefix 'PATCH 6.2.y' HEAD^..
Possible dependencies:
f4e9e0e69468 ("mm/mempolicy: fix use-after-free of VMA iterator")9760ebffbf55 ("mm: switch vma_merge(), split_vma(), and __split_vma to vma iterator") 47d9644de92c ("nommu: convert nommu to using the vma iterator")a27a11f92fe2 ("mm/mremap: use vmi version of vma_merge()")076f16bf7698 ("mmap: use vmi version of vma_merge()")0c0c5bffd0a2 ("mmap: pass through vmi iterator to __split_vma()")178e22ac2078 ("madvise: use vmi iterator for __split_vma() and vma_merge()") f10c2abcdac4 ("mempolicy: convert to vma iterator")37598f5a9d8b ("mlock: convert mlock to vma iterator")2286a6914c77 ("mm: change mprotect_fixup to vma iterator")11a9b90274f6 ("userfaultfd: use vma iterator")f2ebfe43ba6c ("mm: add temporary vma iterator versions of vma_merge(), split_vma(), and __split_vma()") 183654ce26a5 ("mmap: change do_mas_munmap and do_mas_aligned_munmap() to use vma iterator") 0378c0a0e9e4 ("mm/mmap: remove preallocation from do_mas_align_munmap()")92fed82047d7 ("mm/mmap: convert brk to use vma iterator")baabcfc93d3b ("mm/mmap: fix typo in comment")c5d5546ea065 ("maple_tree: remove the parameter entry of mas_preallocate") 5ab0fc155dc0 ("Sync mm-stable with mm-hotfixes-stable to pick up dependent patches")
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From f4e9e0e69468583c2c6d9d5c7bfc975e292bf188 Mon Sep 17 00:00:00 2001
From: "Liam R. Howlett" <[email protected]>
Date: Mon, 10 Apr 2023 11:22:05 -0400
Subject: [PATCH] mm/mempolicy: fix use-after-free of VMA iterator
set_mempolicy_home_node() iterates over a list of VMAs and calls mbind_range() on each VMA, which also iterates over the singular list of the VMA passed in and potentially splits the VMA. Since the VMA iterator is not passed through, set_mempolicy_home_node() may now point to a stale node in the VMA tree. This can result in a UAF as reported by syzbot.
Avoid the stale maple tree node by passing the VMA iterator through to the underlying call to split_vma().
mbind_range() is also overly complicated, since there are two calling functions and one already handles iterating over the VMAs. Simplify mbind_range() to only handle merging and splitting of the VMAs.
Align the new loop in do_mbind() and existing loop in set_mempolicy_home_node() to use the reduced mbind_range() function. This allows for a single location of the range calculation and avoids constantly looking up the previous VMA (since this is a loop over the VMAs).
mm/mempolicy.c +49 -55
@@ -790,61 +790,50 @@ static int vma_replace_policy(struct vm_area_struct *vma,return err; } -/* Step 2: apply policy to a range and do splits. */ -static int mbind_range (struct mm_struct *mm,unsigned long start, -unsigned long end,struct mempolicy *new_pol) +/* Split or merge the VMA (if required) and apply the new policy */ +static int mbind_range (struct vma_iterator *vmi,struct vm_area_struct *vma, +struct vm_area_struct **prev,unsigned long start, +unsigned long end,struct mempolicy *new_pol) { -VMA_ITERATOR (vmi, mm, start); -struct vm_area_struct *prev; -struct vm_area_struct *vma; -int err =0 ; +struct vm_area_struct *merged; +unsigned long vmstart, vmend;pgoff_t pgoff; +int err; - prev =vma_prev (&vmi); - vma =vma_find (&vmi, end); -if (WARN_ON (!vma)) + vmend =min (end, vma->vm_end); +if (start > vma->vm_start) { + *prev = vma; + vmstart = start; + }else { + vmstart = vma->vm_start; + } + +if (mpol_equal (vma_policy (vma), new_pol))return 0 ; -if (start > vma->vm_start) - prev = vma; - - do { - unsigned long vmstart = max(start, vma->vm_start); - unsigned long vmend = min(end, vma->vm_end); - - if (mpol_equal(vma_policy(vma), new_pol)) - goto next; - - pgoff = vma->vm_pgoff + - ((vmstart - vma->vm_start) >> PAGE_SHIFT); - prev = vma_merge(&vmi, mm, prev, vmstart, vmend, vma->vm_flags, - vma->anon_vma, vma->vm_file, pgoff, - new_pol, vma->vm_userfaultfd_ctx, - anon_vma_name(vma)); - if (prev) { - vma = prev; - goto replace; - } - if (vma->vm_start != vmstart) { - err = split_vma(&vmi, vma, vmstart, 1); - if (err) - goto out; - } - if (vma->vm_end != vmend) { - err = split_vma(&vmi, vma, vmend, 0); - if (err) - goto out; - } -replace: - err = vma_replace_policy(vma, new_pol); + pgoff = vma->vm_pgoff + ((vmstart - vma->vm_start) >>PAGE_SHIFT ); + merged =vma_merge (vmi, vma->vm_mm, *prev, vmstart, vmend, vma->vm_flags, + vma->anon_vma, vma->vm_file, pgoff, new_pol, + vma->vm_userfaultfd_ctx,anon_vma_name (vma)); +if (merged) { + *prev = merged; +return vma_replace_policy (merged, new_pol); + } + +if (vma->vm_start != vmstart) { + err =split_vma (vmi, vma, vmstart,1 );if (err) - goto out; -next: - prev = vma; - } for_each_vma_range(vmi, vma, end); +return err; + } -out: - return err; +if (vma->vm_end != vmend) { + err =split_vma (vmi, vma, vmend,0 ); +if (err) +return err; + } + + *prev = vma; +return vma_replace_policy (vma, new_pol); }/* Set the process memory policy */
@@ -1259,6 +1248,8 @@ static long do_mbind(unsigned long start, unsigned long len, nodemask_t *nmask, unsigned long flags) {struct mm_struct *mm = current->mm; +struct vm_area_struct *vma, *prev; +struct vma_iterator vmi;struct mempolicy *new;unsigned long end;int err;
@@ -1328,7 +1319,13 @@ static long do_mbind(unsigned long start, unsigned long len, goto up_out; } - err =mbind_range (mm, start, end, new); +vma_iter_init (&vmi, mm, start); + prev =vma_prev (&vmi); +for_each_vma_range (vmi, vma, end) { + err =mbind_range (&vmi, vma, &prev, start, end, new); +if (err) +break ; + }if (!err) {int nr_failed =0 ;
@@ -1489,10 +1486,8 @@ SYSCALL_DEFINE4(set_mempolicy_home_node, unsigned long, start, unsigned long, le unsigned long, home_node, unsigned long, flags) {struct mm_struct *mm = current->mm; -struct vm_area_struct *vma; +struct vm_area_struct *vma, *prev;struct mempolicy *new, *old; -unsigned long vmstart; -unsigned long vmend;unsigned long end;int err = -ENOENT ;VMA_ITERATOR (vmi, mm, start);
@@ -1521,6 +1516,7 @@ SYSCALL_DEFINE4(set_mempolicy_home_node, unsigned long, start, unsigned long, leif (end == start)return 0 ;mmap_write_lock (mm); + prev =vma_prev (&vmi);for_each_vma_range (vmi, vma, end) {/* * If any vma in the range got policy other than MPOL_BIND
@@ -1541,9 +1537,7 @@ SYSCALL_DEFINE4(set_mempolicy_home_node, unsigned long, start, unsigned long, le } new->home_node = home_node; - vmstart =max (start, vma->vm_start); - vmend =min (end, vma->vm_end); - err =mbind_range (mm, vmstart, vmend, new); + err =mbind_range (&vmi, vma, &prev, start, end, new);mpol_put (new);if (err)break ;