The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH bpf-next v6] bpf: Fix use-after-free on mm_struct in bpf_find_vma()
@ 2026-06-30  3:25 Sanghyun Park
  2026-07-01 19:48 ` Andrii Nakryiko
  2026-07-07  7:50 ` patchwork-bot+netdevbpf
  0 siblings, 2 replies; 5+ messages in thread
From: Sanghyun Park @ 2026-06-30  3:25 UTC (permalink / raw)
  To: Yonghong Song, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko
  Cc: Sanghyun Park, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Kumar Kartikeya Dwivedi, John Fastabend, KP Singh,
	Stanislav Fomichev, Hao Luo, Jiri Olsa, Emil Tsalapatis,
	Puranjay Mohan, bpf, linux-kernel

bpf_find_vma() reads task->mm and calls mmap_read_trylock(mm) without
holding a reference on the mm. On a foreign task, a concurrent exit_mm()
can free the mm_struct between the lockless read and the trylock,
resulting in a use-after-free. mm_struct is not SLAB_TYPESAFE_BY_RCU.

For the current task, task->mm is stable. For a foreign task, pin the mm
under task->alloc_lock and release it with mmput_async(), mirroring commit
d8e27d2d22b6 ("bpf: fix mm lifecycle in open-coded task_vma iterator").
Use spin_trylock() instead of get_task_mm() so BPF context does not block
on alloc_lock. Reject irqs-disabled contexts and !CONFIG_MMU on the
foreign-task path because dropping the mm reference is not safe there.

Race:

  CPU0 (BPF program)                  CPU1 (exiting task)
  ============================        ==========================
  bpf_find_vma(foreign_task):
    mm = task->mm
                                      exit_mm():
                                        task->mm = NULL
                                        mmput(mm) -> frees mm_struct
    mmap_read_trylock(mm)
        // UAF on mm

Fixes: 7c7e3d31e785 ("bpf: Introduce helper bpf_find_vma")
Acked-by: Yonghong Song <yonghong.song@linux.dev>
Signed-off-by: Sanghyun Park <sanghyun.park.cnu@gmail.com>
---
v6:
 - Restore bpf_iter_mmput_async() because bpf_iter_task_vma_destroy()
   still uses it.
 - Keep the direct mmput_async() call in bpf_find_vma(), but guard it with
   CONFIG_MMU because mmput_async() is declared only for CONFIG_MMU builds.
v5: https://lore.kernel.org/bpf/20260630023443.3026627-2-sanghyun.park.cnu@gmail.com/
 - Replace bpf_iter_mmput_async() with mmput_async() directly as suggested
   by Yonghong.
 - Add Yonghong's Acked-by.
v4: https://lore.kernel.org/bpf/20260610024637.343364-1-sanghyun.park.cnu@gmail.com/
 - Use [PATCH bpf-next] subject as requested by Alexei.
 - Add the missing BPF maintainers/reviewers to Cc.
v3: https://lore.kernel.org/bpf/20260609105216.3536839-1-sanghyun.park.cnu@gmail.com/
 - Drop get_task_mm()+mmput(); mirror d8e27d2d22b6 with alloc_lock
   trylock + mmput_async(). (Yonghong Song)
 - Reject irqs-disabled contexts on the foreign-task path.
 - Reject foreign-task path when !CONFIG_MMU: bpf_iter_mmput_async()
   falls back to mmput() which may sleep, and bpf_find_vma() can run
   in non-sleepable context.
 - Shorten the foreign-task rationale comment and trim the changelog body.
 - Fix the v2's whitespace damage.
v2: https://lore.kernel.org/bpf/CAOrxSK5_7e4114VyfEU9htGi+UneuNt88fGVKOAa3_ZenPOFkA@mail.gmail.com/

 kernel/bpf/task_iter.c | 36 +++++++++++++++++++++++++++++++++---
 1 file changed, 33 insertions(+), 3 deletions(-)

diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c
index fc5f463ca529a..1d56193caf5e4 100644
--- a/kernel/bpf/task_iter.c
+++ b/kernel/bpf/task_iter.c
@@ -760,6 +760,7 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *, task, u64, start,
 	struct mmap_unlock_irq_work *work = NULL;
 	struct vm_area_struct *vma;
 	bool irq_work_busy = false;
+	bool mmput_needed = false;
 	struct mm_struct *mm;
 	int ret = -ENOENT;
 
@@ -769,14 +770,38 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *, task, u64, start,
 	if (!task)
 		return -ENOENT;
 
-	mm = task->mm;
+	if (task == current) {
+		mm = task->mm;
+	} else {
+		/*
+		 * Foreign task: pin task->mm against a concurrent exit_mm().
+		 * Use trylock on alloc_lock instead of get_task_mm()'s
+		 * blocking task_lock() to avoid deadlocking the target task.
+		 */
+		if (!IS_ENABLED(CONFIG_MMU))
+			return -EOPNOTSUPP;
+		if (irqs_disabled())
+			return -EBUSY;
+		if (!spin_trylock(&task->alloc_lock))
+			return -EBUSY;
+		mm = task->mm;
+		if (mm && !(task->flags & PF_KTHREAD)) {
+			mmget(mm);
+			mmput_needed = true;
+		} else {
+			mm = NULL;
+		}
+		spin_unlock(&task->alloc_lock);
+	}
 	if (!mm)
 		return -ENOENT;
 
 	irq_work_busy = bpf_mmap_unlock_get_irq_work(&work);
 
-	if (irq_work_busy || !mmap_read_trylock(mm))
-		return -EBUSY;
+	if (irq_work_busy || !mmap_read_trylock(mm)) {
+		ret = -EBUSY;
+		goto out;
+	}
 
 	vma = find_vma(mm, start);
 
@@ -786,6 +811,11 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *, task, u64, start,
 		ret = 0;
 	}
 	bpf_mmap_unlock_mm(work, mm);
+out:
+#ifdef CONFIG_MMU
+	if (mmput_needed)
+		mmput_async(mm);
+#endif
 	return ret;
 }
 
-- 
2.48.1

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH bpf-next v6] bpf: Fix use-after-free on mm_struct in bpf_find_vma()
  2026-06-30  3:25 [PATCH bpf-next v6] bpf: Fix use-after-free on mm_struct in bpf_find_vma() Sanghyun Park
