From: Daniel Borkmann <daniel@iogearbox.net>
To: memxor@gmail.com
Cc: eddyz87@gmail.com, puranjay@kernel.org, info@starlabs.sg,
bpf@vger.kernel.org
Subject: [PATCH bpf-next 5/6] selftests/bpf: Add arena fault test for load-acquire
Date: Thu, 6 Aug 2026 16:39:23 +0200 [thread overview]
Message-ID: <20260806143924.319238-5-daniel@iogearbox.net> (raw)
In-Reply-To: <20260806143924.319238-1-daniel@iogearbox.net>
Add stream_arena_load_acquire_fault, which performs a load-acquire from an
unmapped arena address, next to the existing read and write fault tests.
The test covers both halves of the JIT bug that treated a load-acquire as
a store when populating its exception table entry:
- the fault has to be reported as a READ, and at the address held by
the source register, which __stderr() and test_address() check, and
- the destination register has to be cleared by the fault handler,
which the program checks by poisoning it before the load-acquire
and returning it, so __retval(0) fails if it is left untouched
# LDLIBS=-static PKG_CONFIG='pkg-config --static' ./vmtest.sh -- ./test_progs -t stream_arena_fault_address
[...]
#462/1 stream_arena_fault_address/read_fault:OK
#462/2 stream_arena_fault_address/write_fault:OK
#462/3 stream_arena_fault_address/load_acquire_fault:OK
#462 stream_arena_fault_address:OK
Summary: 1/3 PASSED, 0 SKIPPED, 0 FAILED
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
---
.../testing/selftests/bpf/prog_tests/stream.c | 2 +
tools/testing/selftests/bpf/progs/stream.c | 46 +++++++++++++++++++
2 files changed, 48 insertions(+)
diff --git a/tools/testing/selftests/bpf/prog_tests/stream.c b/tools/testing/selftests/bpf/prog_tests/stream.c
index c3cce5c292bd..15dd3ae2a84b 100644
--- a/tools/testing/selftests/bpf/prog_tests/stream.c
+++ b/tools/testing/selftests/bpf/prog_tests/stream.c
@@ -103,6 +103,8 @@ void test_stream_arena_fault_address(void)
test_address(skel->progs.stream_arena_read_fault, &skel->bss->fault_addr);
if (test__start_subtest("write_fault"))
test_address(skel->progs.stream_arena_write_fault, &skel->bss->fault_addr);
+ if (test__start_subtest("load_acquire_fault"))
+ test_address(skel->progs.stream_arena_load_acquire_fault, &skel->bss->fault_addr);
stream__destroy(skel);
}
diff --git a/tools/testing/selftests/bpf/progs/stream.c b/tools/testing/selftests/bpf/progs/stream.c
index 8d8e53d37266..82c855889180 100644
--- a/tools/testing/selftests/bpf/progs/stream.c
+++ b/tools/testing/selftests/bpf/progs/stream.c
@@ -185,6 +185,52 @@ int stream_arena_read_fault(void *ctx)
return 0;
}
+SEC("syscall")
+__arch_x86_64
+__arch_arm64
+__success __retval(0)
+__stderr("ERROR: Arena READ access at unmapped address 0x{{.*}}")
+__stderr("CPU: {{[0-9]+}} UID: 0 PID: {{[0-9]+}} Comm: {{.*}}")
+__stderr("Call trace:\n"
+"{{([a-zA-Z_][a-zA-Z0-9_]*\\+0x[0-9a-fA-F]+/0x[0-9a-fA-F]+\n"
+"|[ \t]+[^\n]+\n)*}}")
+int stream_arena_load_acquire_fault(void *ctx)
+{
+ struct bpf_arena *ptr = (void *)&arena;
+ u64 user_vm_start, val;
+
+ /*
+ * Prevent GCC bounds warning: casting &arena to struct bpf_arena *
+ * triggers bounds checking since the map definition is smaller than
+ * struct bpf_arena. barrier_var() makes the pointer opaque to GCC,
+ * preventing the bounds analysis.
+ */
+ barrier_var(ptr);
+ user_vm_start = ptr->user_vm_start;
+ fault_addr = user_vm_start + 0x7fff;
+ bpf_addr_space_cast(user_vm_start, 0, 1);
+ /*
+ * A load-acquire is of BPF_STX class, but reads from src_reg into
+ * dst_reg. Poison dst_reg up front: the fault has to be reported
+ * as a READ from the src_reg address, and the exception handler has
+ * to clear dst_reg, so the returned value must be 0.
+ *
+ * The load-acquire is open coded as BPF_ATOMIC_OP(BPF_W, BPF_LOAD_ACQ,
+ * BPF_REG_0, BPF_REG_1, 0x7fff) since <linux/filter.h> cannot be
+ * included alongside vmlinux.h.
+ */
+ asm volatile (
+ "r1 = %[user_vm_start];"
+ "r0 = 1;"
+ ".8byte 0x000001007fff10c3;" /* r0 = load_acquire((u32 *)(r1 + 0x7fff)) */
+ "%[val] = r0;"
+ : [val] "=r" (val)
+ : [user_vm_start] "r" (user_vm_start)
+ : "r0", "r1"
+ );
+ return val;
+}
+
static __noinline void subprog(void)
{
int __arena *addr = (int __arena *)0xdeadbeef;
--
2.43.0
next prev parent reply other threads:[~2026-08-06 14:39 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-06 14:39 [PATCH bpf-next 1/6] bpf: Reject load-acquire from pointers requiring fault protection Daniel Borkmann
2026-08-06 14:39 ` [PATCH bpf-next 2/6] bpf, riscv: Add and use bpf_atomic_is_load_acq() helper Daniel Borkmann
2026-08-06 14:39 ` [PATCH bpf-next 3/6] bpf, x86: Fix exception table metadata for arena load-acquire Daniel Borkmann
2026-08-06 14:58 ` sashiko-bot
2026-08-06 15:01 ` Daniel Borkmann
2026-08-06 14:39 ` [PATCH bpf-next 4/6] bpf, arm64: " Daniel Borkmann
2026-08-06 14:42 ` Puranjay Mohan
2026-08-06 14:39 ` Daniel Borkmann [this message]
2026-08-06 20:09 ` [PATCH bpf-next 5/6] selftests/bpf: Add arena fault test for load-acquire Daniel Borkmann
2026-08-06 14:39 ` [PATCH bpf-next 6/6] selftests/bpf: Add load-acquire test for probe-memory pointer types Daniel Borkmann
2026-08-06 15:01 ` [PATCH bpf-next 1/6] bpf: Reject load-acquire from pointers requiring fault protection sashiko-bot
2026-08-06 15:25 ` Daniel Borkmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260806143924.319238-5-daniel@iogearbox.net \
--to=daniel@iogearbox.net \
--cc=bpf@vger.kernel.org \
--cc=eddyz87@gmail.com \
--cc=info@starlabs.sg \
--cc=memxor@gmail.com \
--cc=puranjay@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox