From a5a6b29a700fda1dd766cc42dde2cbba9b19f470 Mon Sep 17 00:00:00 2001 From: KaFai Wan Date: Thu, 24 Jul 2025 23:14:51 +0800 Subject: [PATCH 1/4] bpf: Show precise rejected function when attaching fexit/fmod_ret to __noreturn functions With this change, we know the precise rejected function name when attaching fexit/fmod_ret to __noreturn functions from log. $ ./fexit libbpf: prog 'fexit': BPF program load failed: -EINVAL libbpf: prog 'fexit': -- BEGIN PROG LOAD LOG -- Attaching fexit/fmod_ret to __noreturn function 'do_exit' is rejected. Suggested-by: Leon Hwang Signed-off-by: KaFai Wan Acked-by: Yafang Shao Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20250724151454.499040-2-kafai.wan@linux.dev Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 3 ++- tools/testing/selftests/bpf/progs/fexit_noreturns.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index e50d3d43be67..4bf7392fd2c3 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -23985,7 +23985,8 @@ static int check_attach_btf_id(struct bpf_verifier_env *env) } else if ((prog->expected_attach_type == BPF_TRACE_FEXIT || prog->expected_attach_type == BPF_MODIFY_RETURN) && btf_id_set_contains(&noreturn_deny, btf_id)) { - verbose(env, "Attaching fexit/fmod_ret to __noreturn functions is rejected.\n"); + verbose(env, "Attaching fexit/fmod_ret to __noreturn function '%s' is rejected.\n", + tgt_info.tgt_name); return -EINVAL; } diff --git a/tools/testing/selftests/bpf/progs/fexit_noreturns.c b/tools/testing/selftests/bpf/progs/fexit_noreturns.c index 54654539f550..b1c33d958ae2 100644 --- a/tools/testing/selftests/bpf/progs/fexit_noreturns.c +++ b/tools/testing/selftests/bpf/progs/fexit_noreturns.c @@ -8,7 +8,7 @@ char _license[] SEC("license") = "GPL"; SEC("fexit/do_exit") -__failure __msg("Attaching fexit/fmod_ret to __noreturn functions is rejected.") +__failure __msg("Attaching fexit/fmod_ret to __noreturn function 'do_exit' is rejected.") int BPF_PROG(noreturns) { return 0; From 863aab3d4dcdfffa5cf0e0795c526dadca65be7a Mon Sep 17 00:00:00 2001 From: KaFai Wan Date: Thu, 24 Jul 2025 23:14:52 +0800 Subject: [PATCH 2/4] bpf: Add log for attaching tracing programs to functions in deny list Show the rejected function name when attaching tracing programs to functions in deny list. With this change, we know why tracing programs can't attach to functions like __rcu_read_lock() from log. $ ./fentry libbpf: prog '__rcu_read_lock': BPF program load failed: -EINVAL libbpf: prog '__rcu_read_lock': -- BEGIN PROG LOAD LOG -- Attaching tracing programs to function '__rcu_read_lock' is rejected. Suggested-by: Leon Hwang Signed-off-by: KaFai Wan Acked-by: Yafang Shao Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20250724151454.499040-3-kafai.wan@linux.dev Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 4bf7392fd2c3..399f03e62508 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -23981,6 +23981,8 @@ static int check_attach_btf_id(struct bpf_verifier_env *env) return ret; } else if (prog->type == BPF_PROG_TYPE_TRACING && btf_id_set_contains(&btf_id_deny, btf_id)) { + verbose(env, "Attaching tracing programs to function '%s' is rejected.\n", + tgt_info.tgt_name); return -EINVAL; } else if ((prog->expected_attach_type == BPF_TRACE_FEXIT || prog->expected_attach_type == BPF_MODIFY_RETURN) && From a32f6f17a74d0e897b48bd4c697cc9782a38bf4f Mon Sep 17 00:00:00 2001 From: KaFai Wan Date: Thu, 24 Jul 2025 23:14:53 +0800 Subject: [PATCH 3/4] selftests/bpf: Add selftest for attaching tracing programs to functions in deny list The result: $ tools/testing/selftests/bpf/test_progs -t tracing_failure/tracing_deny #468/3 tracing_failure/tracing_deny:OK #468 tracing_failure:OK Summary: 1/1 PASSED, 0 SKIPPED, 0 FAILED Signed-off-by: KaFai Wan Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20250724151454.499040-4-kafai.wan@linux.dev Signed-off-by: Alexei Starovoitov --- .../bpf/prog_tests/tracing_failure.c | 33 +++++++++++++++++++ .../selftests/bpf/progs/tracing_failure.c | 6 ++++ 2 files changed, 39 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/tracing_failure.c b/tools/testing/selftests/bpf/prog_tests/tracing_failure.c index a222df765bc3..39b59276884a 100644 --- a/tools/testing/selftests/bpf/prog_tests/tracing_failure.c +++ b/tools/testing/selftests/bpf/prog_tests/tracing_failure.c @@ -28,10 +28,43 @@ static void test_bpf_spin_lock(bool is_spin_lock) tracing_failure__destroy(skel); } +static void test_tracing_deny(void) +{ + struct tracing_failure *skel; + char log_buf[256]; + int btf_id, err; + + /* __rcu_read_lock depends on CONFIG_PREEMPT_RCU */ + btf_id = libbpf_find_vmlinux_btf_id("__rcu_read_lock", BPF_TRACE_FENTRY); + if (btf_id <= 0) { + test__skip(); + return; + } + + skel = tracing_failure__open(); + if (!ASSERT_OK_PTR(skel, "tracing_failure__open")) + return; + + bpf_program__set_autoload(skel->progs.tracing_deny, true); + bpf_program__set_log_buf(skel->progs.tracing_deny, log_buf, sizeof(log_buf)); + + err = tracing_failure__load(skel); + if (!ASSERT_ERR(err, "tracing_failure__load")) + goto out; + + ASSERT_HAS_SUBSTR(log_buf, + "Attaching tracing programs to function '__rcu_read_lock' is rejected.", + "log_buf"); +out: + tracing_failure__destroy(skel); +} + void test_tracing_failure(void) { if (test__start_subtest("bpf_spin_lock")) test_bpf_spin_lock(true); if (test__start_subtest("bpf_spin_unlock")) test_bpf_spin_lock(false); + if (test__start_subtest("tracing_deny")) + test_tracing_deny(); } diff --git a/tools/testing/selftests/bpf/progs/tracing_failure.c b/tools/testing/selftests/bpf/progs/tracing_failure.c index d41665d2ec8c..58d2777014e1 100644 --- a/tools/testing/selftests/bpf/progs/tracing_failure.c +++ b/tools/testing/selftests/bpf/progs/tracing_failure.c @@ -18,3 +18,9 @@ int BPF_PROG(test_spin_unlock, struct bpf_spin_lock *lock) { return 0; } + +SEC("?fentry/__rcu_read_lock") +int BPF_PROG(tracing_deny) +{ + return 0; +} From 51d3750aba798335568970f3157629c6ca5dc91a Mon Sep 17 00:00:00 2001 From: KaFai Wan Date: Thu, 24 Jul 2025 23:14:54 +0800 Subject: [PATCH 4/4] selftests/bpf: Migrate fexit_noreturns case into tracing_failure test suite Delete fexit_noreturns.c files and migrate the cases into tracing_failure.c files. The result: $ tools/testing/selftests/bpf/test_progs -t tracing_failure/fexit_noreturns #467/4 tracing_failure/fexit_noreturns:OK #467 tracing_failure:OK Summary: 1/1 PASSED, 0 SKIPPED, 0 FAILED Signed-off-by: KaFai Wan Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20250724151454.499040-5-kafai.wan@linux.dev Signed-off-by: Alexei Starovoitov --- .../bpf/prog_tests/fexit_noreturns.c | 9 ---- .../bpf/prog_tests/tracing_failure.c | 53 +++++++++++++------ .../selftests/bpf/progs/fexit_noreturns.c | 15 ------ .../selftests/bpf/progs/tracing_failure.c | 6 +++ 4 files changed, 42 insertions(+), 41 deletions(-) delete mode 100644 tools/testing/selftests/bpf/prog_tests/fexit_noreturns.c delete mode 100644 tools/testing/selftests/bpf/progs/fexit_noreturns.c diff --git a/tools/testing/selftests/bpf/prog_tests/fexit_noreturns.c b/tools/testing/selftests/bpf/prog_tests/fexit_noreturns.c deleted file mode 100644 index 568d3aa48a78..000000000000 --- a/tools/testing/selftests/bpf/prog_tests/fexit_noreturns.c +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#include -#include "fexit_noreturns.skel.h" - -void test_fexit_noreturns(void) -{ - RUN_TESTS(fexit_noreturns); -} diff --git a/tools/testing/selftests/bpf/prog_tests/tracing_failure.c b/tools/testing/selftests/bpf/prog_tests/tracing_failure.c index 39b59276884a..10e231965589 100644 --- a/tools/testing/selftests/bpf/prog_tests/tracing_failure.c +++ b/tools/testing/selftests/bpf/prog_tests/tracing_failure.c @@ -28,11 +28,36 @@ static void test_bpf_spin_lock(bool is_spin_lock) tracing_failure__destroy(skel); } -static void test_tracing_deny(void) +static void test_tracing_fail_prog(const char *prog_name, const char *exp_msg) { struct tracing_failure *skel; + struct bpf_program *prog; char log_buf[256]; - int btf_id, err; + int err; + + skel = tracing_failure__open(); + if (!ASSERT_OK_PTR(skel, "tracing_failure__open")) + return; + + prog = bpf_object__find_program_by_name(skel->obj, prog_name); + if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name")) + goto out; + + bpf_program__set_autoload(prog, true); + bpf_program__set_log_buf(prog, log_buf, sizeof(log_buf)); + + err = tracing_failure__load(skel); + if (!ASSERT_ERR(err, "tracing_failure__load")) + goto out; + + ASSERT_HAS_SUBSTR(log_buf, exp_msg, "log_buf"); +out: + tracing_failure__destroy(skel); +} + +static void test_tracing_deny(void) +{ + int btf_id; /* __rcu_read_lock depends on CONFIG_PREEMPT_RCU */ btf_id = libbpf_find_vmlinux_btf_id("__rcu_read_lock", BPF_TRACE_FENTRY); @@ -41,22 +66,14 @@ static void test_tracing_deny(void) return; } - skel = tracing_failure__open(); - if (!ASSERT_OK_PTR(skel, "tracing_failure__open")) - return; + test_tracing_fail_prog("tracing_deny", + "Attaching tracing programs to function '__rcu_read_lock' is rejected."); +} - bpf_program__set_autoload(skel->progs.tracing_deny, true); - bpf_program__set_log_buf(skel->progs.tracing_deny, log_buf, sizeof(log_buf)); - - err = tracing_failure__load(skel); - if (!ASSERT_ERR(err, "tracing_failure__load")) - goto out; - - ASSERT_HAS_SUBSTR(log_buf, - "Attaching tracing programs to function '__rcu_read_lock' is rejected.", - "log_buf"); -out: - tracing_failure__destroy(skel); +static void test_fexit_noreturns(void) +{ + test_tracing_fail_prog("fexit_noreturns", + "Attaching fexit/fmod_ret to __noreturn function 'do_exit' is rejected."); } void test_tracing_failure(void) @@ -67,4 +84,6 @@ void test_tracing_failure(void) test_bpf_spin_lock(false); if (test__start_subtest("tracing_deny")) test_tracing_deny(); + if (test__start_subtest("fexit_noreturns")) + test_fexit_noreturns(); } diff --git a/tools/testing/selftests/bpf/progs/fexit_noreturns.c b/tools/testing/selftests/bpf/progs/fexit_noreturns.c deleted file mode 100644 index b1c33d958ae2..000000000000 --- a/tools/testing/selftests/bpf/progs/fexit_noreturns.c +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#include -#include -#include -#include "bpf_misc.h" - -char _license[] SEC("license") = "GPL"; - -SEC("fexit/do_exit") -__failure __msg("Attaching fexit/fmod_ret to __noreturn function 'do_exit' is rejected.") -int BPF_PROG(noreturns) -{ - return 0; -} diff --git a/tools/testing/selftests/bpf/progs/tracing_failure.c b/tools/testing/selftests/bpf/progs/tracing_failure.c index 58d2777014e1..65e485c4468c 100644 --- a/tools/testing/selftests/bpf/progs/tracing_failure.c +++ b/tools/testing/selftests/bpf/progs/tracing_failure.c @@ -24,3 +24,9 @@ int BPF_PROG(tracing_deny) { return 0; } + +SEC("?fexit/do_exit") +int BPF_PROG(fexit_noreturns) +{ + return 0; +}