Re: [PATCH v2 bpf-next 3/3] selftests/bpf: Add a runtime test for private stack and stack arguments

From: Alexei Starovoitov

Date: Thu Nov 05 2026 - 11:52:31 EST


On Wed, Nov 04, 2026 at 02:04 AM Chen Pei <cp0613@xxxxxxxxxxxxxxxxx> wrote:
> .../selftests/bpf/private_stack_runtime.h | 12 ++
> .../bpf/prog_tests/private_stack_runtime.c | 84 +++++++++++
> .../bpf/progs/private_stack_runtime.c | 140 ++++++++++++++++++
> 3 files changed, 236 insertions(+)

bpf ci is right in the other email.

pw-bot: cr

Also, the test runs on riscv64 only. BPF CI runs arm64 and not riscv64.
arm64 has the same combination and no test for it.
The run time part has nothing specific to riscv64.
The __jited patterns pin the frame sizes that clang picks for C code.
zero_stack doesn't use the private stack.
It's the only reason for serial_.

Two asm progs in verifier_stack_arg.c are enough.
BPF_PROG_TEST_RUN runs a raw_tp prog. No need to attach it.
The test runs on x86-64, arm64 and riscv64.
On x86-64 both frames stay on the kernel stack.

Like (not even compile tested):

diff --git a/tools/testing/selftests/bpf/progs/verifier_stack_arg.c b/tools/testing/selftests/bpf/progs/verifier_stack_arg.c
index abf319c..9423048 100644
--- a/tools/testing/selftests/bpf/progs/verifier_stack_arg.c
+++ b/tools/testing/selftests/bpf/progs/verifier_stack_arg.c
@@ -667,6 +667,53 @@ __naked void stack_arg_precision_fallback(void)
);
}

+/* Writes both ends of its frame, then reads args 9, 10 and the frame of the caller. */
+__naked __noinline __used
+static long priv_stack_10args(long a, long b, long c, long d, long e, long f, long g, long h,
+ long i, long *j)
+{
+ asm volatile (
+ "r1 = 0;"
+ "*(u64 *)(r10 - 8) = r1;"
+ "*(u64 *)(r10 - 64) = r1;"
+ "r0 = *(u64 *)(r11 + 32);"
+ "r1 = *(u64 *)(r11 + 40);"
+ "r1 = *(u64 *)(r1 + 0);"
+ "r0 += r1;"
+ "exit;"
+ );
+}
+
+/*
+ * A frame of 64 bytes in a raw_tp prog goes to the private stack.
+ * arm64 and riscv64 pass args 9 and 10 on the kernel stack.
+ */
+SEC("raw_tp")
+__description("stack_arg: private stack in the caller and in the callee")
+__success __retval(890)
+__naked void stack_arg_priv_stack(void)
+{
+ asm volatile (
+ "r1 = 800;"
+ "*(u64 *)(r10 - 64) = r1;"
+ "r1 = r10;"
+ "r1 += -64;"
+ "*(u64 *)(r11 - 40) = r1;"
+ "*(u64 *)(r11 - 32) = 90;"
+ "*(u64 *)(r11 - 24) = 8;"
+ "*(u64 *)(r11 - 16) = 7;"
+ "*(u64 *)(r11 - 8) = 6;"
+ "r1 = 1;"
+ "r2 = 2;"
+ "r3 = 3;"
+ "r4 = 4;"
+ "r5 = 5;"
+ "call priv_stack_10args;"
+ "exit;"
+ ::: __clobber_all
+ );
+}
+
#else

SEC("socket")