summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@kernel.org>2026-10-27 19:03:14 +0000
committerAlexei Starovoitov <ast@kernel.org>2026-10-28 04:07:03 +0000
commitb433cdb1cc4f599d840ab33d97f8498625bef629 (patch)
tree053cc1a10c0f7cadbe1d9c32b7249b441be76731
parent4d0f560f4926417f010ce38f8628c41bcad29c9f (diff)
selftests/bpf: Test stack arguments across may_goto
Each test passes arguments 6-8 on the stack. Thus it uses all the registers in which the JITs of x86-64, arm64 and riscv64 pass stack arguments. may_goto then ------------------------------------------- --------------------------- 70000 iterations in the callee the callee reads the args the time is up in the callee the callee reads the args 70000 iterations in the caller, after the the caller calls the callee writes of the args 70000 iterations have one look at the clock. Without the fix on x86-64 the second test fails, and the first test fails with the hpet clocksource. The third test passes there. The result depends on the registers that the C code uses. Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://patch.msgid.link/20261027190314.1440199-20-alexei.starovoitov@gmail.com
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_stack_arg.c119
1 files changed, 119 insertions, 0 deletions
diff --git a/tools/testing/selftests/bpf/progs/verifier_stack_arg.c b/tools/testing/selftests/bpf/progs/verifier_stack_arg.c
index b9f799f6e405..15a12497e074 100644
--- a/tools/testing/selftests/bpf/progs/verifier_stack_arg.c
+++ b/tools/testing/selftests/bpf/progs/verifier_stack_arg.c
@@ -433,6 +433,125 @@ __naked void stack_arg_sequential_calls(void)
);
}
+/*
+ * A JIT passes the first stack arguments in registers. may_goto is not a call: they must be
+ * the same after it, also when it looks at the clock. That is once in 65535 iterations.
+ */
+__naked __noinline __used
+static long loops_then_reads_8args(long a, long b, long c, long d, long e, long f, long g, long h)
+{
+ asm volatile (
+ "r1 = 0;"
+ "1:"
+ "may_goto 2f;"
+ "r1 += 1;"
+ "if r1 < 70000 goto 1b;"
+ "2:"
+ "r0 = *(u64 *)(r11 + 8);"
+ "r1 = *(u64 *)(r11 + 16);"
+ "r0 += r1;"
+ "r1 = *(u64 *)(r11 + 24);"
+ "r0 += r1;"
+ "exit;"
+ );
+}
+
+SEC("tc")
+__description("stack_arg: may_goto looks at the clock, then the callee reads its args")
+__success __retval(876)
+__naked void stack_arg_may_goto_in_callee(void)
+{
+ asm volatile (
+ "r1 = 1;"
+ "r2 = 2;"
+ "r3 = 3;"
+ "r4 = 4;"
+ "r5 = 5;"
+ "*(u64 *)(r11 - 24) = 800;"
+ "*(u64 *)(r11 - 16) = 70;"
+ "*(u64 *)(r11 - 8) = 6;"
+ "call loops_then_reads_8args;"
+ "exit;"
+ ::: __clobber_all
+ );
+}
+
+__naked __noinline __used
+static long spins_then_reads_8args(long a, long b, long c, long d, long e, long f, long g, long h)
+{
+ asm volatile (
+ "1:"
+ "may_goto 2f;"
+ "goto 1b;"
+ "2:"
+ "r0 = *(u64 *)(r11 + 8);"
+ "r1 = *(u64 *)(r11 + 16);"
+ "r0 += r1;"
+ "r1 = *(u64 *)(r11 + 24);"
+ "r0 += r1;"
+ "exit;"
+ );
+}
+
+SEC("tc")
+__description("stack_arg: the time of may_goto is up, then the callee reads its args")
+__success __retval(876)
+__naked void stack_arg_may_goto_timeout_in_callee(void)
+{
+ asm volatile (
+ "r1 = 1;"
+ "r2 = 2;"
+ "r3 = 3;"
+ "r4 = 4;"
+ "r5 = 5;"
+ "*(u64 *)(r11 - 24) = 800;"
+ "*(u64 *)(r11 - 16) = 70;"
+ "*(u64 *)(r11 - 8) = 6;"
+ "call spins_then_reads_8args;"
+ "exit;"
+ ::: __clobber_all
+ );
+}
+
+__naked __noinline __used
+static long reads_8args(long a, long b, long c, long d, long e, long f, long g, long h)
+{
+ asm volatile (
+ "r0 = *(u64 *)(r11 + 8);"
+ "r1 = *(u64 *)(r11 + 16);"
+ "r0 += r1;"
+ "r1 = *(u64 *)(r11 + 24);"
+ "r0 += r1;"
+ "exit;"
+ );
+}
+
+SEC("tc")
+__description("stack_arg: may_goto looks at the clock between the stores of the args and the call")
+__success __retval(876)
+__naked void stack_arg_may_goto_in_caller(void)
+{
+ asm volatile (
+ "*(u64 *)(r11 - 24) = 800;"
+ "*(u64 *)(r11 - 16) = 70;"
+ "*(u64 *)(r11 - 8) = 6;"
+ "r6 = 0;"
+ "1:"
+ "may_goto 2f;"
+ "r6 += 1;"
+ "if r6 < 70000 goto 1b;"
+ "2:"
+ "r1 = 1;"
+ "r2 = 2;"
+ "r3 = 3;"
+ "r4 = 4;"
+ "r5 = 5;"
+ "call reads_8args;"
+ "exit;"
+ ::: __clobber_all
+ );
+}
+
#else
SEC("socket")