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


Reply via email to