Add two new subtests to kprobe_multi_test to validate the kprobe.session exact function name optimization:
test_session_syms: Attaches a kprobe.session program to an exact function name (bpf_fentry_test1) to verify the fast syms[] path works correctly. Validates that both entry and return probes fire. test_session_errors: Verifies error code consistency between the wildcard pattern path (slow, parses kallsyms) and the exact function name path (fast, uses syms[] array). Both paths must return -ENOENT for non-existent functions, protecting against future changes that could break API consistency. Signed-off-by: Andrey Grodzovsky <[email protected]> --- .../bpf/prog_tests/kprobe_multi_test.c | 76 +++++++++++++++++++ .../bpf/progs/kprobe_multi_session_errors.c | 27 +++++++ .../bpf/progs/kprobe_multi_session_syms.c | 45 +++++++++++ 3 files changed, 148 insertions(+) create mode 100644 tools/testing/selftests/bpf/progs/kprobe_multi_session_errors.c create mode 100644 tools/testing/selftests/bpf/progs/kprobe_multi_session_syms.c diff --git a/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c b/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c index 9caef222e528..62f7959858a9 100644 --- a/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c +++ b/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c @@ -8,6 +8,8 @@ #include "kprobe_multi_override.skel.h" #include "kprobe_multi_session.skel.h" #include "kprobe_multi_session_cookie.skel.h" +#include "kprobe_multi_session_syms.skel.h" +#include "kprobe_multi_session_errors.skel.h" #include "kprobe_multi_verifier.skel.h" #include "kprobe_write_ctx.skel.h" #include "bpf/libbpf_internal.h" @@ -400,6 +402,76 @@ static void test_session_cookie_skel_api(void) kprobe_multi_session_cookie__destroy(skel); } +static void test_session_syms_skel_api(void) +{ + struct kprobe_multi_session_syms *skel = NULL; + + LIBBPF_OPTS(bpf_test_run_opts, topts); + int err, prog_fd; + + skel = kprobe_multi_session_syms__open_and_load(); + if (!ASSERT_OK_PTR(skel, "kprobe_multi_session_syms__open_and_load")) + return; + + skel->bss->pid = getpid(); + + err = kprobe_multi_session_syms__attach(skel); + if (!ASSERT_OK(err, "kprobe_multi_session_syms__attach")) + goto cleanup; + + prog_fd = bpf_program__fd(skel->progs.trigger); + err = bpf_prog_test_run_opts(prog_fd, &topts); + ASSERT_OK(err, "test_run"); + ASSERT_EQ(topts.retval, 0, "test_run"); + + /* Test 1: Both entry and return should fire */ + ASSERT_EQ(skel->bss->test1_count, 2, "test1_count"); + ASSERT_TRUE(skel->bss->test1_return, "test1_return"); + +cleanup: + kprobe_multi_session_syms__destroy(skel); +} + +static void test_session_errors(void) +{ + struct kprobe_multi_session_errors *skel = NULL; + struct bpf_link *link_wildcard = NULL; + struct bpf_link *link_exact = NULL; + int err_wildcard, err_exact; + + skel = kprobe_multi_session_errors__open_and_load(); + if (!ASSERT_OK_PTR(skel, "kprobe_multi_session_errors__open_and_load")) + return; + + /* + * Test error code consistency: both wildcard (slow path) and exact name + * (fast path) should return the same error code (ENOENT) for non-existent + * functions. This protects against future kernel changes that might alter + * error return values. + */ + + /* Try to attach with non-existent wildcard pattern (slow path) */ + link_wildcard = bpf_program__attach(skel->progs.test_nonexistent_wildcard); + err_wildcard = -errno; + ASSERT_ERR_PTR(link_wildcard, "attach_nonexistent_wildcard"); + ASSERT_EQ(err_wildcard, -ENOENT, "wildcard_error_enoent"); + + /* Try to attach with non-existent exact name (fast path) */ + link_exact = bpf_program__attach(skel->progs.test_nonexistent_exact); + err_exact = -errno; + ASSERT_ERR_PTR(link_exact, "attach_nonexistent_exact"); + ASSERT_EQ(err_exact, -ENOENT, "exact_error_enoent"); + + /* + * Verify both paths return identical error codes - this is critical for + * API consistency and prevents user code from breaking when switching + * between wildcard patterns and exact function names. + */ + ASSERT_EQ(err_wildcard, err_exact, "error_consistency"); + + kprobe_multi_session_errors__destroy(skel); +} + static void test_unique_match(void) { LIBBPF_OPTS(bpf_kprobe_multi_opts, opts); @@ -645,6 +717,10 @@ void test_kprobe_multi_test(void) test_session_skel_api(); if (test__start_subtest("session_cookie")) test_session_cookie_skel_api(); + if (test__start_subtest("session_syms")) + test_session_syms_skel_api(); + if (test__start_subtest("session_errors")) + test_session_errors(); if (test__start_subtest("unique_match")) test_unique_match(); if (test__start_subtest("attach_write_ctx")) diff --git a/tools/testing/selftests/bpf/progs/kprobe_multi_session_errors.c b/tools/testing/selftests/bpf/progs/kprobe_multi_session_errors.c new file mode 100644 index 000000000000..749d43b35bc2 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/kprobe_multi_session_errors.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Test error code consistency between fast and slow paths for non-existent functions */ +#include <linux/bpf.h> +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_tracing.h> + +char _license[] SEC("license") = "GPL"; + +/* + * Test 1: Non-existent wildcard pattern (slow path) + * This uses pattern matching with kallsyms parsing and should fail with ENOENT + */ +SEC("kprobe.session/__impossible_test_func_xyz_wildcard_*") +int test_nonexistent_wildcard(struct pt_regs *ctx) +{ + return 0; +} + +/* + * Test 2: Non-existent exact function name (fast path) + * This uses syms[] array and should fail with ENOENT (normalized from ESRCH) + */ +SEC("kprobe.session/__impossible_test_func_xyz_exact_123") +int test_nonexistent_exact(struct pt_regs *ctx) +{ + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/kprobe_multi_session_syms.c b/tools/testing/selftests/bpf/progs/kprobe_multi_session_syms.c new file mode 100644 index 000000000000..6a4bd57af1fc --- /dev/null +++ b/tools/testing/selftests/bpf/progs/kprobe_multi_session_syms.c @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Test kprobe.session with exact function names to verify syms[] optimization */ +#include <vmlinux.h> +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_tracing.h> +#include <stdbool.h> + +char _license[] SEC("license") = "GPL"; + +int pid = 0; + +/* Results for each function: incremented on entry and return */ +__u64 test1_count = 0; + +/* Track entry vs return */ +bool test1_return = false; + +/* + * No tests in here, just to trigger 'bpf_fentry_test*' + * through tracing test_run + */ +SEC("fentry/bpf_modify_return_test") +int BPF_PROG(trigger) +{ + return 0; +} + +/* + * Test 1: Exact function name (no wildcards) - uses fast syms[] path + * This should attach via opts.syms array, bypassing kallsyms parsing + */ +SEC("kprobe.session/bpf_fentry_test1") +int test_kprobe_syms_1(struct pt_regs *ctx) +{ + if (bpf_get_current_pid_tgid() >> 32 != pid) + return 0; + + test1_count++; + + /* Check if this is return probe */ + if (bpf_session_is_return(ctx)) + test1_return = true; + + return 0; /* Always execute return probe */ +} -- 2.34.1