@ 2026-07-01 19:48 ` Andrii Nakryiko
  2026-07-06 11:28   ` Puranjay Mohan
  2026-07-07  7:50 ` patchwork-bot+netdevbpf
  1 sibling, 1 reply; 5+ messages in thread
From: Andrii Nakryiko @ 2026-07-01 19:48 UTC (permalink / raw)
  To: Sanghyun Park, Puranjay Mohan
  Cc: Yonghong Song, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Kumar Kartikeya Dwivedi, John Fastabend, KP Singh,
	Stanislav Fomichev, Hao Luo, Jiri Olsa, Emil Tsalapatis, bpf,
	linux-kernel

On Mon, Jun 29, 2026 at 8:25 PM Sanghyun Park
<sanghyun.park.cnu@gmail.com> wrote:
>
> bpf_find_vma() reads task->mm and calls mmap_read_trylock(mm) without
> holding a reference on the mm. On a foreign task, a concurrent exit_mm()
> can free the mm_struct between the lockless read and the trylock,
> resulting in a use-after-free. mm_struct is not SLAB_TYPESAFE_BY_RCU.
>
> For the current task, task->mm is stable. For a foreign task, pin the mm
> under task->alloc_lock and release it with mmput_async(), mirroring commit
> d8e27d2d22b6 ("bpf: fix mm lifecycle in open-coded task_vma iterator").
> Use spin_trylock() instead of get_task_mm() so BPF context does not block
> on alloc_lock. Reject irqs-disabled contexts and !CONFIG_MMU on the
> foreign-task path because dropping the mm reference is not safe there.
>
> Race:
>
>   CPU0 (BPF program)                  CPU1 (exiting task)
>   ============================        ==========================
>   bpf_find_vma(foreign_task):
>     mm = task->mm
>                                       exit_mm():
>                                         task->mm = NULL
>                                         mmput(mm) -> frees mm_struct
>     mmap_read_trylock(mm)
>         // UAF on mm
>
> Fixes: 7c7e3d31e785 ("bpf: Introduce helper bpf_find_vma")
> Acked-by: Yonghong Song <yonghong.song@linux.dev>
> Signed-off-by: Sanghyun Park <sanghyun.park.cnu@gmail.com>
> ---

Puranjay, PTAL, I think you've been fixing similar issue in
bpf_iter_task_vma_new(), would be nice for you to check this fix as
well. Thanks!

> v6:
>  - Restore bpf_iter_mmput_async() because bpf_iter_task_vma_destroy()
>    still uses it.
>  - Keep the direct mmput_async() call in bpf_find_vma(), but guard it with
>    CONFIG_MMU because mmput_async() is declared only for CONFIG_MMU builds.
> v5: https://lore.kernel.org/bpf/20260630023443.3026627-2-sanghyun.park.cnu@gmail.com/
>  - Replace bpf_iter_mmput_async() with mmput_async() directly as suggested
>    by Yonghong.
>  - Add Yonghong's Acked-by.
> v4: https://lore.kernel.org/bpf/20260610024637.343364-1-sanghyun.park.cnu@gmail.com/
>  - Use [PATCH bpf-next] subject as requested by Alexei.
>  - Add the missing BPF maintainers/reviewers to Cc.
> v3: https://lore.kernel.org/bpf/20260609105216.3536839-1-sanghyun.park.cnu@gmail.com/
>  - Drop get_task_mm()+mmput(); mirror d8e27d2d22b6 with alloc_lock
>    trylock + mmput_async(). (Yonghong Song)
>  - Reject irqs-disabled contexts on the foreign-task path.
>  - Reject foreign-task path when !CONFIG_MMU: bpf_iter_mmput_async()
>    falls back to mmput() which may sleep, and bpf_find_vma() can run
>    in non-sleepable context.
>  - Shorten the foreign-task rationale comment and trim the changelog body.
>  - Fix the v2's whitespace damage.
> v2: https://lore.kernel.org/bpf/CAOrxSK5_7e4114VyfEU9htGi+UneuNt88fGVKOAa3_ZenPOFkA@mail.gmail.com/
>
>  kernel/bpf/task_iter.c | 36 +++++++++++++++++++++++++++++++++---
>  1 file changed, 33 insertions(+), 3 deletions(-)
>
> diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c
> index fc5f463ca529a..1d56193caf5e4 100644
> --- a/kernel/bpf/task_iter.c
> +++ b/kernel/bpf/task_iter.c
> @@ -760,6 +760,7 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *, task, u64, start,
>         struct mmap_unlock_irq_work *work = NULL;
>         struct vm_area_struct *vma;
>         bool irq_work_busy = false;
> +       bool mmput_needed = false;
>         struct mm_struct *mm;
>         int ret = -ENOENT;
>
> @@ -769,14 +770,38 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *, task, u64, start,
>         if (!task)
>                 return -ENOENT;
>
> -       mm = task->mm;
> +       if (task == current) {
> +               mm = task->mm;
> +       } else {
> +               /*
> +                * Foreign task: pin task->mm against a concurrent exit_mm().
> +                * Use trylock on alloc_lock instead of get_task_mm()'s
> +                * blocking task_lock() to avoid deadlocking the target task.
> +                */
> +               if (!IS_ENABLED(CONFIG_MMU))
> +                       return -EOPNOTSUPP;
> +               if (irqs_disabled())
> +                       return -EBUSY;
> +               if (!spin_trylock(&task->alloc_lock))
> +                       return -EBUSY;
> +               mm = task->mm;
> +               if (mm && !(task->flags & PF_KTHREAD)) {
> +                       mmget(mm);
> +                       mmput_needed = true;
> +               } else {
> +                       mm = NULL;
> +               }
> +               spin_unlock(&task->alloc_lock);
> +       }
>         if (!mm)
>                 return -ENOENT;
>
>         irq_work_busy = bpf_mmap_unlock_get_irq_work(&work);
>
> -       if (irq_work_busy || !mmap_read_trylock(mm))
> -               return -EBUSY;
> +       if (irq_work_busy || !mmap_read_trylock(mm)) {
> +               ret = -EBUSY;
> +               goto out;
> +       }
>
>         vma = find_vma(mm, start);
>
> @@ -786,6 +811,11 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *, task, u64, start,
>                 ret = 0;
>         }
>         bpf_mmap_unlock_mm(work, mm);
> +out:
> +#ifdef CONFIG_MMU
> +       if (mmput_needed)
> +               mmput_async(mm);
> +#endif
>         return ret;
>  }
>
> --
> 2.48.1

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH bpf-next v6] bpf: Fix use-after-free on mm_struct in bpf_find_vma()
  2026-07-01 19:48 ` Andrii Nakryiko
