From: Yonghong Song <yonghong.song@linux.dev>
To: Sanghyun Park <sanghyun.park.cnu@gmail.com>,
ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org
Cc: bpf@vger.kernel.org, linux-kernel@vger.kernel.org, puranjay@kernel.org
Subject: Re: [PATCH v2] bpf: Fix use-after-free on mm_struct in bpf_find_vma()
Date: Mon, 1 Jun 2026 22:55:27 -0700 [thread overview]
Message-ID: <a775c0b8-07f3-4265-8cfd-ec01ffd9efbf@linux.dev> (raw)
In-Reply-To: <CAOrxSK5_7e4114VyfEU9htGi+UneuNt88fGVKOAa3_ZenPOFkA@mail.gmail.com>
On 5/29/26 1:01 AM, Sanghyun Park wrote:
> bpf_find_vma() reads task->mm without holding task_lock() or taking an
> mm reference via mmget()/mmget_not_zero(). When called on a foreign task
> obtained via bpf_task_from_pid(), a concurrent exit_mm() can free the
> mm_struct between the raw pointer read and mmap_read_trylock(mm),
> resulting in a use-after-free on the mm's mmap_lock.
>
> This is the same bug class fixed by commit d8e27d2d22b6 ("bpf: fix mm
> lifecycle in open-coded task_vma iterator") for the open-coded task_vma
> iterator, but bpf_find_vma() in the same file was missed by that fix.
>
> For the current task, task->mm is stable and needs no extra reference.
> For a foreign task, use get_task_mm() which acquires task_lock(), checks
> task->mm, and calls mmget() atomically, preventing the race with
> exit_mm(). The reference is dropped via mmput() after the mmap lock is
> released.
>
> Race:
> CPU0 (BPF program) CPU1 (exiting task)
> ============================ ==========================
> bpf_find_vma(foreign_task):
> mm = task->mm
> // raw read, no reference
> exit_mm():
> task->mm = NULL
> mmput(mm) -> frees mm_struct
> mmap_read_trylock(mm)
> // UAF: mm is freed
>
> Reproduction:
>
> 1. Build kernel >= 5.17 with CONFIG_KASAN=y, CONFIG_BPF_SYSCALL=y
> 2. Boot in a VM (QEMU works fine)
> 3. Compile the reproducer below:
> gcc -O2 -o repro -static repro.c -lbpf -lelf -lz
> 4. Run as root: ./repro
> 5. Check dmesg for: BUG: KASAN: slab-use-after-free in down_read_trylock
>
> The reproducer attaches a BPF program that calls bpf_find_vma() on a
> foreign task obtained via bpf_task_from_pid(). A racing thread
> repeatedly fork+exit's that task, creating a window where mm is freed.
>
> KASAN report (reproduced on 6.12.91, CONFIG_PREEMPT + KASAN):
>
> BUG: KASAN: slab-use-after-free in down_read_trylock+0x380/0x3f0
> Read of size 8 at addr ffff888003cd2fd0 by task repro/164451
>
> Call Trace:
> down_read_trylock+0x380/0x3f0
> bpf_find_vma+0xdd/0x360
> bpf_prog_708df9c9a3e172a7_main_f+0x8b/0x9e
> bpf_trampoline_6442513469+0x43/0xa3
>
> Freed by task 164453:
> kmem_cache_free+0x15d/0x4b0
> finish_task_switch.isra.0+0x4ab/0x810
>
> Fixes: 7c7e3d31e785 ("bpf: Introduce helper bpf_find_vma")
> Signed-off-by: Sanghyun Park <sanghyun.park.cnu@gmail.com>
> ---
> v2: Rebased onto bpf-next to fix merge conflict (no code changes).
>
> kernel/bpf/task_iter.c | 10 +++++++++-
> 1 file changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c
> index e791ae065c..015399e62b 100644
> --- a/kernel/bpf/task_iter.c
> +++ b/kernel/bpf/task_iter.c
> @@ -757,6 +757,7 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *,
> task, u64, start,
> struct vm_area_struct *vma;
> bool irq_work_busy = false;
> struct mm_struct *mm;
> + bool foreign = task != current;
> int ret = -ENOENT;
>
> if (flags)
> @@ -765,7 +766,12 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *,
> task, u64, start,
> if (!task)
> return -ENOENT;
>
> - mm = task->mm;
> + if (foreign) {
> + mm = get_task_mm(task);
> + } else {
> + mm = task->mm;
> + }
> +
> if (!mm)
> return -ENOENT;
>
> @@ -782,6 +788,8 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *,
> task, u64, start,
> ret = 0;
> }
> bpf_mmap_unlock_mm(work, mm);
> + if (foreign)
> + mmput(mm);
mmput may sleep. See the code:
void mmput(struct mm_struct *mm)
{
might_sleep();
if (atomic_dec_and_test(&mm->mm_users))
__mmput(mm);
}
But bpf_find_vma may be in non-sleepable prog context (rcu context).
So the fix does not work.
Also, there is a format issue in the diff.
> return ret;
> }
>
next prev parent reply other threads:[~2026-06-02 5:55 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-29 8:01 [PATCH v2] bpf: Fix use-after-free on mm_struct in bpf_find_vma() Sanghyun Park
2026-06-02 5:55 ` Yonghong Song [this message]
2026-06-09 10:26 ` Sanghyun Park
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=a775c0b8-07f3-4265-8cfd-ec01ffd9efbf@linux.dev \
--to=yonghong.song@linux.dev \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=linux-kernel@vger.kernel.org \
--cc=puranjay@kernel.org \
--cc=sanghyun.park.cnu@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.