On Tue Jun 30, 2026 at 6:12 AM EDT, Yiyang Chen wrote:
> Add a verifier_arena case that fills a two-page arena, calls
> bpf_arena_free_pages() with a scalar address one page below the arena
> base, and then verifies that another allocation is still rejected.
>
> Before the runtime guard, the invalid free can repopulate the free
> tree with an out-of-domain offset and the final allocation succeeds.
>
> Signed-off-by: Yiyang Chen <[email protected]>

Reviewed-by: Emil Tsalapatis <[email protected]>

Nit/question below.

> ---
>  .../selftests/bpf/progs/verifier_arena.c      | 41 ++++++++++++++++---
>  1 file changed, 36 insertions(+), 5 deletions(-)
>
> diff --git a/tools/testing/selftests/bpf/progs/verifier_arena.c 
> b/tools/testing/selftests/bpf/progs/verifier_arena.c
> index 62e282f4448aa..b4bd134646607 100644
> --- a/tools/testing/selftests/bpf/progs/verifier_arena.c
> +++ b/tools/testing/selftests/bpf/progs/verifier_arena.c
> @@ -12,15 +12,17 @@
>  
>  #define private(name) SEC(".bss." #name) __hidden __attribute__((aligned(8)))
>  
> +#ifdef __TARGET_ARCH_arm64
> +#define ARENA_VM_START ((1ull << 32) | (~0u - __PAGE_SIZE * 2 + 1))
> +#else
> +#define ARENA_VM_START ((1ull << 44) | (~0u - __PAGE_SIZE * 2 + 1))
> +#endif
> +
>  struct {
>       __uint(type, BPF_MAP_TYPE_ARENA);
>       __uint(map_flags, BPF_F_MMAPABLE);
>       __uint(max_entries, 2); /* arena of two pages close to 32-bit boundary*/
> -#ifdef __TARGET_ARCH_arm64
> -        __ulong(map_extra, (1ull << 32) | (~0u - __PAGE_SIZE * 2 + 1)); /* 
> start of mmap() region */
> -#else
> -        __ulong(map_extra, (1ull << 44) | (~0u - __PAGE_SIZE * 2 + 1)); /* 
> start of mmap() region */
> -#endif
> +     __ulong(map_extra, ARENA_VM_START); /* start of mmap() region */
>  } arena SEC(".maps");
>  
>  SEC("socket")
> @@ -93,6 +95,35 @@ int basic_alloc1(void *ctx)
>       return 0;
>  }
>  
> +SEC("syscall")
> +__success __retval(0)
> +int free_scalar_below_arena(void *ctx)
> +{
> +     void __arena *page1, *page2, *page3;
> +     __u64 bad_addr = ARENA_VM_START - __PAGE_SIZE;
> +
> +     page1 = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
> +     if (!page1)
> +             return 1;
> +
> +     page2 = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
> +     if (!page2)
> +             return 2;
> +
> +     page3 = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
> +     if (page3)
> +             return 3;
> +
> +     asm volatile("" : "+r"(bad_addr));

Why the asm volatile? We use it right underneath, what does this give
us.

> +     bpf_arena_free_pages(&arena, (void __arena *)bad_addr, 1);
> +
> +     page3 = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
> +     if (page3)
> +             return 4;
> +
> +     return 0;
> +}
> +
>  SEC("socket")
>  __success __retval(0)
>  int basic_alloc2_nosleep(void *ctx)


Reply via email to