[PATCH bpf-next v4 8/8] selftests/bpf: cast explicitly in the arena subprog and callback faults
From: Vineet Gupta
Date: Tue Nov 03 2026 - 13:23:04 EST
Stream tests fail with BPF_GCC, e.g.
test_stream_arena_fault_address:FAIL:stream__open_and_load unexpected error: -13
They call stream__open_and_load(), which loads every program in the object,
and two of those do not verify:
#481/11 stream_success/stream_arena_subprog_fault:FAIL
#481/12 stream_success/stream_arena_callback_fault:FAIL
Both dereference an arena pointer and leave the cast to the compiler:
int __arena *addr = (int __arena *)0xdeadbeef;
*addr = 1;
Without arena support __arena is only btf_type_tag("arena"), so no
addr_space_cast is emitted and the store is to a scalar, which the
verifier rejects. GCC splits it into byte stores, 0xdeadbeef not
being aligned:
r2=3735928559 ll
*(u8*)(r2+0)=1 <- plain store, no cast
Their siblings in the same file do not rely on the compiler; they use
bpf_addr_space_cast(), which emits the instruction byte by byte and
works anywhere. Do the same here.
The address space has to come off the local as well. Left on, a
compiler that supports arenas casts a second time for the
dereference, on a pointer the explicit cast has already converted:
r2 = addr_space_cast(r2, 0, 1)
r3 = addr_space_cast(r2, 0, 1)
*(u32*)(r3+0)=1
With it off, GCC with and without arena support and clang all emit the
same thing, which is what the test wants:
r2 = addr_space_cast(r2, 0, 1)
*(u32*)(r2+0)=1
What these two assert is the fault report, not how the pointer was
produced, so nothing they were testing is lost.
Measured on bpf-next with a stock bpf-gcc, test_progs before and
after. Every test that loads this object recovers, not just the arena
ones:
stream_arena_fault_address FAIL -> OK
stream_fd FAIL -> OK
stream_fd/blocking FAIL -> OK
stream_fd/edge FAIL -> OK
stream_fd/empty FAIL -> OK
stream_fd/hup FAIL -> OK
stream_fd/nmi_epoll FAIL -> OK
stream_fd/nonblock FAIL -> OK
stream_fd/open FAIL -> OK
stream_oversize FAIL -> OK
stream_partial_read FAIL -> OK
stream_success FAIL -> OK
stream_success/stream_arena_callback_fault FAIL -> OK
stream_success/stream_arena_subprog_fault FAIL -> OK
stream_syscall FAIL -> OK
and the subtests of the object that failed to load appear for the
first time:
stream_arena_fault_address/read_fault -> OK
stream_arena_fault_address/write_fault -> OK
stream_arena_fault_address/xchg_fault -> OK
stream_arena_fault_address/cmpxchg_fault -> OK
stream_arena_fault_address/load_acquire_fault -> OK
Signed-off-by: Vineet Gupta <vineet.gupta@xxxxxxxxx>
---
v3 -> v4: was 6/8. No longer drops #include <bpf_arena_common.h>,
which the arena_base() patch now needs in this file.
tools/testing/selftests/bpf/progs/stream.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/bpf/progs/stream.c b/tools/testing/selftests/bpf/progs/stream.c
index b4d88d0e01ad..8c49a130150b 100644
--- a/tools/testing/selftests/bpf/progs/stream.c
+++ b/tools/testing/selftests/bpf/progs/stream.c
@@ -341,9 +341,10 @@ int stream_arena_cmpxchg_fault(void *ctx)
static __noinline void subprog(void)
{
- int __arena *addr = (int __arena *)0xdeadbeef;
+ int *addr = (int *)0xdeadbeef;
arena_ptr = &arena;
+ bpf_addr_space_cast(addr, 0, 1);
*addr = 1;
}
@@ -364,9 +365,10 @@ int stream_arena_subprog_fault(void *ctx)
static __noinline int timer_cb(void *map, int *key, struct bpf_timer *timer)
{
- int __arena *addr = (int __arena *)0xdeadbeef;
+ int *addr = (int *)0xdeadbeef;
arena_ptr = &arena;
+ bpf_addr_space_cast(addr, 0, 1);
*addr = 1;
return 0;
}
--
2.53.0-Meta