Currently, functions with 'union' arguments cannot be traced with fentry/fexit: bpftrace -e 'fentry:release_pages { exit(); }' -v AST node count: 6 Attaching 1 probe... ERROR: Error loading BPF program for fentry_vmlinux_release_pages_1. Kernel error log: The function release_pages arg0 type UNION is unsupported. processed 0 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0 ERROR: Loading BPF object(s) failed. The type of the 'release_pages' argument is defined as: typedef union { struct page **pages; struct folio **folios; struct encoded_page **encoded_pages; } release_pages_arg __attribute__ ((__transparent_union__)); This patch relaxes the restriction by allowing function arguments of type 'union' to be traced. Signed-off-by: Leon Hwang --- kernel/bpf/btf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 64739308902f7..86883b3c97d20 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -6762,7 +6762,7 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type, /* skip modifiers */ while (btf_type_is_modifier(t)) t = btf_type_by_id(btf, t->type); - if (btf_type_is_small_int(t) || btf_is_any_enum(t) || __btf_type_is_struct(t)) + if (btf_type_is_small_int(t) || btf_is_any_enum(t) || btf_type_is_struct(t)) /* accessing a scalar */ return true; if (!btf_type_is_ptr(t)) { @@ -7334,7 +7334,7 @@ static int __get_type_size(struct btf *btf, u32 btf_id, if (btf_type_is_ptr(t)) /* kernel size of pointer. Not BPF's size of pointer*/ return sizeof(void *); - if (btf_type_is_int(t) || btf_is_any_enum(t) || __btf_type_is_struct(t)) + if (btf_type_is_int(t) || btf_is_any_enum(t) || btf_type_is_struct(t)) return t->size; return -EINVAL; } -- 2.50.1 Adding verifier test for accessing union argument in tracing programs. The test program loads 1st argument of bpf_fentry_test11 function which is union and checks that verifier allows that. cd tools/testing/selftests/bpf ./test_progs -t verifier_btf_ctx 501/7 verifier_btf_ctx_access/btf_ctx_access union arg accept:OK 501 verifier_btf_ctx_access:OK Summary: 1/7 PASSED, 0 SKIPPED, 0 FAILED Signed-off-by: Leon Hwang --- net/bpf/test_run.c | 14 +++++++++++++- .../selftests/bpf/progs/verifier_btf_ctx_access.c | 12 ++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c index 4a862d6053861..c65d468fd6012 100644 --- a/net/bpf/test_run.c +++ b/net/bpf/test_run.c @@ -574,6 +574,16 @@ noinline int bpf_fentry_test10(const void *a) return (long)a; } +typedef union { + void *arg0; + int *arg1; +} union_test_t; + +noinline int bpf_fentry_test11(union_test_t t) +{ + return (int)(long)t.arg0; +} + noinline void bpf_fentry_test_sinfo(struct skb_shared_info *sinfo) { } @@ -688,6 +698,7 @@ int bpf_prog_test_run_tracing(struct bpf_prog *prog, struct bpf_fentry_test_t arg = {}; u16 side_effect = 0, ret = 0; int b = 2, err = -EFAULT; + union_test_t utt = {}; u32 retval = 0; if (kattr->test.flags || kattr->test.cpu || kattr->test.batch_size) @@ -705,7 +716,8 @@ int bpf_prog_test_run_tracing(struct bpf_prog *prog, bpf_fentry_test7((struct bpf_fentry_test_t *)0) != 0 || bpf_fentry_test8(&arg) != 0 || bpf_fentry_test9(&retval) != 0 || - bpf_fentry_test10((void *)0) != 0) + bpf_fentry_test10((void *)0) != 0 || + bpf_fentry_test11(utt) != 0) goto out; break; case BPF_MODIFY_RETURN: diff --git a/tools/testing/selftests/bpf/progs/verifier_btf_ctx_access.c b/tools/testing/selftests/bpf/progs/verifier_btf_ctx_access.c index 03942cec07e56..ff379836b5f00 100644 --- a/tools/testing/selftests/bpf/progs/verifier_btf_ctx_access.c +++ b/tools/testing/selftests/bpf/progs/verifier_btf_ctx_access.c @@ -77,4 +77,16 @@ __naked void ctx_access_const_void_pointer_accept(void) " ::: __clobber_all); } +SEC("fentry/bpf_fentry_test11") +__description("btf_ctx_access union arg accept") +__success __retval(0) +__naked void ctx_access_union_arg_accept(void) +{ + asm volatile (" \ + r2 = *(u64 *)(r1 + 0); /* load 1st argument value (union) */\ + r0 = 0; \ + exit; \ +" ::: __clobber_all); +} + char _license[] SEC("license") = "GPL"; -- 2.50.1