Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: Add union argument tests using fexit programs

Add test coverage for union argument support using fexit programs:

* 8B union argument - verify that the verifier accepts it and that fexit
programs can trace such functions.
* 16B union argument - verify that the verifier accepts it and that
fexit programs can access the argument, which is passed using two
registers.

Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
Link: https://lore.kernel.org/r/20250919044110.23729-3-leon.hwang@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Leon Hwang and committed by
Alexei Starovoitov
1c6686bf ccb4f5d9

+93
+29
tools/testing/selftests/bpf/prog_tests/tracing_struct.c
··· 112 112 tracing_struct_many_args__destroy(skel); 113 113 } 114 114 115 + static void test_union_args(void) 116 + { 117 + struct tracing_struct *skel; 118 + int err; 119 + 120 + skel = tracing_struct__open_and_load(); 121 + if (!ASSERT_OK_PTR(skel, "tracing_struct__open_and_load")) 122 + return; 123 + 124 + err = tracing_struct__attach(skel); 125 + if (!ASSERT_OK(err, "tracing_struct__attach")) 126 + goto out; 127 + 128 + ASSERT_OK(trigger_module_test_read(256), "trigger_read"); 129 + 130 + ASSERT_EQ(skel->bss->ut1_a_a, 1, "ut1:a.arg.a"); 131 + ASSERT_EQ(skel->bss->ut1_b, 4, "ut1:b"); 132 + ASSERT_EQ(skel->bss->ut1_c, 5, "ut1:c"); 133 + 134 + ASSERT_EQ(skel->bss->ut2_a, 6, "ut2:a"); 135 + ASSERT_EQ(skel->bss->ut2_b_a, 2, "ut2:b.arg.a"); 136 + ASSERT_EQ(skel->bss->ut2_b_b, 3, "ut2:b.arg.b"); 137 + 138 + out: 139 + tracing_struct__destroy(skel); 140 + } 141 + 115 142 void test_tracing_struct(void) 116 143 { 117 144 if (test__start_subtest("struct_args")) 118 145 test_struct_args(); 119 146 if (test__start_subtest("struct_many_args")) 120 147 test_struct_many_args(); 148 + if (test__start_subtest("union_args")) 149 + test_union_args(); 121 150 }
+33
tools/testing/selftests/bpf/progs/tracing_struct.c
··· 18 18 int b[]; 19 19 }; 20 20 21 + union bpf_testmod_union_arg_1 { 22 + char a; 23 + short b; 24 + struct bpf_testmod_struct_arg_1 arg; 25 + }; 26 + 27 + union bpf_testmod_union_arg_2 { 28 + int a; 29 + long b; 30 + struct bpf_testmod_struct_arg_2 arg; 31 + }; 32 + 21 33 long t1_a_a, t1_a_b, t1_b, t1_c, t1_ret, t1_nregs; 22 34 __u64 t1_reg0, t1_reg1, t1_reg2, t1_reg3; 23 35 long t2_a, t2_b_a, t2_b_b, t2_c, t2_ret; ··· 37 25 long t4_a_a, t4_b, t4_c, t4_d, t4_e_a, t4_e_b, t4_ret; 38 26 long t5_ret; 39 27 int t6; 28 + 29 + long ut1_a_a, ut1_b, ut1_c; 30 + long ut2_a, ut2_b_a, ut2_b_b; 40 31 41 32 SEC("fentry/bpf_testmod_test_struct_arg_1") 42 33 int BPF_PROG2(test_struct_arg_1, struct bpf_testmod_struct_arg_2, a, int, b, int, c) ··· 142 127 int BPF_PROG2(test_struct_arg_11, struct bpf_testmod_struct_arg_3 *, a) 143 128 { 144 129 t6 = a->b[0]; 130 + return 0; 131 + } 132 + 133 + SEC("fexit/bpf_testmod_test_union_arg_1") 134 + int BPF_PROG2(test_union_arg_1, union bpf_testmod_union_arg_1, a, int, b, int, c) 135 + { 136 + ut1_a_a = a.arg.a; 137 + ut1_b = b; 138 + ut1_c = c; 139 + return 0; 140 + } 141 + 142 + SEC("fexit/bpf_testmod_test_union_arg_2") 143 + int BPF_PROG2(test_union_arg_2, int, a, union bpf_testmod_union_arg_2, b) 144 + { 145 + ut2_a = a; 146 + ut2_b_a = b.arg.a; 147 + ut2_b_b = b.arg.b; 145 148 return 0; 146 149 } 147 150
+31
tools/testing/selftests/bpf/test_kmods/bpf_testmod.c
··· 62 62 long d; 63 63 }; 64 64 65 + union bpf_testmod_union_arg_1 { 66 + char a; 67 + short b; 68 + struct bpf_testmod_struct_arg_1 arg; 69 + }; 70 + 71 + union bpf_testmod_union_arg_2 { 72 + int a; 73 + long b; 74 + struct bpf_testmod_struct_arg_2 arg; 75 + }; 76 + 65 77 __bpf_hook_start(); 66 78 67 79 noinline int ··· 137 125 { 138 126 bpf_testmod_test_struct_arg_result = a + (long)b + c + d + (long)e + 139 127 f + g + h.a + h.b + h.c + h.d + i; 128 + return bpf_testmod_test_struct_arg_result; 129 + } 130 + 131 + noinline int 132 + bpf_testmod_test_union_arg_1(union bpf_testmod_union_arg_1 a, int b, int c) 133 + { 134 + bpf_testmod_test_struct_arg_result = a.arg.a + b + c; 135 + return bpf_testmod_test_struct_arg_result; 136 + } 137 + 138 + noinline int 139 + bpf_testmod_test_union_arg_2(int a, union bpf_testmod_union_arg_2 b) 140 + { 141 + bpf_testmod_test_struct_arg_result = a + b.arg.a + b.arg.b; 140 142 return bpf_testmod_test_struct_arg_result; 141 143 } 142 144 ··· 434 408 struct bpf_testmod_struct_arg_3 *struct_arg3; 435 409 struct bpf_testmod_struct_arg_4 struct_arg4 = {21, 22}; 436 410 struct bpf_testmod_struct_arg_5 struct_arg5 = {23, 24, 25, 26}; 411 + union bpf_testmod_union_arg_1 union_arg1 = { .arg = {1} }; 412 + union bpf_testmod_union_arg_2 union_arg2 = { .arg = {2, 3} }; 437 413 int i = 1; 438 414 439 415 while (bpf_testmod_return_ptr(i)) ··· 452 424 (void *)20, struct_arg4, 23); 453 425 (void)bpf_testmod_test_struct_arg_9(16, (void *)17, 18, 19, (void *)20, 454 426 21, 22, struct_arg5, 27); 427 + 428 + (void)bpf_testmod_test_union_arg_1(union_arg1, 4, 5); 429 + (void)bpf_testmod_test_union_arg_2(6, union_arg2); 455 430 456 431 (void)bpf_testmod_test_arg_ptr_to_struct(&struct_arg1_2); 457 432