Add a verifier selftest that fills a two-page arena, frees the page below the arena start through a scalar value, and checks that a third allocation is still unavailable.
Without the arena free range check, the out-of-range free can be inserted into the free range tree and then allocated again, so the test returns 3. With the fix, the out-of-range free is ignored and the focused test passes. Signed-off-by: Nuoqi Gui <[email protected]> --- tools/testing/selftests/bpf/progs/verifier_arena.c | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/verifier_arena.c b/tools/testing/selftests/bpf/progs/verifier_arena.c index df0e22d1a29b..b21a8895804f 100644 --- a/tools/testing/selftests/bpf/progs/verifier_arena.c +++ b/tools/testing/selftests/bpf/progs/verifier_arena.c @@ -11,6 +11,7 @@ #include <bpf_arena_common.h> #define private(name) SEC(".bss." #name) __hidden __attribute__((aligned(8))) +#define ARENA_VM_START_L32 (~0u - __PAGE_SIZE * 2 + 1) struct { __uint(type, BPF_MAP_TYPE_ARENA); @@ -93,6 +94,31 @@ int basic_alloc1(void *ctx) return 0; } +SEC("syscall") +__success __retval(0) +int free_pages_out_of_bounds(void *ctx) +{ +#if defined(__BPF_FEATURE_ADDR_SPACE_CAST) + __u64 page1, page2, no_page; + __u64 below_start = (__u32)(ARENA_VM_START_L32 - __PAGE_SIZE); + + page1 = (__u64)bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0); + if (!page1) + return 1; + page2 = (__u64)bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0); + if (!page2) + return 2; + + asm volatile("" : "+r"(below_start)); + bpf_arena_free_pages(&arena, (void __arena *)below_start, 1); + + no_page = (__u64)bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0); + if (no_page) + return 3; +#endif + return 0; +} + SEC("socket") __success __retval(0) int basic_alloc2_nosleep(void *ctx) -- 2.34.1