@ 2026-07-06 11:28   ` Puranjay Mohan
  2026-07-07  7:43     ` Daniel Borkmann
  0 siblings, 1 reply; 5+ messages in thread
From: Puranjay Mohan @ 2026-07-06 11:28 UTC (permalink / raw)
  To: Andrii Nakryiko
  Cc: Sanghyun Park, Yonghong Song, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Kumar Kartikeya Dwivedi, John Fastabend, KP Singh,
	Stanislav Fomichev, Hao Luo, Jiri Olsa, Emil Tsalapatis, bpf,
	linux-kernel

On Wed, Jul 1, 2026 at 8:48 PM Andrii Nakryiko
<andrii.nakryiko@gmail.com> wrote:
>
> On Mon, Jun 29, 2026 at 8:25 PM Sanghyun Park
> <sanghyun.park.cnu@gmail.com> wrote:
> >
> > bpf_find_vma() reads task->mm and calls mmap_read_trylock(mm) without
> > holding a reference on the mm. On a foreign task, a concurrent exit_mm()
> > can free the mm_struct between the lockless read and the trylock,
> > resulting in a use-after-free. mm_struct is not SLAB_TYPESAFE_BY_RCU.
> >
> > For the current task, task->mm is stable. For a foreign task, pin the mm
> > under task->alloc_lock and release it with mmput_async(), mirroring commit
> > d8e27d2d22b6 ("bpf: fix mm lifecycle in open-coded task_vma iterator").
> > Use spin_trylock() instead of get_task_mm() so BPF context does not block
> > on alloc_lock. Reject irqs-disabled contexts and !CONFIG_MMU on the
> > foreign-task path because dropping the mm reference is not safe there.
> >
> > Race:
> >
> >   CPU0 (BPF program)                  CPU1 (exiting task)
> >   ============================        ==========================
> >   bpf_find_vma(foreign_task):
> >     mm = task->mm
> >                                       exit_mm():
> >                                         task->mm = NULL
> >                                         mmput(mm) -> frees mm_struct
> >     mmap_read_trylock(mm)
> >         // UAF on mm
> >
> > Fixes: 7c7e3d31e785 ("bpf: Introduce helper bpf_find_vma")
> > Acked-by: Yonghong Song <yonghong.song@linux.dev>
> > Signed-off-by: Sanghyun Park <sanghyun.park.cnu@gmail.com>
> > ---
>
> Puranjay, PTAL, I think you've been fixing similar issue in
> bpf_iter_task_vma_new(), would be nice for you to check this fix as
> well. Thanks!
>
> > v6:
> >  - Restore bpf_iter_mmput_async() because bpf_iter_task_vma_destroy()
> >    still uses it.
> >  - Keep the direct mmput_async() call in bpf_find_vma(), but guard it with
> >    CONFIG_MMU because mmput_async() is declared only for CONFIG_MMU builds.
> > v5: https://lore.kernel.org/bpf/20260630023443.3026627-2-sanghyun.park.cnu@gmail.com/
> >  - Replace bpf_iter_mmput_async() with mmput_async() directly as suggested
> >    by Yonghong.
> >  - Add Yonghong's Acked-by.
> > v4: https://lore.kernel.org/bpf/20260610024637.343364-1-sanghyun.park.cnu@gmail.com/
> >  - Use [PATCH bpf-next] subject as requested by Alexei.
> >  - Add the missing BPF maintainers/reviewers to Cc.
> > v3: https://lore.kernel.org/bpf/20260609105216.3536839-1-sanghyun.park.cnu@gmail.com/
> >  - Drop get_task_mm()+mmput(); mirror d8e27d2d22b6 with alloc_lock
> >    trylock + mmput_async(). (Yonghong Song)
> >  - Reject irqs-disabled contexts on the foreign-task path.
> >  - Reject foreign-task path when !CONFIG_MMU: bpf_iter_mmput_async()
> >    falls back to mmput() which may sleep, and bpf_find_vma() can run
> >    in non-sleepable context.
> >  - Shorten the foreign-task rationale comment and trim the changelog body.
> >  - Fix the v2's whitespace damage.
> > v2: https://lore.kernel.org/bpf/CAOrxSK5_7e4114VyfEU9htGi+UneuNt88fGVKOAa3_ZenPOFkA@mail.gmail.com/
> >
> >  kernel/bpf/task_iter.c | 36 +++++++++++++++++++++++++++++++++---
> >  1 file changed, 33 insertions(+), 3 deletions(-)
> >
> > diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c
> > index fc5f463ca529a..1d56193caf5e4 100644
> > --- a/kernel/bpf/task_iter.c
> > +++ b/kernel/bpf/task_iter.c
> > @@ -760,6 +760,7 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *, task, u64, start,
> >         struct mmap_unlock_irq_work *work = NULL;
> >         struct vm_area_struct *vma;
> >         bool irq_work_busy = false;
> > +       bool mmput_needed = false;
> >         struct mm_struct *mm;
> >         int ret = -ENOENT;
> >
> > @@ -769,14 +770,38 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *, task, u64, start,
> >         if (!task)
> >                 return -ENOENT;
> >
> > -       mm = task->mm;
> > +       if (task == current) {
> > +               mm = task->mm;
> > +       } else {
> > +               /*
> > +                * Foreign task: pin task->mm against a concurrent exit_mm().
> > +                * Use trylock on alloc_lock instead of get_task_mm()'s
> > +                * blocking task_lock() to avoid deadlocking the target task.
> > +                */
> > +               if (!IS_ENABLED(CONFIG_MMU))
> > +                       return -EOPNOTSUPP;
> > +               if (irqs_disabled())
> > +                       return -EBUSY;
> > +               if (!spin_trylock(&task->alloc_lock))
> > +                       return -EBUSY;
> > +               mm = task->mm;
> > +               if (mm && !(task->flags & PF_KTHREAD)) {
> > +                       mmget(mm);
> > +                       mmput_needed = true;
> > +               } else {
> > +                       mm = NULL;
> > +               }
> > +               spin_unlock(&task->alloc_lock);
> > +       }
> >         if (!mm)
> >                 return -ENOENT;
> >
> >         irq_work_busy = bpf_mmap_unlock_get_irq_work(&work);
> >
> > -       if (irq_work_busy || !mmap_read_trylock(mm))
> > -               return -EBUSY;
> > +       if (irq_work_busy || !mmap_read_trylock(mm)) {
> > +               ret = -EBUSY;
> > +               goto out;
> > +       }
> >
> >         vma = find_vma(mm, start);
> >
> > @@ -786,6 +811,11 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *, task, u64, start,
> >                 ret = 0;
> >         }
> >         bpf_mmap_unlock_mm(work, mm);
> > +out:
> > +#ifdef CONFIG_MMU
> > +       if (mmput_needed)
> > +               mmput_async(mm);
> > +#endif
> >         return ret;
> >  }
> >
> > --
> > 2.48.1

Thanks for this, it looks good to me.

Reviewed-by: Puranjay Mohan <puranjay@kernel.org>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH bpf-next v6] bpf: Fix use-after-free on mm_struct in bpf_find_vma()
  2026-07-06 11:28   ` Puranjay Mohan
@ 2026-07-07  7:43     ` Daniel Borkmann
  0 siblings, 0 replies; 5+ messages in thread
From: Daniel Borkmann @ 2026-07-07  7:43 UTC (permalink / raw)
  To: Puranjay Mohan, Andrii Nakryiko
  Cc: Sanghyun Park, Yonghong Song, Alexei Starovoitov, Andrii Nakryiko,
	Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Kumar Kartikeya Dwivedi, John Fastabend, KP Singh,
	Stanislav Fomichev, Hao Luo, Jiri Olsa, Emil Tsalapatis, bpf,
	linux-kernel

On 7/6/26 1:28 PM, Puranjay Mohan wrote:
> On Wed, Jul 1, 2026 at 8:48 PM Andrii Nakryiko
> <andrii.nakryiko@gmail.com> wrote:
>>
>> On Mon, Jun 29, 2026 at 8:25 PM Sanghyun Park
>> <sanghyun.park.cnu@gmail.com> wrote:
>>>
>>> bpf_find_vma() reads task->mm and calls mmap_read_trylock(mm) without
>>> holding a reference on the mm. On a foreign task, a concurrent exit_mm()
>>> can free the mm_struct between the lockless read and the trylock,
>>> resulting in a use-after-free. mm_struct is not SLAB_TYPESAFE_BY_RCU.
>>>
>>> For the current task, task->mm is stable. For a foreign task, pin the mm
>>> under task->alloc_lock and release it with mmput_async(), mirroring commit
>>> d8e27d2d22b6 ("bpf: fix mm lifecycle in open-coded task_vma iterator").
>>> Use spin_trylock() instead of get_task_mm() so BPF context does not block
>>> on alloc_lock. Reject irqs-disabled contexts and !CONFIG_MMU on the
>>> foreign-task path because dropping the mm reference is not safe there.
>>>
>>> Race:
>>>
>>>    CPU0 (BPF program)                  CPU1 (exiting task)
>>>    ============================        ==========================
>>>    bpf_find_vma(foreign_task):
>>>      mm = task->mm
>>>                                        exit_mm():
>>>                                          task->mm = NULL
>>>                                          mmput(mm) -> frees mm_struct
>>>      mmap_read_trylock(mm)
>>>          // UAF on mm
>>>
>>> Fixes: 7c7e3d31e785 ("bpf: Introduce helper bpf_find_vma")
>>> Acked-by: Yonghong Song <yonghong.song@linux.dev>
>>> Signed-off-by: Sanghyun Park <sanghyun.park.cnu@gmail.com>
>>> ---
>>
>> Puranjay, PTAL, I think you've been fixing similar issue in
>> bpf_iter_task_vma_new(), would be nice for you to check this fix as
>> well. Thanks!
>>
>>> v6:
>>>   - Restore bpf_iter_mmput_async() because bpf_iter_task_vma_destroy()
>>>     still uses it.
>>>   - Keep the direct mmput_async() call in bpf_find_vma(), but guard it with
>>>     CONFIG_MMU because mmput_async() is declared only for CONFIG_MMU builds.
>>> v5: https://lore.kernel.org/bpf/20260630023443.3026627-2-sanghyun.park.cnu@gmail.com/
>>>   - Replace bpf_iter_mmput_async() with mmput_async() directly as suggested
>>>     by Yonghong.
>>>   - Add Yonghong's Acked-by.
>>> v4: https://lore.kernel.org/bpf/20260610024637.343364-1-sanghyun.park.cnu@gmail.com/
>>>   - Use [PATCH bpf-next] subject as requested by Alexei.
>>>   - Add the missing BPF maintainers/reviewers to Cc.
>>> v3: https://lore.kernel.org/bpf/20260609105216.3536839-1-sanghyun.park.cnu@gmail.com/
>>>   - Drop get_task_mm()+mmput(); mirror d8e27d2d22b6 with alloc_lock
>>>     trylock + mmput_async(). (Yonghong Song)
>>>   - Reject irqs-disabled contexts on the foreign-task path.
>>>   - Reject foreign-task path when !CONFIG_MMU: bpf_iter_mmput_async()
>>>     falls back to mmput() which may sleep, and bpf_find_vma() can run
>>>     in non-sleepable context.
>>>   - Shorten the foreign-task rationale comment and trim the changelog body.
>>>   - Fix the v2's whitespace damage.
>>> v2: https://lore.kernel.org/bpf/CAOrxSK5_7e4114VyfEU9htGi+UneuNt88fGVKOAa3_ZenPOFkA@mail.gmail.com/
>>>
>>>   kernel/bpf/task_iter.c | 36 +++++++++++++++++++++++++++++++++---
>>>   1 file changed, 33 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c
>>> index fc5f463ca529a..1d56193caf5e4 100644
>>> --- a/kernel/bpf/task_iter.c
>>> +++ b/kernel/bpf/task_iter.c
>>> @@ -760,6 +760,7 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *, task, u64, start,
>>>          struct mmap_unlock_irq_work *work = NULL;
>>>          struct vm_area_struct *vma;
>>>          bool irq_work_busy = false;
>>> +       bool mmput_needed = false;
>>>          struct mm_struct *mm;
>>>          int ret = -ENOENT;
>>>
>>> @@ -769,14 +770,38 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *, task, u64, start,
>>>          if (!task)
>>>                  return -ENOENT;
>>>
>>> -       mm = task->mm;
>>> +       if (task == current) {
>>> +               mm = task->mm;
>>> +       } else {
>>> +               /*
>>> +                * Foreign task: pin task->mm against a concurrent exit_mm().
>>> +                * Use trylock on alloc_lock instead of get_task_mm()'s
>>> +                * blocking task_lock() to avoid deadlocking the target task.
>>> +                */
>>> +               if (!IS_ENABLED(CONFIG_MMU))
>>> +                       return -EOPNOTSUPP;
>>> +               if (irqs_disabled())
>>> +                       return -EBUSY;
>>> +               if (!spin_trylock(&task->alloc_lock))
>>> +                       return -EBUSY;
>>> +               mm = task->mm;
>>> +               if (mm && !(task->flags & PF_KTHREAD)) {
>>> +                       mmget(mm);
>>> +                       mmput_needed = true;
>>> +               } else {
>>> +                       mm = NULL;
>>> +               }
>>> +               spin_unlock(&task->alloc_lock);
>>> +       }
>>>          if (!mm)
>>>                  return -ENOENT;
>>>
>>>          irq_work_busy = bpf_mmap_unlock_get_irq_work(&work);
>>>
>>> -       if (irq_work_busy || !mmap_read_trylock(mm))
>>> -               return -EBUSY;
>>> +       if (irq_work_busy || !mmap_read_trylock(mm)) {
>>> +               ret = -EBUSY;
>>> +               goto out;
>>> +       }
>>>
>>>          vma = find_vma(mm, start);
>>>
>>> @@ -786,6 +811,11 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *, task, u64, start,
>>>                  ret = 0;
>>>          }
>>>          bpf_mmap_unlock_mm(work, mm);
>>> +out:
>>> +#ifdef CONFIG_MMU
>>> +       if (mmput_needed)
>>> +               mmput_async(mm);
>>> +#endif
>>>          return ret;
>>>   }
>>>
>>> --
>>> 2.48.1
> 
> Thanks for this, it looks good to me.
> 
> Reviewed-by: Puranjay Mohan <puranjay@kernel.org>

