On Wed, May 13, 2026 at 11:30 AM Daniel Hodges <[email protected]> wrote:
>
> arena_vm_open() only increments a refcount on the existing vma_list
> entry without creating a new entry for the child's VMA. After fork,
> vml->vma still points to the parent's VMA. When the parent unmaps
> (arena_vm_close decrements refcount but doesn't remove the entry),
> vml->vma becomes a dangling pointer. A subsequent bpf_arena_free_pages
> call reaches zap_pages() which dereferences the freed VMA via
> zap_vma_range(vml->vma, ...), causing a use-after-free:
>
> BUG: KASAN: slab-use-after-free in zap_vma_range+0xf2/0x100
> Read of size 8 at addr ff11000113ec9b10 by task test_progs/198
> Call Trace:
> zap_vma_range+0xf2/0x100
> arena_free_pages+0x6de/0x970
> bpf_prog_a2b540a82b1066f3_arena_free+0x8b/0xb6
> bpf_prog_test_run_syscall+0x3d3/0x8a0
>
> The same issue is triggered by __split_vma (partial munmap) and
> copy_vma (mremap), both of which call vm_ops->open.
>
> Fix this by giving each VMA its own vma_list entry instead of sharing
> one with a refcount. arena_vm_open now allocates a new entry for the
> new VMA, and arena_vm_close always removes and frees its own entry.
> If the allocation fails in arena_vm_open, vm_private_data is set to
> NULL and arena_vm_close handles this gracefully, meaning the VMA
> simply won't be zapped during arena page frees.
>
> Fixes: 317460317a02 ("bpf: Introduce bpf_arena.")
> Signed-off-by: Daniel Hodges <[email protected]>
> Assisted-by: Claude-Code:claude-opus-4-6
> ---
> kernel/bpf/arena.c | 19 +++++++++++++------
> 1 file changed, 13 insertions(+), 6 deletions(-)
>
> diff --git a/kernel/bpf/arena.c b/kernel/bpf/arena.c
> index 49a8f7b1beef..a3c46100dd12 100644
> --- a/kernel/bpf/arena.c
> +++ b/kernel/bpf/arena.c
> @@ -310,64 +310,71 @@ static int arena_map_check_btf(struct bpf_map *map,
> const struct btf *btf,
> }
>
> static u64 arena_map_mem_usage(const struct bpf_map *map)
> {
> return 0;
> }
>
> struct vma_list {
> struct vm_area_struct *vma;
> struct list_head head;
> - refcount_t mmap_count;
> };
>
> static int remember_vma(struct bpf_arena *arena, struct vm_area_struct *vma)
> {
> struct vma_list *vml;
>
> vml = kmalloc_obj(*vml);
> if (!vml)
> return -ENOMEM;
> - refcount_set(&vml->mmap_count, 1);
> vma->vm_private_data = vml;
> vml->vma = vma;
> list_add(&vml->head, &arena->vma_list);
> return 0;
> }
>
> static void arena_vm_open(struct vm_area_struct *vma)
> {
> - struct vma_list *vml = vma->vm_private_data;
> + struct bpf_map *map = vma->vm_file->private_data;
> + struct bpf_arena *arena = container_of(map, struct bpf_arena, map);
> + struct vma_list *vml;
>
> - refcount_inc(&vml->mmap_count);
> + vml = kmalloc_obj(*vml);
> + if (!vml) {
> + vma->vm_private_data = NULL;
> + return;
> + }
I'm tired of seeing the same garbage patch from claude for the 3rd time.
Please make sure you use claude on the latest kernel.
The fix 4fddde2a732d ("bpf: Fix use-after-free in arena_vm_close on fork")
landed a month ago.
pw-bot: cr