Re: [PATCH bpf-next v6 2/3] bpf: Avoid faultable build ID reads under mm locks
From: bot+bpf-ci
Date: Thu May 21 2026 - 19:33:46 EST
> diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
> index 4c753e02c415..95336c0e8b56 100644
> --- a/kernel/bpf/stackmap.c
> +++ b/kernel/bpf/stackmap.c
[ ... ]
> @@ -174,6 +175,107 @@ static inline void stack_map_build_id_set_valid(struct bpf_stack_build_id *id,
> memcpy(id->build_id, build_id, BUILD_ID_SIZE_MAX);
> }
>
> +struct stack_map_vma_lock {
> + bool vma_locked;
> + struct vm_area_struct *vma;
> + struct mm_struct *mm;
> +};
> +
> +static struct vm_area_struct *stack_map_lock_vma(struct stack_map_vma_lock *lock, unsigned long ip)
> +{
> + struct mm_struct *mm = lock->mm;
> + struct vm_area_struct *vma;
> +
> + if (WARN_ON_ONCE(!mm))
> + return NULL;
> +
> + vma = lock_vma_under_rcu(mm, ip);
> + if (vma)
> + goto vma_locked;
> +
> + /*
> + * Taking mmap_read_lock() is unsafe here, because the caller
> + * BPF program might already hold it, causing a deadlock.
> + */
> + if (!mmap_read_trylock(mm))
> + return NULL;
> +
> + vma = vma_lookup(mm, ip);
> + if (!vma) {
> + mmap_read_unlock(mm);
> + return NULL;
> + }
> +
> +#ifdef CONFIG_PER_VMA_LOCK
> + if (!vma_start_read_locked(vma)) {
> + mmap_read_unlock(mm);
> + return NULL;
> + }
> + mmap_read_unlock(mm);
> +#else
> + mmap_read_unlock(mm);
> + return NULL;
> +#endif
Does the fallback for kernels built without CONFIG_PER_VMA_LOCK completely
disable build ID parsing?
Looking at the #else branch, it unconditionally drops mmap_read_lock and
returns NULL. This causes the caller to receive a NULL VMA for every IP,
which skips parsing and falls back to returning IP-only traces.
Could this instead keep mmap_read_lock held, return the VMA, and allow the
caller to extract the file reference, vm_pgoff, and vm_start before safely
dropping the lock?
This was raised by sashiko-bot@xxxxxxxxxx in v4 and v5 at:
https://lore.kernel.org/bpf/20260515012547.EFF40C2BCB3@xxxxxxxxxxxxxxx/
> +vma_locked:
> + lock->vma_locked = true;
> + lock->vma = vma;
> + return vma;
> +}
> +
> +static void stack_map_unlock_vma(struct stack_map_vma_lock *lock)
> +{
> + struct vm_area_struct *vma = lock->vma;
> +
> + if (lock->vma_locked) {
> + if (WARN_ON_ONCE(!vma))
> + goto out;
> + vma_end_read(vma);
> + }
> +out:
> + lock->vma_locked = false;
> + lock->vma = NULL;
> +}
> +
> +static void stack_map_get_build_id_offset_sleepable(struct bpf_stack_build_id *id_offs,
> + u32 trace_nr)
> +{
> + struct mm_struct *mm = current->mm;
> + struct stack_map_vma_lock lock = {
> + .vma_locked = false,
> + .vma = NULL,
> + .mm = mm,
> + };
> + struct vm_area_struct *vma;
> + struct file *file;
> + u64 offset;
> + u64 ip;
> +
> + for (u32 i = 0; i < trace_nr; i++) {
> + ip = READ_ONCE(id_offs[i].ip);
> +
> + vma = stack_map_lock_vma(&lock, ip);
> + if (!vma || !vma->vm_file) {
> + stack_map_build_id_set_ip(&id_offs[i]);
> + stack_map_unlock_vma(&lock);
> + continue;
> + }
Is using !vma->vm_file to classify anonymous VMAs fully correct?
Per mm-vma.md's VMA classification rules, the canonical test for anonymous
VMAs is vma_is_anonymous() (i.e. !vma->vm_ops). Some anonymous VMAs carry a
vm_file reference. For example, private mappings of /dev/zero set via
vma_set_anonymous() leave vm_file populated while clearing vm_ops.
While this won't cause a crash (build_id_parse_file would fail gracefully),
it causes unnecessary sleepable read attempts on pseudo-files.
This was raised by bot+bpf-ci@xxxxxxxxxx and sashiko-bot@xxxxxxxxxx across
v3, v4, and v5 at:
https://lore.kernel.org/bpf/0e2084173f17252ff227aba064e534682b52a7a451280c0df4041825ebae30b6@xxxxxxxxxxxxxxx/
> +
> + file = get_file(vma->vm_file);
> + offset = stack_map_build_id_offset(vma->vm_pgoff, vma->vm_start, ip);
> + stack_map_unlock_vma(&lock);
> +
> + /* build_id_parse_file() may block on filesystem reads */
> + if (build_id_parse_file(file, id_offs[i].build_id, NULL)) {
> + stack_map_build_id_set_ip(&id_offs[i]);
> + fput(file);
> + continue;
> + }
> + fput(file);
> +
> + stack_map_build_id_set_valid(&id_offs[i], offset, id_offs[i].build_id);
> + }
> +}
[ ... ]
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/26258400944