selftests/bpf: Check the member named for an unsupported kfunc return type

Add tests to cover cases where a kfunc return type is rejected with
proper messages including member names and array types.

Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
Link: https://lore.kernel.org/r/20260829061600.1697800-1-yonghong.song@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Yonghong Song 2026-08-28 23:16:00 -07:00 committed by Alexei Starovoitov
parent 9046109974
commit cc03706d92
3 changed files with 164 additions and 0 deletions

View File

@ -19,6 +19,11 @@ void __kfunc_btf_root(void)
"r"(&bpf_kfunc_call_test_ret_fastcall),
"r"(&bpf_kfunc_call_test_ret_ptr),
"r"(&bpf_kfunc_call_test_ret_ii),
"r"(&bpf_kfunc_call_test_ret_nested),
"r"(&bpf_kfunc_call_test_ret_ptr_arr),
"r"(&bpf_kfunc_call_test_ret_deep),
"r"(&bpf_kfunc_call_test_ret_arr_struct),
"r"(&bpf_kfunc_call_test_ret_arr2d),
"r"(&bpf_kfunc_call_test_ret_big));
}
@ -72,6 +77,7 @@ __naked int aggregate_ret_kfunc_fastcall_fail(void)
SEC("tc")
__arch_x86_64 __arch_arm64
__failure __msg("is not composed of scalars or arena pointers")
__msg("member 'p' has type PTR")
__naked int aggregate_ret_kfunc_ptr_fail(void)
{
asm volatile (
@ -84,6 +90,82 @@ __naked int aggregate_ret_kfunc_ptr_fail(void)
: __clobber_all);
}
SEC("tc")
__arch_x86_64 __arch_arm64
__failure __msg("is not composed of scalars or arena pointers")
__msg("member 'in.p' has type PTR")
__naked int aggregate_ret_kfunc_nested_ptr_fail(void)
{
asm volatile (
"r1 = 0;"
"call %[bpf_kfunc_call_test_ret_nested];"
"r0 = 0;"
"exit;"
:
: __imm(bpf_kfunc_call_test_ret_nested)
: __clobber_all);
}
SEC("tc")
__arch_x86_64 __arch_arm64
__failure __msg("is not composed of scalars or arena pointers")
__msg("member 'p[]' has type PTR")
__naked int aggregate_ret_kfunc_ptr_arr_fail(void)
{
asm volatile (
"call %[bpf_kfunc_call_test_ret_ptr_arr];"
"r0 = 0;"
"exit;"
:
: __imm(bpf_kfunc_call_test_ret_ptr_arr)
: __clobber_all);
}
SEC("tc")
__arch_x86_64 __arch_arm64
__failure __msg("is not composed of scalars or arena pointers")
__msg("member 'in1[].in2.p' has type PTR")
__naked int aggregate_ret_kfunc_arr_struct_fail(void)
{
asm volatile (
"call %[bpf_kfunc_call_test_ret_arr_struct];"
"r0 = 0;"
"exit;"
:
: __imm(bpf_kfunc_call_test_ret_arr_struct)
: __clobber_all);
}
SEC("tc")
__arch_x86_64 __arch_arm64
__failure __msg("is not composed of scalars or arena pointers")
__msg("member 'a[].p' has type PTR")
__naked int aggregate_ret_kfunc_arr2d_fail(void)
{
asm volatile (
"call %[bpf_kfunc_call_test_ret_arr2d];"
"r0 = 0;"
"exit;"
:
: __imm(bpf_kfunc_call_test_ret_arr2d)
: __clobber_all);
}
SEC("tc")
__arch_x86_64 __arch_arm64
__failure __msg("max struct nesting depth exceeded")
__naked int aggregate_ret_kfunc_too_deep_fail(void)
{
asm volatile (
"r1 = 0;"
"call %[bpf_kfunc_call_test_ret_deep];"
"r0 = 0;"
"exit;"
:
: __imm(bpf_kfunc_call_test_ret_deep)
: __clobber_all);
}
SEC("tc")
__arch_x86_64 __arch_arm64
__failure __msg("R2 !read_ok")

View File

