]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
selftests/bpf: Refactor bpf_get_ksyms() trace helper
authorIhor Solodrai <ihor.solodrai@linux.dev>
Mon, 23 Feb 2026 19:07:25 +0000 (11:07 -0800)
committerAlexei Starovoitov <ast@kernel.org>
Tue, 24 Feb 2026 16:19:49 +0000 (08:19 -0800)
ASAN reported a memory leak in bpf_get_ksyms(): it allocates a struct
ksyms internally and never frees it.

Move struct ksyms to trace_helpers.h and return it from the
bpf_get_ksyms(), giving ownership to the caller. Add filtered_syms and
filtered_cnt fields to the ksyms to hold the filtered array of
symbols, previously returned by bpf_get_ksyms().

Fixup the call sites: kprobe_multi_test and bench_trigger.

Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20260223190736.649171-10-ihor.solodrai@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
tools/testing/selftests/bpf/benchs/bench_trigger.c
tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c
tools/testing/selftests/bpf/trace_helpers.c
tools/testing/selftests/bpf/trace_helpers.h

index aeec9edd3851dbf9ea8a87215df8558871904786..f74b313d6ae46e70ee25be2ac57e0cb706470d88 100644 (file)
@@ -230,8 +230,8 @@ static void trigger_fentry_setup(void)
 static void attach_ksyms_all(struct bpf_program *empty, bool kretprobe)
 {
        LIBBPF_OPTS(bpf_kprobe_multi_opts, opts);
-       char **syms = NULL;
-       size_t cnt = 0;
+       struct bpf_link *link = NULL;
+       struct ksyms *ksyms = NULL;
 
        /* Some recursive functions will be skipped in
         * bpf_get_ksyms -> skip_entry, as they can introduce sufficient
@@ -241,16 +241,18 @@ static void attach_ksyms_all(struct bpf_program *empty, bool kretprobe)
         * So, don't run the kprobe-multi-all and kretprobe-multi-all on
         * a debug kernel.
         */
-       if (bpf_get_ksyms(&syms, &cnt, true)) {
+       if (bpf_get_ksyms(&ksyms, true)) {
                fprintf(stderr, "failed to get ksyms\n");
                exit(1);
        }
 
-       opts.syms = (const char **) syms;
-       opts.cnt = cnt;
+       opts.syms = (const char **)ksyms->filtered_syms;
+       opts.cnt = ksyms->filtered_cnt;
        opts.retprobe = kretprobe;
        /* attach empty to all the kernel functions except bpf_get_numa_node_id. */
-       if (!bpf_program__attach_kprobe_multi_opts(empty, NULL, &opts)) {
+       link = bpf_program__attach_kprobe_multi_opts(empty, NULL, &opts);
+       free_kallsyms_local(ksyms);
+       if (!link) {
                fprintf(stderr, "failed to attach bpf_program__attach_kprobe_multi_opts to all\n");
                exit(1);
        }
index 9caef222e52885baf319ec033676bd07fb266896..f81dcd609ee928fbe3dd29e9dc3846ee96651af8 100644 (file)
@@ -456,25 +456,23 @@ static void test_kprobe_multi_bench_attach(bool kernel)
 {
        LIBBPF_OPTS(bpf_kprobe_multi_opts, opts);
        struct kprobe_multi_empty *skel = NULL;
-       char **syms = NULL;
-       size_t cnt = 0;
+       struct ksyms *ksyms = NULL;
 
-       if (!ASSERT_OK(bpf_get_ksyms(&syms, &cnt, kernel), "bpf_get_ksyms"))
+       if (!ASSERT_OK(bpf_get_ksyms(&ksyms, kernel), "bpf_get_ksyms"))
                return;
 
        skel = kprobe_multi_empty__open_and_load();
        if (!ASSERT_OK_PTR(skel, "kprobe_multi_empty__open_and_load"))
                goto cleanup;
 
-       opts.syms = (const char **) syms;
-       opts.cnt = cnt;
+       opts.syms = (const char **)ksyms->filtered_syms;
+       opts.cnt = ksyms->filtered_cnt;
 
        do_bench_test(skel, &opts);
 
 cleanup:
        kprobe_multi_empty__destroy(skel);
-       if (syms)
-               free(syms);
+       free_kallsyms_local(ksyms);
 }
 
 static void test_kprobe_multi_bench_attach_addr(bool kernel)
index eeaab7013ca2fe5de12210e435dd48aa5d826ddc..0e63daf83ed52bc599ec685985b5bd7b023e1693 100644 (file)
 #define TRACEFS_PIPE   "/sys/kernel/tracing/trace_pipe"
 #define DEBUGFS_PIPE   "/sys/kernel/debug/tracing/trace_pipe"
 
-struct ksyms {
-       struct ksym *syms;
-       size_t sym_cap;
-       size_t sym_cnt;
-};
-
 static struct ksyms *ksyms;
 static pthread_mutex_t ksyms_mutex = PTHREAD_MUTEX_INITIALIZER;
 
@@ -54,6 +48,8 @@ void free_kallsyms_local(struct ksyms *ksyms)
        if (!ksyms)
                return;
 
+       free(ksyms->filtered_syms);
+
        if (!ksyms->syms) {
                free(ksyms);
                return;
@@ -610,7 +606,7 @@ static int search_kallsyms_compare(const void *p1, const struct ksym *p2)
        return compare_name(p1, p2->name);
 }
 
-int bpf_get_ksyms(char ***symsp, size_t *cntp, bool kernel)
+int bpf_get_ksyms(struct ksyms **ksymsp, bool kernel)
 {
        size_t cap = 0, cnt = 0;
        char *name = NULL, *ksym_name, **syms = NULL;
@@ -637,8 +633,10 @@ int bpf_get_ksyms(char ***symsp, size_t *cntp, bool kernel)
        else
                f = fopen("/sys/kernel/debug/tracing/available_filter_functions", "r");
 
-       if (!f)
+       if (!f) {
+               free_kallsyms_local(ksyms);
                return -EINVAL;
+       }
 
        map = hashmap__new(symbol_hash, symbol_equal, NULL);
        if (IS_ERR(map)) {
@@ -679,15 +677,18 @@ int bpf_get_ksyms(char ***symsp, size_t *cntp, bool kernel)
                syms[cnt++] = ksym_name;
        }
 
-       *symsp = syms;
-       *cntp = cnt;
+       ksyms->filtered_syms = syms;
+       ksyms->filtered_cnt = cnt;
+       *ksymsp = ksyms;
 
 error:
        free(name);
        fclose(f);
        hashmap__free(map);
-       if (err)
+       if (err) {
                free(syms);
+               free_kallsyms_local(ksyms);
+       }
        return err;
 }
 
index a5576b2dfc267ebcb0eeafad0235875d9c65c9b7..d5bf1433675d66f4ee8994bdf60b8a0c17133fb6 100644 (file)
@@ -23,7 +23,14 @@ struct ksym {
        long addr;
        char *name;
 };
-struct ksyms;
+
+struct ksyms {
+       struct ksym *syms;
+       size_t sym_cap;
+       size_t sym_cnt;
+       char **filtered_syms;
+       size_t filtered_cnt;
+};
 
 typedef int (*ksym_cmp_t)(const void *p1, const void *p2);
 typedef int (*ksym_search_cmp_t)(const void *p1, const struct ksym *p2);
@@ -53,7 +60,7 @@ ssize_t get_rel_offset(uintptr_t addr);
 
 int read_build_id(const char *path, char *build_id, size_t size);
 
-int bpf_get_ksyms(char ***symsp, size_t *cntp, bool kernel);
+int bpf_get_ksyms(struct ksyms **ksymsp, bool kernel);
 int bpf_get_addrs(unsigned long **addrsp, size_t *cntp, bool kernel);
 
 #endif