Applied, thanks! Could either you or Sanghyun look into the pre-existing
sashiko-reported issue as well?

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH bpf-next v6] bpf: Fix use-after-free on mm_struct in bpf_find_vma()
  2026-06-30  3:25 [PATCH bpf-next v6] bpf: Fix use-after-free on mm_struct in bpf_find_vma() Sanghyun Park
  2026-07-01 19:48 ` Andrii Nakryiko
@ 2026-07-07  7:50 ` patchwork-bot+netdevbpf
  1 sibling, 0 replies; 5+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-07-07  7:50 UTC (permalink / raw)
  To: Sanghyun Park
  Cc: yonghong.song, ast, daniel, andrii, martin.lau, eddyz87, song,
	memxor, john.fastabend, kpsingh, sdf, haoluo, jolsa, emil,
	puranjay, bpf, linux-kernel

Hello:

This patch was applied to bpf/bpf-next.git (master)
by Daniel Borkmann <daniel@iogearbox.net>:

On Tue, 30 Jun 2026 12:25:43 +0900 you wrote:
> bpf_find_vma() reads task->mm and calls mmap_read_trylock(mm) without
> holding a reference on the mm. On a foreign task, a concurrent exit_mm()
> can free the mm_struct between the lockless read and the trylock,
> resulting in a use-after-free. mm_struct is not SLAB_TYPESAFE_BY_RCU.
> 
> For the current task, task->mm is stable. For a foreign task, pin the mm
> under task->alloc_lock and release it with mmput_async(), mirroring commit
> d8e27d2d22b6 ("bpf: fix mm lifecycle in open-coded task_vma iterator").
> Use spin_trylock() instead of get_task_mm() so BPF context does not block
> on alloc_lock. Reject irqs-disabled contexts and !CONFIG_MMU on the
> foreign-task path because dropping the mm reference is not safe there.
> 
> [...]

Here is the summary with links:
  - [bpf-next,v6] bpf: Fix use-after-free on mm_struct in bpf_find_vma()
    https://git.kernel.org/bpf/bpf-next/c/311e11cfbfbf

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-07-07  7:50 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-30  3:25 [PATCH bpf-next v6] bpf: Fix use-after-free on mm_struct in bpf_find_vma() Sanghyun Park
2026-07-01 19:48 ` Andrii Nakryiko
2026-07-06 11:28   ` Puranjay Mohan
2026-07-07  7:43     ` Daniel Borkmann
2026-07-07  7:50 ` patchwork-bot+netdevbpf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox