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