Commit a1a771bd authored by Ihor Solodrai's avatar Ihor Solodrai Committed by Alexei Starovoitov
Browse files

selftests/bpf: Refactor bpf_get_ksyms() trace helper



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: default avatarIhor Solodrai <ihor.solodrai@linux.dev>
Acked-by: default avatarEduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20260223190736.649171-10-ihor.solodrai@linux.dev


Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 45897ced
Loading
Loading
Loading
Loading
+8 −6
Original line number Diff line number Diff line
@@ -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);
	}
+5 −7
Original line number Diff line number Diff line
@@ -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)
+12 −11
Original line number Diff line number Diff line
@@ -24,12 +24,6 @@
#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;
}

+9 −2
Original line number Diff line number Diff line
@@ -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