@ -981,6 +981,41 @@ __bpf_kfunc struct prog_test_ret_ptr bpf_kfunc_call_test_ret_ptr(u64 tag)
return r;
}
__bpf_kfunc struct prog_test_ret_nested bpf_kfunc_call_test_ret_nested(u64 tag)
{
struct prog_test_ret_nested r = { .in = { .p = NULL }, .tag = tag };
return r;
}
__bpf_kfunc struct prog_test_ret_ptr_arr bpf_kfunc_call_test_ret_ptr_arr(void)
{
struct prog_test_ret_ptr_arr r = { .p = { NULL, NULL } };
return r;
}
__bpf_kfunc struct prog_test_ret_arr_struct bpf_kfunc_call_test_ret_arr_struct(void)
{
struct prog_test_ret_arr_struct r = {};
return r;
}
__bpf_kfunc struct prog_test_ret_arr2d bpf_kfunc_call_test_ret_arr2d(void)
{
struct prog_test_ret_arr2d r = {};
return r;
}
__bpf_kfunc struct prog_test_ret_deep bpf_kfunc_call_test_ret_deep(u64 v)
{
struct prog_test_ret_deep r = { .l1 = { .l2 = { .l3 = { .l4 = { .v = v } } } } };
return r;
}
__bpf_kfunc struct prog_test_ret_ii bpf_kfunc_call_test_ret_ii(int a, int b)
{
struct prog_test_ret_ii r = { .a = a, .b = b };
@ -1539,6 +1574,11 @@ BTF_ID_FLAGS(func, bpf_kfunc_call_test_i128)
BTF_ID_FLAGS(func, bpf_kfunc_call_test_ret_pair)
BTF_ID_FLAGS(func, bpf_kfunc_call_test_ret_fastcall, KF_FASTCALL)
BTF_ID_FLAGS(func, bpf_kfunc_call_test_ret_ptr)
BTF_ID_FLAGS(func, bpf_kfunc_call_test_ret_nested)
BTF_ID_FLAGS(func, bpf_kfunc_call_test_ret_ptr_arr)
BTF_ID_FLAGS(func, bpf_kfunc_call_test_ret_arr_struct)
BTF_ID_FLAGS(func, bpf_kfunc_call_test_ret_arr2d)
BTF_ID_FLAGS(func, bpf_kfunc_call_test_ret_deep)
BTF_ID_FLAGS(func, bpf_kfunc_call_test_ret_ii)
#endif
BTF_ID_FLAGS(func, bpf_kfunc_call_test_ret_big)

View File

@ -70,6 +70,43 @@ struct prog_test_ret_ptr { /* 16 bytes: contains a pointer */
__u64 tag;
};
struct prog_test_ret_nested { /* 16 bytes: the pointer hides one level down */
struct {
void *p;
} in;
__u64 tag;
};
struct prog_test_ret_ptr_arr { /* 16 bytes: an array of pointers */
void *p[2];
};
struct prog_test_ret_arr_struct { /* 16 bytes: the pointer is under an array of structs */
struct {
struct {
void *p;
} in2;
} in1[2];
};
struct prog_test_ret_arr2d { /* 16 bytes: a two dimensional array of structs */
struct {
void *p;
} a[1][2];
};
struct prog_test_ret_deep { /* 8 bytes, but nested past the 4-level walk limit */
struct {
struct {
struct {
struct {
__u64 v;
} l4;
} l3;
} l2;
} l1;
};
struct prog_test_ret_big { /* 24 bytes: too large for R0:R2 */
__u64 a;
__u64 b;
@ -159,6 +196,11 @@ struct prog_test_ret_pair bpf_kfunc_call_test_ret_pair(__u64 a, __u64 b) __ksym;
struct prog_test_ret_pair bpf_kfunc_call_test_ret_fastcall(__u64 a, __u64 b) __ksym;
struct prog_test_ret_ii bpf_kfunc_call_test_ret_ii(int a, int b) __ksym;
struct prog_test_ret_ptr bpf_kfunc_call_test_ret_ptr(__u64 tag) __ksym;
struct prog_test_ret_nested bpf_kfunc_call_test_ret_nested(__u64 tag) __ksym;
struct prog_test_ret_ptr_arr bpf_kfunc_call_test_ret_ptr_arr(void) __ksym;
struct prog_test_ret_arr_struct bpf_kfunc_call_test_ret_arr_struct(void) __ksym;
struct prog_test_ret_arr2d bpf_kfunc_call_test_ret_arr2d(void) __ksym;
struct prog_test_ret_deep bpf_kfunc_call_test_ret_deep(__u64 v) __ksym;
struct prog_test_ret_big bpf_kfunc_call_test_ret_big(void) __ksym;
__u64 bpf_kfunc_call_stack_arg(__u64 a, __u64 b, __u64 c, __u64 d,
__u64 e, __u64 f, __u64 g, __u64 h,