xref: /linux/tools/testing/selftests/bpf/progs/stack_arg_precision.c (revision b2128290c29902315e632ea59e0504d6bc9e9b42)
16e277efbSYonghong Song // SPDX-License-Identifier: GPL-2.0
26e277efbSYonghong Song /* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
36e277efbSYonghong Song 
46e277efbSYonghong Song #include <vmlinux.h>
56e277efbSYonghong Song #include <bpf/bpf_helpers.h>
66e277efbSYonghong Song #include "../test_kmods/bpf_testmod_kfunc.h"
76e277efbSYonghong Song #include "bpf_misc.h"
86e277efbSYonghong Song 
9*90e43f1bSPuranjay Mohan #if (defined(__TARGET_ARCH_x86) || defined(__TARGET_ARCH_arm64)) && \
10*90e43f1bSPuranjay Mohan 	defined(__BPF_FEATURE_STACK_ARGUMENT)
116e277efbSYonghong Song 
126e277efbSYonghong Song /* Force kfunc extern BTF generation for inline asm call below.
136e277efbSYonghong Song  * Uses its own SEC so it's not included as a .text subprog.
146e277efbSYonghong Song  * The '?' prefix sets autoload=false so libbpf won't load it.
156e277efbSYonghong Song  */
166e277efbSYonghong Song SEC("?tc")
176e277efbSYonghong Song int __btf_kfunc_gen(struct __sk_buff *ctx)
186e277efbSYonghong Song {
196e277efbSYonghong Song 	char buf[8] = {};
206e277efbSYonghong Song 
216e277efbSYonghong Song 	return bpf_kfunc_call_stack_arg_mem(0, 0, 0, 0, 0, buf, sizeof(buf));
226e277efbSYonghong Song }
236e277efbSYonghong Song 
246e277efbSYonghong Song /*
256e277efbSYonghong Song  * Test precision backtracking across bpf-to-bpf call for kfunc stack arg.
266e277efbSYonghong Song  * subprog_call_mem_kfunc receives a size as incoming stack arg (arg6)
276e277efbSYonghong Song  * and forwards it as mem__sz (arg7) to bpf_kfunc_call_stack_arg_mem.
286e277efbSYonghong Song  */
296e277efbSYonghong Song __naked __noinline __used
306e277efbSYonghong Song static long subprog_call_mem_kfunc(long a, long b, long c, long d, long e, long size)
316e277efbSYonghong Song {
326e277efbSYonghong Song 	asm volatile (
336e277efbSYonghong Song 		"r1 = *(u64 *)(r11 + 8);"	/* r1 = incoming arg6 (size) */
346e277efbSYonghong Song 		"r2 = 0x0807060504030201 ll;"	/* r2 = buf contents */
356e277efbSYonghong Song 		"*(u64 *)(r10 - 8) = r2;"	/* store buf to stack */
366e277efbSYonghong Song 		"r2 = r10;"
376e277efbSYonghong Song 		"r2 += -8;"			/* r2 = &buf */
386e277efbSYonghong Song 		"*(u64 *)(r11 - 8) = r2;"	/* outgoing arg6 = buf */
396e277efbSYonghong Song 		"*(u64 *)(r11 - 16) = r1;"	/* outgoing arg7 = size */
406e277efbSYonghong Song 		"r1 = 1;"
416e277efbSYonghong Song 		"r2 = 2;"
426e277efbSYonghong Song 		"r3 = 3;"
436e277efbSYonghong Song 		"r4 = 4;"
446e277efbSYonghong Song 		"r5 = 5;"
456e277efbSYonghong Song 		"call %[bpf_kfunc_call_stack_arg_mem];"
466e277efbSYonghong Song 		"exit;"
476e277efbSYonghong Song 		:
486e277efbSYonghong Song 		: __imm(bpf_kfunc_call_stack_arg_mem)
496e277efbSYonghong Song 		: __clobber_all
506e277efbSYonghong Song 	);
516e277efbSYonghong Song }
526e277efbSYonghong Song 
536e277efbSYonghong Song SEC("tc")
546e277efbSYonghong Song __description("stack_arg: precision backtracking across bpf2bpf call for kfunc")
556e277efbSYonghong Song __success
566e277efbSYonghong Song __log_level(2)
576e277efbSYonghong Song __flag(BPF_F_TEST_STATE_FREQ)
586e277efbSYonghong Song __btf_func_path("btf__stack_arg_precision.bpf.o")
596e277efbSYonghong Song __msg("mark_precise: frame1: last_idx 26 first_idx 13 subseq_idx -1")
606e277efbSYonghong Song __msg("mark_precise: frame1: regs= stack= before 25: (b7) r5 = 5")
616e277efbSYonghong Song __msg("mark_precise: frame1: regs= stack= before 24: (b7) r4 = 4")
626e277efbSYonghong Song __msg("mark_precise: frame1: regs= stack= before 23: (b7) r3 = 3")
636e277efbSYonghong Song __msg("mark_precise: frame1: regs= stack= before 22: (b7) r2 = 2")
646e277efbSYonghong Song __msg("mark_precise: frame1: regs= stack= before 21: (b7) r1 = 1")
656e277efbSYonghong Song __msg("mark_precise: frame1: regs= stack= before 20: (7b) *(u64 *)(r11 -16) = r1")
666e277efbSYonghong Song __msg("mark_precise: frame1: regs=r1 stack= before 19: (7b) *(u64 *)(r11 -8) = r2")
676e277efbSYonghong Song __msg("mark_precise: frame1: regs=r1 stack= before 18: (07) r2 += -8")
686e277efbSYonghong Song __msg("mark_precise: frame1: regs=r1 stack= before 17: (bf) r2 = r10")
696e277efbSYonghong Song __msg("mark_precise: frame1: regs=r1 stack= before 16: (7b) *(u64 *)(r10 -8) = r2")
706e277efbSYonghong Song __msg("mark_precise: frame1: regs=r1 stack= before 14: (18) r2 = 0x807060504030201")
716e277efbSYonghong Song __msg("mark_precise: frame1: regs=r1 stack= before 13: (79) r1 = *(u64 *)(r11 +8)")
726e277efbSYonghong Song __msg("mark_precise: frame1: parent state regs= stack=:  frame1: R10=fp0")
736e277efbSYonghong Song __msg("mark_precise: frame0: parent state regs= stack=:  R10=fp0")
746e277efbSYonghong Song __msg("mark_precise: frame1: last_idx 11 first_idx 11 subseq_idx 13")
756e277efbSYonghong Song __msg("mark_precise: frame1: regs= stack= before 11: (85) call pc+1")
766e277efbSYonghong Song __msg("mark_precise: frame0: parent state regs= stack=:  R1=1 R2=2 R3=3 R4=4 R5=5 R10=fp0")
776e277efbSYonghong Song __msg("mark_precise: frame0: last_idx 9 first_idx 7 subseq_idx 11")
786e277efbSYonghong Song __msg("mark_precise: frame0: regs= stack= before 9: (05) goto pc+1")
796e277efbSYonghong Song __msg("mark_precise: frame0: regs= stack= before 8: (7a) *(u64 *)(r11 -8) = 4")
806e277efbSYonghong Song __msg("mark_precise: frame1: last_idx 26 first_idx 13 subseq_idx -1 ")
816e277efbSYonghong Song __msg("mark_precise: frame1: regs= stack= before 25: (b7) r5 = 5")
826e277efbSYonghong Song __msg("mark_precise: frame1: regs= stack= before 24: (b7) r4 = 4")
836e277efbSYonghong Song __msg("mark_precise: frame1: regs= stack= before 23: (b7) r3 = 3")
846e277efbSYonghong Song __msg("mark_precise: frame1: regs= stack= before 22: (b7) r2 = 2")
856e277efbSYonghong Song __msg("mark_precise: frame1: regs= stack= before 21: (b7) r1 = 1")
866e277efbSYonghong Song __msg("mark_precise: frame1: regs= stack= before 20: (7b) *(u64 *)(r11 -16) = r1")
876e277efbSYonghong Song __msg("mark_precise: frame1: regs=r1 stack= before 19: (7b) *(u64 *)(r11 -8) = r2")
886e277efbSYonghong Song __msg("mark_precise: frame1: regs=r1 stack= before 18: (07) r2 += -8")
896e277efbSYonghong Song __msg("mark_precise: frame1: regs=r1 stack= before 17: (bf) r2 = r10")
906e277efbSYonghong Song __msg("mark_precise: frame1: regs=r1 stack= before 16: (7b) *(u64 *)(r10 -8) = r2")
916e277efbSYonghong Song __msg("mark_precise: frame1: regs=r1 stack= before 14: (18) r2 = 0x807060504030201")
926e277efbSYonghong Song __msg("mark_precise: frame1: regs=r1 stack= before 13: (79) r1 = *(u64 *)(r11 +8)")
936e277efbSYonghong Song __msg("mark_precise: frame1: parent state regs= stack=:  frame1: R10=fp0")
946e277efbSYonghong Song __msg("mark_precise: frame0: parent state regs= stack=:  R10=fp0")
956e277efbSYonghong Song __msg("mark_precise: frame1: last_idx 11 first_idx 11 subseq_idx 13 ")
966e277efbSYonghong Song __msg("mark_precise: frame1: regs= stack= before 11: (85) call pc+1")
976e277efbSYonghong Song __msg("mark_precise: frame0: parent state regs= stack=:  R1=1 R2=2 R3=3 R4=4 R5=5 R10=fp0")
986e277efbSYonghong Song __msg("mark_precise: frame0: last_idx 10 first_idx 10 subseq_idx 11 ")
996e277efbSYonghong Song __msg("mark_precise: frame0: regs= stack= before 10: (7a) *(u64 *)(r11 -8) = 6")
1006e277efbSYonghong Song __naked void stack_arg_precision_bpf2bpf(void)
1016e277efbSYonghong Song {
1026e277efbSYonghong Song 	asm volatile (
1036e277efbSYonghong Song 		"call %[bpf_get_prandom_u32];"
1046e277efbSYonghong Song 		"r6 = r0;"
1056e277efbSYonghong Song 		"r1 = 1;"
1066e277efbSYonghong Song 		"r2 = 2;"
1076e277efbSYonghong Song 		"r3 = 3;"
1086e277efbSYonghong Song 		"r4 = 4;"
1096e277efbSYonghong Song 		"r5 = 5;"
1106e277efbSYonghong Song 		"if r6 < 2 goto l0_%=;"
1116e277efbSYonghong Song 		"*(u64 *)(r11 - 8) = 4;"
1126e277efbSYonghong Song 		"goto l1_%=;"
1136e277efbSYonghong Song 	"l0_%=:"
1146e277efbSYonghong Song 		"*(u64 *)(r11 - 8) = 6;"
1156e277efbSYonghong Song 	"l1_%=:"
1166e277efbSYonghong Song 		"call subprog_call_mem_kfunc;"
1176e277efbSYonghong Song 		"exit;"
1186e277efbSYonghong Song 		:: __imm(bpf_get_prandom_u32)
1196e277efbSYonghong Song 		: __clobber_all
1206e277efbSYonghong Song 	);
1216e277efbSYonghong Song }
1226e277efbSYonghong Song 
1236e277efbSYonghong Song #else
1246e277efbSYonghong Song 
1256e277efbSYonghong Song SEC("socket")
1266e277efbSYonghong Song __description("stack_arg_precision: not supported, dummy test")
1276e277efbSYonghong Song __success
1286e277efbSYonghong Song int dummy_test(void)
1296e277efbSYonghong Song {
1306e277efbSYonghong Song 	return 0;
1316e277efbSYonghong Song }
1326e277efbSYonghong Song 
1336e277efbSYonghong Song #endif
1346e277efbSYonghong Song 
1356e277efbSYonghong Song char _license[] SEC("license") = "GPL";
136