* [PATCH bpf-next v1 01/14] selftests/bpf: Pass through build flags to bpftool and resolve_btfids
2026-02-12 1:13 [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN Ihor Solodrai
@ 2026-02-12 1:13 ` Ihor Solodrai
2026-02-12 2:39 ` Alexei Starovoitov
2026-02-12 1:13 ` [PATCH bpf-next v1 02/14] resolve_btfids: Fix memory leaks reported by ASAN Ihor Solodrai
` (14 subsequent siblings)
15 siblings, 1 reply; 47+ messages in thread
From: Ihor Solodrai @ 2026-02-12 1:13 UTC (permalink / raw)
To: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
EXTRA_* and SAN_* build flags were not correctly propagated to bpftool
and resolve_btids when building selftests/bpf. This led to various
build errors on attempt to build with SAN_CFLAGS="-fsanitize=address",
for example.
Fix the makefiles to address this:
- Pass SAN_CFLAGS/SAN_LDFLAGS to bpftool and resolve_btfids build
- Propagate EXTRA_LDFLAGS to resolve_btfids link command
- Use pkg-config to detect zlib and zstd for resolve_btfids, similar
libelf handling
Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
---
tools/bpf/resolve_btfids/Makefile | 7 +++++--
tools/testing/selftests/bpf/Makefile | 9 +++++----
2 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/tools/bpf/resolve_btfids/Makefile b/tools/bpf/resolve_btfids/Makefile
index 1733a6e93a07..ef083602b73a 100644
--- a/tools/bpf/resolve_btfids/Makefile
+++ b/tools/bpf/resolve_btfids/Makefile
@@ -65,6 +65,9 @@ $(BPFOBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(LIBBPF_OU
LIBELF_FLAGS := $(shell $(HOSTPKG_CONFIG) libelf --cflags 2>/dev/null)
LIBELF_LIBS := $(shell $(HOSTPKG_CONFIG) libelf --libs 2>/dev/null || echo -lelf)
+ZLIB_LIBS := $(shell $(HOSTPKG_CONFIG) zlib --libs 2>/dev/null || echo -lz)
+ZSTD_LIBS := $(shell $(HOSTPKG_CONFIG) libzstd --libs 2>/dev/null || echo -lzstd)
+
HOSTCFLAGS_resolve_btfids += -g \
-I$(srctree)/tools/include \
-I$(srctree)/tools/include/uapi \
@@ -73,7 +76,7 @@ HOSTCFLAGS_resolve_btfids += -g \
$(LIBELF_FLAGS) \
-Wall -Werror
-LIBS = $(LIBELF_LIBS) -lz
+LIBS = $(LIBELF_LIBS) $(ZLIB_LIBS) $(ZSTD_LIBS)
export srctree OUTPUT HOSTCFLAGS_resolve_btfids Q HOSTCC HOSTLD HOSTAR
include $(srctree)/tools/build/Makefile.include
@@ -83,7 +86,7 @@ $(BINARY_IN): fixdep FORCE prepare | $(OUTPUT)
$(BINARY): $(BPFOBJ) $(SUBCMDOBJ) $(BINARY_IN)
$(call msg,LINK,$@)
- $(Q)$(HOSTCC) $(BINARY_IN) $(KBUILD_HOSTLDFLAGS) -o $@ $(BPFOBJ) $(SUBCMDOBJ) $(LIBS)
+ $(Q)$(HOSTCC) $(BINARY_IN) $(KBUILD_HOSTLDFLAGS) $(EXTRA_LDFLAGS) -o $@ $(BPFOBJ) $(SUBCMDOBJ) $(LIBS)
clean_objects := $(wildcard $(OUTPUT)/*.o \
$(OUTPUT)/.*.o.cmd \
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index c6bf4dfb1495..a0a594de9007 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -326,8 +326,8 @@ $(DEFAULT_BPFTOOL): $(wildcard $(BPFTOOLDIR)/*.[ch] $(BPFTOOLDIR)/Makefile) \
$(HOST_BPFOBJ) | $(HOST_BUILD_DIR)/bpftool
$(Q)$(MAKE) $(submake_extras) -C $(BPFTOOLDIR) \
ARCH= CROSS_COMPILE= CC="$(HOSTCC)" LD="$(HOSTLD)" \
- EXTRA_CFLAGS='-g $(OPT_FLAGS) $(EXTRA_CFLAGS)' \
- EXTRA_LDFLAGS='$(EXTRA_LDFLAGS)' \
+ EXTRA_CFLAGS='-g $(OPT_FLAGS) $(SAN_CFLAGS) $(EXTRA_CFLAGS)' \
+ EXTRA_LDFLAGS='$(SAN_LDFLAGS) $(EXTRA_LDFLAGS)' \
OUTPUT=$(HOST_BUILD_DIR)/bpftool/ \
LIBBPF_OUTPUT=$(HOST_BUILD_DIR)/libbpf/ \
LIBBPF_DESTDIR=$(HOST_SCRATCH_DIR)/ \
@@ -338,8 +338,8 @@ $(CROSS_BPFTOOL): $(wildcard $(BPFTOOLDIR)/*.[ch] $(BPFTOOLDIR)/Makefile) \
$(BPFOBJ) | $(BUILD_DIR)/bpftool
$(Q)$(MAKE) $(submake_extras) -C $(BPFTOOLDIR) \
ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) \
- EXTRA_CFLAGS='-g $(OPT_FLAGS) $(EXTRA_CFLAGS)' \
- EXTRA_LDFLAGS='$(EXTRA_LDFLAGS)' \
+ EXTRA_CFLAGS='-g $(OPT_FLAGS) $(SAN_CFLAGS) $(EXTRA_CFLAGS)' \
+ EXTRA_LDFLAGS='$(SAN_LDFLAGS) $(EXTRA_LDFLAGS)' \
OUTPUT=$(BUILD_DIR)/bpftool/ \
LIBBPF_OUTPUT=$(BUILD_DIR)/libbpf/ \
LIBBPF_DESTDIR=$(SCRATCH_DIR)/ \
@@ -404,6 +404,7 @@ $(RESOLVE_BTFIDS): $(HOST_BPFOBJ) | $(HOST_BUILD_DIR)/resolve_btfids \
$(Q)$(MAKE) $(submake_extras) -C $(TOOLSDIR)/bpf/resolve_btfids \
CC="$(HOSTCC)" LD="$(HOSTLD)" AR="$(HOSTAR)" \
LIBBPF_INCLUDE=$(HOST_INCLUDE_DIR) \
+ EXTRA_LDFLAGS='$(SAN_LDFLAGS) $(EXTRA_LDFLAGS)' \
OUTPUT=$(HOST_BUILD_DIR)/resolve_btfids/ BPFOBJ=$(HOST_BPFOBJ)
# Get Clang's default includes on this system, as opposed to those seen by
--
2.53.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* Re: [PATCH bpf-next v1 01/14] selftests/bpf: Pass through build flags to bpftool and resolve_btfids
2026-02-12 1:13 ` [PATCH bpf-next v1 01/14] selftests/bpf: Pass through build flags to bpftool and resolve_btfids Ihor Solodrai
@ 2026-02-12 2:39 ` Alexei Starovoitov
2026-02-12 3:08 ` Ihor Solodrai
0 siblings, 1 reply; 47+ messages in thread
From: Alexei Starovoitov @ 2026-02-12 2:39 UTC (permalink / raw)
To: Ihor Solodrai
Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman, Amery Hung, Mykyta Yatsenko,
Alexis Lothoré, bpf, LKML, Kernel Team
On Wed, Feb 11, 2026 at 5:14 PM Ihor Solodrai <ihor.solodrai@linux.dev> wrote:
>
> EXTRA_* and SAN_* build flags were not correctly propagated to bpftool
> and resolve_btids when building selftests/bpf. This led to various
> build errors on attempt to build with SAN_CFLAGS="-fsanitize=address",
> for example.
>
> Fix the makefiles to address this:
> - Pass SAN_CFLAGS/SAN_LDFLAGS to bpftool and resolve_btfids build
> - Propagate EXTRA_LDFLAGS to resolve_btfids link command
> - Use pkg-config to detect zlib and zstd for resolve_btfids, similar
> libelf handling
>
> Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
> ---
> tools/bpf/resolve_btfids/Makefile | 7 +++++--
> tools/testing/selftests/bpf/Makefile | 9 +++++----
> 2 files changed, 10 insertions(+), 6 deletions(-)
>
> diff --git a/tools/bpf/resolve_btfids/Makefile b/tools/bpf/resolve_btfids/Makefile
> index 1733a6e93a07..ef083602b73a 100644
> --- a/tools/bpf/resolve_btfids/Makefile
> +++ b/tools/bpf/resolve_btfids/Makefile
> @@ -65,6 +65,9 @@ $(BPFOBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(LIBBPF_OU
> LIBELF_FLAGS := $(shell $(HOSTPKG_CONFIG) libelf --cflags 2>/dev/null)
> LIBELF_LIBS := $(shell $(HOSTPKG_CONFIG) libelf --libs 2>/dev/null || echo -lelf)
>
> +ZLIB_LIBS := $(shell $(HOSTPKG_CONFIG) zlib --libs 2>/dev/null || echo -lz)
> +ZSTD_LIBS := $(shell $(HOSTPKG_CONFIG) libzstd --libs 2>/dev/null || echo -lzstd)
The first two patches look serious enough and justify going to bpf tree.
The rest can probably go via bpf as well, since we're early
in the merge window.
Would be great to have some Acks first though.
Why add zstd here? It's not used by resolve_btfid. Why add it?
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH bpf-next v1 01/14] selftests/bpf: Pass through build flags to bpftool and resolve_btfids
2026-02-12 2:39 ` Alexei Starovoitov
@ 2026-02-12 3:08 ` Ihor Solodrai
2026-02-13 0:08 ` Ihor Solodrai
0 siblings, 1 reply; 47+ messages in thread
From: Ihor Solodrai @ 2026-02-12 3:08 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman, Amery Hung, Mykyta Yatsenko,
Alexis Lothoré, bpf, LKML, Kernel Team
On 2/11/26 6:39 PM, Alexei Starovoitov wrote:
> On Wed, Feb 11, 2026 at 5:14 PM Ihor Solodrai <ihor.solodrai@linux.dev> wrote:
>>
>> EXTRA_* and SAN_* build flags were not correctly propagated to bpftool
>> and resolve_btids when building selftests/bpf. This led to various
>> build errors on attempt to build with SAN_CFLAGS="-fsanitize=address",
>> for example.
>>
>> Fix the makefiles to address this:
>> - Pass SAN_CFLAGS/SAN_LDFLAGS to bpftool and resolve_btfids build
>> - Propagate EXTRA_LDFLAGS to resolve_btfids link command
>> - Use pkg-config to detect zlib and zstd for resolve_btfids, similar
>> libelf handling
>>
>> Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
>> ---
>> tools/bpf/resolve_btfids/Makefile | 7 +++++--
>> tools/testing/selftests/bpf/Makefile | 9 +++++----
>> 2 files changed, 10 insertions(+), 6 deletions(-)
>>
>> diff --git a/tools/bpf/resolve_btfids/Makefile b/tools/bpf/resolve_btfids/Makefile
>> index 1733a6e93a07..ef083602b73a 100644
>> --- a/tools/bpf/resolve_btfids/Makefile
>> +++ b/tools/bpf/resolve_btfids/Makefile
>> @@ -65,6 +65,9 @@ $(BPFOBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(LIBBPF_OU
>> LIBELF_FLAGS := $(shell $(HOSTPKG_CONFIG) libelf --cflags 2>/dev/null)
>> LIBELF_LIBS := $(shell $(HOSTPKG_CONFIG) libelf --libs 2>/dev/null || echo -lelf)
>>
>> +ZLIB_LIBS := $(shell $(HOSTPKG_CONFIG) zlib --libs 2>/dev/null || echo -lz)
>> +ZSTD_LIBS := $(shell $(HOSTPKG_CONFIG) libzstd --libs 2>/dev/null || echo -lzstd)
>
> The first two patches look serious enough and justify going to bpf tree.
> The rest can probably go via bpf as well, since we're early
> in the merge window.
> Would be great to have some Acks first though.
>
> Why add zstd here? It's not used by resolve_btfid. Why add it?
IIRC zstd is a transitive dependency of libelf.
I stumbled on a combination of build flags that caused link errors
because of this missing. I can find or produce an example log later
if that'd be helpful.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH bpf-next v1 01/14] selftests/bpf: Pass through build flags to bpftool and resolve_btfids
2026-02-12 3:08 ` Ihor Solodrai
@ 2026-02-13 0:08 ` Ihor Solodrai
0 siblings, 0 replies; 47+ messages in thread
From: Ihor Solodrai @ 2026-02-13 0:08 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman, Amery Hung, Mykyta Yatsenko,
Alexis Lothoré, bpf, LKML, Kernel Team
On 2/11/26 7:08 PM, Ihor Solodrai wrote:
>
>
> On 2/11/26 6:39 PM, Alexei Starovoitov wrote:
>> On Wed, Feb 11, 2026 at 5:14 PM Ihor Solodrai <ihor.solodrai@linux.dev> wrote:
>>>
>>> EXTRA_* and SAN_* build flags were not correctly propagated to bpftool
>>> and resolve_btids when building selftests/bpf. This led to various
>>> build errors on attempt to build with SAN_CFLAGS="-fsanitize=address",
>>> for example.
>>>
>>> Fix the makefiles to address this:
>>> - Pass SAN_CFLAGS/SAN_LDFLAGS to bpftool and resolve_btfids build
>>> - Propagate EXTRA_LDFLAGS to resolve_btfids link command
>>> - Use pkg-config to detect zlib and zstd for resolve_btfids, similar
>>> libelf handling
>>>
>>> Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
>>> ---
>>> tools/bpf/resolve_btfids/Makefile | 7 +++++--
>>> tools/testing/selftests/bpf/Makefile | 9 +++++----
>>> 2 files changed, 10 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/tools/bpf/resolve_btfids/Makefile b/tools/bpf/resolve_btfids/Makefile
>>> index 1733a6e93a07..ef083602b73a 100644
>>> --- a/tools/bpf/resolve_btfids/Makefile
>>> +++ b/tools/bpf/resolve_btfids/Makefile
>>> @@ -65,6 +65,9 @@ $(BPFOBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(LIBBPF_OU
>>> LIBELF_FLAGS := $(shell $(HOSTPKG_CONFIG) libelf --cflags 2>/dev/null)
>>> LIBELF_LIBS := $(shell $(HOSTPKG_CONFIG) libelf --libs 2>/dev/null || echo -lelf)
>>>
>>> +ZLIB_LIBS := $(shell $(HOSTPKG_CONFIG) zlib --libs 2>/dev/null || echo -lz)
>>> +ZSTD_LIBS := $(shell $(HOSTPKG_CONFIG) libzstd --libs 2>/dev/null || echo -lzstd)
>>
>> The first two patches look serious enough and justify going to bpf tree.
>> The rest can probably go via bpf as well, since we're early
>> in the merge window.
>> Would be great to have some Acks first though.
>>
>> Why add zstd here? It's not used by resolve_btfid. Why add it?
>
> IIRC zstd is a transitive dependency of libelf.
>
> I stumbled on a combination of build flags that caused link errors
> because of this missing. I can find or produce an example log later
> if that'd be helpful.
Reproduced the splat. See below.
Basically, the bug here was that building selftests/bpf with
EXTRA_LDFLAGS="-static" didn't propagate -static to resolve_btfids so
zstd and co were actually linked dynamically.
After I fixed the propagation of EXTRA_LDFLAGS, the static build of
selftests would fail on linking of resolve_btfids, because of -zstd
missing:
LINK resolve_btfids
/usr/bin/x86_64-linux-gnu-ld.bfd: /lib/x86_64-linux-gnu/libelf.a(elf_compress.o): in function `__libelf_compress':
(.text+0xe4): undefined reference to `ZSTD_createCCtx'
/usr/bin/x86_64-linux-gnu-ld.bfd: (.text+0x243): undefined reference to `ZSTD_compressStream2'
/usr/bin/x86_64-linux-gnu-ld.bfd: (.text+0x24e): undefined reference to `ZSTD_isError'
/usr/bin/x86_64-linux-gnu-ld.bfd: (.text+0x272): undefined reference to `ZSTD_freeCCtx'
/usr/bin/x86_64-linux-gnu-ld.bfd: (.text+0x4ff): undefined reference to `ZSTD_compressStream2'
/usr/bin/x86_64-linux-gnu-ld.bfd: (.text+0x50a): undefined reference to `ZSTD_isError'
/usr/bin/x86_64-linux-gnu-ld.bfd: (.text+0x6e1): undefined reference to `ZSTD_freeCCtx'
/usr/bin/x86_64-linux-gnu-ld.bfd: (.text+0x708): undefined reference to `ZSTD_freeCCtx'
/usr/bin/x86_64-linux-gnu-ld.bfd: (.text+0x78e): undefined reference to `ZSTD_freeCCtx'
/usr/bin/x86_64-linux-gnu-ld.bfd: (.text+0x828): undefined reference to `ZSTD_freeCCtx'
/usr/bin/x86_64-linux-gnu-ld.bfd: (.text+0x8f7): undefined reference to `ZSTD_freeCCtx'
/usr/bin/x86_64-linux-gnu-ld.bfd: /lib/x86_64-linux-gnu/libelf.a(elf_compress.o): in function `__libelf_decompress':
(.text+0xaf7): undefined reference to `ZSTD_decompress'
/usr/bin/x86_64-linux-gnu-ld.bfd: (.text+0xb02): undefined reference to `ZSTD_isError'
/usr/bin/x86_64-linux-gnu-ld.bfd: /lib/x86_64-linux-gnu/libelf.a(elf_compress.o): in function `__libelf_decompress_elf':
(.text+0xc37): undefined reference to `ZSTD_decompress'
/usr/bin/x86_64-linux-gnu-ld.bfd: (.text+0xc42): undefined reference to `ZSTD_isError'
clang-21: error: linker command failed with exit code 1 (use -v to see invocation)
make[1]: *** [Makefile:89: /ws/linux/tools/testing/selftests/bpf/tools/build/resolve_btfids//resolve_btfids] Error 1
make: *** [Makefile:404: /ws/linux/tools/testing/selftests/bpf/tools/build/resolve_btfids/resolve_btfids] Error 2
make: *** Waiting for unfinished jobs....
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH bpf-next v1 02/14] resolve_btfids: Fix memory leaks reported by ASAN
2026-02-12 1:13 [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN Ihor Solodrai
2026-02-12 1:13 ` [PATCH bpf-next v1 01/14] selftests/bpf: Pass through build flags to bpftool and resolve_btfids Ihor Solodrai
@ 2026-02-12 1:13 ` Ihor Solodrai
2026-02-12 11:28 ` Jiri Olsa
2026-02-12 1:13 ` [PATCH bpf-next v1 03/14] selftests/bpf: Add DENYLIST.asan Ihor Solodrai
` (13 subsequent siblings)
15 siblings, 1 reply; 47+ messages in thread
From: Ihor Solodrai @ 2026-02-12 1:13 UTC (permalink / raw)
To: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
Running resolve_btfids with ASAN reveals memory leaks in btf_id
handling.
- Change get_id() to use a local buffer
- Make btf_id__add() strdup the name internally
- Add btf_id__free_all() that frees all nodese of a tree
- Call the cleanup function on exit for every tree
Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
---
tools/bpf/resolve_btfids/main.c | 78 +++++++++++++++++++++------------
1 file changed, 51 insertions(+), 27 deletions(-)
diff --git a/tools/bpf/resolve_btfids/main.c b/tools/bpf/resolve_btfids/main.c
index ca7fcd03efb6..863fa0faaa31 100644
--- a/tools/bpf/resolve_btfids/main.c
+++ b/tools/bpf/resolve_btfids/main.c
@@ -226,7 +226,7 @@ static struct btf_id *btf_id__find(struct rb_root *root, const char *name)
}
static struct btf_id *__btf_id__add(struct rb_root *root,
- char *name,
+ const char *name,
enum btf_id_kind kind,
bool unique)
{
@@ -250,7 +250,11 @@ static struct btf_id *__btf_id__add(struct rb_root *root,
id = zalloc(sizeof(*id));
if (id) {
pr_debug("adding symbol %s\n", name);
- id->name = name;
+ id->name = strdup(name);
+ if (!id->name) {
+ free(id);
+ return NULL;
+ }
id->kind = kind;
rb_link_node(&id->rb_node, parent, p);
rb_insert_color(&id->rb_node, root);
@@ -258,17 +262,17 @@ static struct btf_id *__btf_id__add(struct rb_root *root,
return id;
}
-static inline struct btf_id *btf_id__add(struct rb_root *root, char *name, enum btf_id_kind kind)
+static inline struct btf_id *btf_id__add(struct rb_root *root, const char *name, enum btf_id_kind kind)
{
return __btf_id__add(root, name, kind, false);
}
-static inline struct btf_id *btf_id__add_unique(struct rb_root *root, char *name, enum btf_id_kind kind)
+static inline struct btf_id *btf_id__add_unique(struct rb_root *root, const char *name, enum btf_id_kind kind)
{
return __btf_id__add(root, name, kind, true);
}
-static char *get_id(const char *prefix_end)
+static int get_id(const char *prefix_end, char *buf, size_t buf_sz)
{
/*
* __BTF_ID__func__vfs_truncate__0
@@ -277,28 +281,28 @@ static char *get_id(const char *prefix_end)
*/
int len = strlen(prefix_end);
int pos = sizeof("__") - 1;
- char *p, *id;
+ char *p;
if (pos >= len)
- return NULL;
+ return -1;
- id = strdup(prefix_end + pos);
- if (id) {
- /*
- * __BTF_ID__func__vfs_truncate__0
- * id = ^
- *
- * cut the unique id part
- */
- p = strrchr(id, '_');
- p--;
- if (*p != '_') {
- free(id);
- return NULL;
- }
- *p = '\0';
- }
- return id;
+ if (len - pos >= buf_sz)
+ return -1;
+
+ strcpy(buf, prefix_end + pos);
+ /*
+ * __BTF_ID__func__vfs_truncate__0
+ * buf = ^
+ *
+ * cut the unique id part
+ */
+ p = strrchr(buf, '_');
+ p--;
+ if (*p != '_')
+ return -1;
+ *p = '\0';
+
+ return 0;
}
static struct btf_id *add_set(struct object *obj, char *name, enum btf_id_kind kind)
@@ -335,10 +339,9 @@ static struct btf_id *add_set(struct object *obj, char *name, enum btf_id_kind k
static struct btf_id *add_symbol(struct rb_root *root, char *name, size_t size)
{
- char *id;
+ char id[KSYM_NAME_LEN];
- id = get_id(name + size);
- if (!id) {
+ if (get_id(name + size, id, sizeof(id))) {
pr_err("FAILED to parse symbol name: %s\n", name);
return NULL;
}
@@ -346,6 +349,22 @@ static struct btf_id *add_symbol(struct rb_root *root, char *name, size_t size)
return btf_id__add(root, id, BTF_ID_KIND_SYM);
}
+static void btf_id__free_all(struct rb_root *root)
+{
+ struct rb_node *node, *next;
+ struct btf_id *id;
+
+ node = rb_first(root);
+ while (node) {
+ next = rb_next(node);
+ id = rb_entry(node, struct btf_id, rb_node);
+ rb_erase(node, root);
+ free(id->name);
+ free(id);
+ node = next;
+ }
+}
+
static void bswap_32_data(void *data, u32 nr_bytes)
{
u32 cnt, i;
@@ -1547,6 +1566,11 @@ int main(int argc, const char **argv)
out:
btf__free(obj.base_btf);
btf__free(obj.btf);
+ btf_id__free_all(&obj.structs);
+ btf_id__free_all(&obj.unions);
+ btf_id__free_all(&obj.typedefs);
+ btf_id__free_all(&obj.funcs);
+ btf_id__free_all(&obj.sets);
if (obj.efile.elf) {
elf_end(obj.efile.elf);
close(obj.efile.fd);
--
2.53.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* Re: [PATCH bpf-next v1 02/14] resolve_btfids: Fix memory leaks reported by ASAN
2026-02-12 1:13 ` [PATCH bpf-next v1 02/14] resolve_btfids: Fix memory leaks reported by ASAN Ihor Solodrai
@ 2026-02-12 11:28 ` Jiri Olsa
0 siblings, 0 replies; 47+ messages in thread
From: Jiri Olsa @ 2026-02-12 11:28 UTC (permalink / raw)
To: Ihor Solodrai
Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman, Amery Hung, Mykyta Yatsenko,
Alexis Lothoré, bpf, linux-kernel, kernel-team
On Wed, Feb 11, 2026 at 05:13:44PM -0800, Ihor Solodrai wrote:
> Running resolve_btfids with ASAN reveals memory leaks in btf_id
> handling.
>
> - Change get_id() to use a local buffer
> - Make btf_id__add() strdup the name internally
> - Add btf_id__free_all() that frees all nodese of a tree
> - Call the cleanup function on exit for every tree
>
> Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
Acked-by: Jiri Olsa <jolsa@kernel.org>
one nit below
thanks,
jirka
> ---
> tools/bpf/resolve_btfids/main.c | 78 +++++++++++++++++++++------------
> 1 file changed, 51 insertions(+), 27 deletions(-)
>
> diff --git a/tools/bpf/resolve_btfids/main.c b/tools/bpf/resolve_btfids/main.c
> index ca7fcd03efb6..863fa0faaa31 100644
> --- a/tools/bpf/resolve_btfids/main.c
> +++ b/tools/bpf/resolve_btfids/main.c
> @@ -226,7 +226,7 @@ static struct btf_id *btf_id__find(struct rb_root *root, const char *name)
> }
>
> static struct btf_id *__btf_id__add(struct rb_root *root,
> - char *name,
> + const char *name,
> enum btf_id_kind kind,
> bool unique)
> {
> @@ -250,7 +250,11 @@ static struct btf_id *__btf_id__add(struct rb_root *root,
> id = zalloc(sizeof(*id));
> if (id) {
> pr_debug("adding symbol %s\n", name);
> - id->name = name;
> + id->name = strdup(name);
> + if (!id->name) {
> + free(id);
> + return NULL;
> + }
> id->kind = kind;
> rb_link_node(&id->rb_node, parent, p);
> rb_insert_color(&id->rb_node, root);
> @@ -258,17 +262,17 @@ static struct btf_id *__btf_id__add(struct rb_root *root,
> return id;
> }
>
> -static inline struct btf_id *btf_id__add(struct rb_root *root, char *name, enum btf_id_kind kind)
> +static inline struct btf_id *btf_id__add(struct rb_root *root, const char *name, enum btf_id_kind kind)
> {
> return __btf_id__add(root, name, kind, false);
> }
>
> -static inline struct btf_id *btf_id__add_unique(struct rb_root *root, char *name, enum btf_id_kind kind)
> +static inline struct btf_id *btf_id__add_unique(struct rb_root *root, const char *name, enum btf_id_kind kind)
> {
> return __btf_id__add(root, name, kind, true);
> }
>
> -static char *get_id(const char *prefix_end)
> +static int get_id(const char *prefix_end, char *buf, size_t buf_sz)
> {
> /*
> * __BTF_ID__func__vfs_truncate__0
> @@ -277,28 +281,28 @@ static char *get_id(const char *prefix_end)
> */
> int len = strlen(prefix_end);
> int pos = sizeof("__") - 1;
> - char *p, *id;
> + char *p;
>
> if (pos >= len)
> - return NULL;
> + return -1;
>
> - id = strdup(prefix_end + pos);
> - if (id) {
> - /*
> - * __BTF_ID__func__vfs_truncate__0
> - * id = ^
> - *
> - * cut the unique id part
> - */
> - p = strrchr(id, '_');
> - p--;
> - if (*p != '_') {
> - free(id);
> - return NULL;
> - }
> - *p = '\0';
> - }
> - return id;
> + if (len - pos >= buf_sz)
> + return -1;
> +
> + strcpy(buf, prefix_end + pos);
> + /*
> + * __BTF_ID__func__vfs_truncate__0
> + * buf = ^
> + *
> + * cut the unique id part
> + */
> + p = strrchr(buf, '_');
> + p--;
> + if (*p != '_')
> + return -1;
> + *p = '\0';
> +
> + return 0;
> }
>
> static struct btf_id *add_set(struct object *obj, char *name, enum btf_id_kind kind)
> @@ -335,10 +339,9 @@ static struct btf_id *add_set(struct object *obj, char *name, enum btf_id_kind k
>
> static struct btf_id *add_symbol(struct rb_root *root, char *name, size_t size)
> {
> - char *id;
> + char id[KSYM_NAME_LEN];
>
> - id = get_id(name + size);
> - if (!id) {
> + if (get_id(name + size, id, sizeof(id))) {
> pr_err("FAILED to parse symbol name: %s\n", name);
> return NULL;
> }
> @@ -346,6 +349,22 @@ static struct btf_id *add_symbol(struct rb_root *root, char *name, size_t size)
> return btf_id__add(root, id, BTF_ID_KIND_SYM);
> }
>
> +static void btf_id__free_all(struct rb_root *root)
> +{
> + struct rb_node *node, *next;
> + struct btf_id *id;
> +
> + node = rb_first(root);
> + while (node) {
> + next = rb_next(node);
> + id = rb_entry(node, struct btf_id, rb_node);
> + rb_erase(node, root);
> + free(id->name);
> + free(id);
> + node = next;
> + }
> +}
nit, I think we could do it with just single rb_node pointer, like:
next = rb_first(root);
while (next) {
id = rb_entry(next, struct btf_id, rb_node);
next = rb_next(&id->rb_node);
rb_erase(&id->rb_node, root);
free(id->name);
free(id);
}
jirka
> +
> static void bswap_32_data(void *data, u32 nr_bytes)
> {
> u32 cnt, i;
> @@ -1547,6 +1566,11 @@ int main(int argc, const char **argv)
> out:
> btf__free(obj.base_btf);
> btf__free(obj.btf);
> + btf_id__free_all(&obj.structs);
> + btf_id__free_all(&obj.unions);
> + btf_id__free_all(&obj.typedefs);
> + btf_id__free_all(&obj.funcs);
> + btf_id__free_all(&obj.sets);
> if (obj.efile.elf) {
> elf_end(obj.efile.elf);
> close(obj.efile.fd);
> --
> 2.53.0
>
>
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH bpf-next v1 03/14] selftests/bpf: Add DENYLIST.asan
2026-02-12 1:13 [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN Ihor Solodrai
2026-02-12 1:13 ` [PATCH bpf-next v1 01/14] selftests/bpf: Pass through build flags to bpftool and resolve_btfids Ihor Solodrai
2026-02-12 1:13 ` [PATCH bpf-next v1 02/14] resolve_btfids: Fix memory leaks reported by ASAN Ihor Solodrai
@ 2026-02-12 1:13 ` Ihor Solodrai
2026-02-12 1:13 ` [PATCH bpf-next v1 04/14] selftests/bpf: Refactor bpf_get_ksyms() trace helper Ihor Solodrai
` (12 subsequent siblings)
15 siblings, 0 replies; 47+ messages in thread
From: Ihor Solodrai @ 2026-02-12 1:13 UTC (permalink / raw)
To: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
Add a denylist file for tests that should be skipped when built with
userspace ASAN:
$ make ... SAN_CFLAGS="-fsanitize=address -fno-omit-frame-pointer"
Skip the following tests:
- *arena*: userspace ASAN does not understand BPF arena maps and gets
confused particularly when map_extra is non-zero
- non-zero map_extra leads to mmap with MAP_FIXED, and ASAN treats
this as an unknown memory region
- task_local_data: ASAN complains about "incorrect" aligned_alloc()
usage, but it's intentional in the test
- uprobe_multi_test: very slow with ASAN enabled
Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
---
tools/testing/selftests/bpf/DENYLIST.asan | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 tools/testing/selftests/bpf/DENYLIST.asan
diff --git a/tools/testing/selftests/bpf/DENYLIST.asan b/tools/testing/selftests/bpf/DENYLIST.asan
new file mode 100644
index 000000000000..d7fe372a2293
--- /dev/null
+++ b/tools/testing/selftests/bpf/DENYLIST.asan
@@ -0,0 +1,3 @@
+*arena*
+task_local_data
+uprobe_multi_test
--
2.53.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH bpf-next v1 04/14] selftests/bpf: Refactor bpf_get_ksyms() trace helper
2026-02-12 1:13 [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN Ihor Solodrai
` (2 preceding siblings ...)
2026-02-12 1:13 ` [PATCH bpf-next v1 03/14] selftests/bpf: Add DENYLIST.asan Ihor Solodrai
@ 2026-02-12 1:13 ` Ihor Solodrai
2026-02-12 11:29 ` Jiri Olsa
2026-02-13 9:56 ` Alexis Lothoré
2026-02-12 1:13 ` [PATCH bpf-next v1 05/14] selftests/bpf: Fix memory leaks in tests Ihor Solodrai
` (11 subsequent siblings)
15 siblings, 2 replies; 47+ messages in thread
From: Ihor Solodrai @ 2026-02-12 1:13 UTC (permalink / raw)
To: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
ASAN reported a memory leak in bpf_get_ksyms(): it allocates a struct
ksyms internally and never frees it.
Moe 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>
---
.../selftests/bpf/benchs/bench_trigger.c | 9 ++++----
.../bpf/prog_tests/kprobe_multi_test.c | 12 ++++------
tools/testing/selftests/bpf/trace_helpers.c | 23 ++++++++++---------
tools/testing/selftests/bpf/trace_helpers.h | 11 +++++++--
4 files changed, 30 insertions(+), 25 deletions(-)
diff --git a/tools/testing/selftests/bpf/benchs/bench_trigger.c b/tools/testing/selftests/bpf/benchs/bench_trigger.c
index aeec9edd3851..7231b88cf21a 100644
--- a/tools/testing/selftests/bpf/benchs/bench_trigger.c
+++ b/tools/testing/selftests/bpf/benchs/bench_trigger.c
@@ -230,8 +230,7 @@ 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 ksyms *ksyms = NULL;
/* Some recursive functions will be skipped in
* bpf_get_ksyms -> skip_entry, as they can introduce sufficient
@@ -241,13 +240,13 @@ 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)) {
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..f81dcd609ee9 100644
--- a/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c
+++ b/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c
@@ -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)
diff --git a/tools/testing/selftests/bpf/trace_helpers.c b/tools/testing/selftests/bpf/trace_helpers.c
index eeaab7013ca2..0e63daf83ed5 100644
--- a/tools/testing/selftests/bpf/trace_helpers.c
+++ b/tools/testing/selftests/bpf/trace_helpers.c
@@ -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;
}
diff --git a/tools/testing/selftests/bpf/trace_helpers.h b/tools/testing/selftests/bpf/trace_helpers.h
index a5576b2dfc26..d5bf1433675d 100644
--- a/tools/testing/selftests/bpf/trace_helpers.h
+++ b/tools/testing/selftests/bpf/trace_helpers.h
@@ -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
--
2.53.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* Re: [PATCH bpf-next v1 04/14] selftests/bpf: Refactor bpf_get_ksyms() trace helper
2026-02-12 1:13 ` [PATCH bpf-next v1 04/14] selftests/bpf: Refactor bpf_get_ksyms() trace helper Ihor Solodrai
@ 2026-02-12 11:29 ` Jiri Olsa
2026-02-17 20:42 ` Ihor Solodrai
2026-02-13 9:56 ` Alexis Lothoré
1 sibling, 1 reply; 47+ messages in thread
From: Jiri Olsa @ 2026-02-12 11:29 UTC (permalink / raw)
To: Ihor Solodrai
Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman, Amery Hung, Mykyta Yatsenko,
Alexis Lothoré, bpf, linux-kernel, kernel-team
On Wed, Feb 11, 2026 at 05:13:46PM -0800, Ihor Solodrai wrote:
> ASAN reported a memory leak in bpf_get_ksyms(): it allocates a struct
> ksyms internally and never frees it.
>
> Moe 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>
> ---
> .../selftests/bpf/benchs/bench_trigger.c | 9 ++++----
> .../bpf/prog_tests/kprobe_multi_test.c | 12 ++++------
> tools/testing/selftests/bpf/trace_helpers.c | 23 ++++++++++---------
> tools/testing/selftests/bpf/trace_helpers.h | 11 +++++++--
> 4 files changed, 30 insertions(+), 25 deletions(-)
>
> diff --git a/tools/testing/selftests/bpf/benchs/bench_trigger.c b/tools/testing/selftests/bpf/benchs/bench_trigger.c
> index aeec9edd3851..7231b88cf21a 100644
> --- a/tools/testing/selftests/bpf/benchs/bench_trigger.c
> +++ b/tools/testing/selftests/bpf/benchs/bench_trigger.c
> @@ -230,8 +230,7 @@ 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 ksyms *ksyms = NULL;
>
> /* Some recursive functions will be skipped in
> * bpf_get_ksyms -> skip_entry, as they can introduce sufficient
> @@ -241,13 +240,13 @@ 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)) {
hi,
missing free_kallsyms_local call in here ?
> 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..f81dcd609ee9 100644
> --- a/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c
> +++ b/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c
> @@ -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)
> diff --git a/tools/testing/selftests/bpf/trace_helpers.c b/tools/testing/selftests/bpf/trace_helpers.c
> index eeaab7013ca2..0e63daf83ed5 100644
> --- a/tools/testing/selftests/bpf/trace_helpers.c
> +++ b/tools/testing/selftests/bpf/trace_helpers.c
> @@ -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);
> + }
I think we could just call free_kallsyms_local unconditionally in here
and fix callers to free syms pointer? seems easier than adding filtered*
fields to ksyms
thanks,
jirak
> return err;
> }
>
> diff --git a/tools/testing/selftests/bpf/trace_helpers.h b/tools/testing/selftests/bpf/trace_helpers.h
> index a5576b2dfc26..d5bf1433675d 100644
> --- a/tools/testing/selftests/bpf/trace_helpers.h
> +++ b/tools/testing/selftests/bpf/trace_helpers.h
> @@ -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
> --
> 2.53.0
>
>
^ permalink raw reply [flat|nested] 47+ messages in thread* Re: [PATCH bpf-next v1 04/14] selftests/bpf: Refactor bpf_get_ksyms() trace helper
2026-02-12 11:29 ` Jiri Olsa
@ 2026-02-17 20:42 ` Ihor Solodrai
2026-02-18 13:14 ` Jiri Olsa
0 siblings, 1 reply; 47+ messages in thread
From: Ihor Solodrai @ 2026-02-17 20:42 UTC (permalink / raw)
To: Jiri Olsa
Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman, Amery Hung, Mykyta Yatsenko,
Alexis Lothoré, bpf, linux-kernel, kernel-team
On 2/12/26 3:29 AM, Jiri Olsa wrote:
> On Wed, Feb 11, 2026 at 05:13:46PM -0800, Ihor Solodrai wrote:
>> ASAN reported a memory leak in bpf_get_ksyms(): it allocates a struct
>> ksyms internally and never frees it.
>>
>> Moe 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>
>> ---
>> .../selftests/bpf/benchs/bench_trigger.c | 9 ++++----
>> .../bpf/prog_tests/kprobe_multi_test.c | 12 ++++------
>> tools/testing/selftests/bpf/trace_helpers.c | 23 ++++++++++---------
>> tools/testing/selftests/bpf/trace_helpers.h | 11 +++++++--
>> 4 files changed, 30 insertions(+), 25 deletions(-)
>>
>> diff --git a/tools/testing/selftests/bpf/benchs/bench_trigger.c b/tools/testing/selftests/bpf/benchs/bench_trigger.c
>> index aeec9edd3851..7231b88cf21a 100644
>> --- a/tools/testing/selftests/bpf/benchs/bench_trigger.c
>> +++ b/tools/testing/selftests/bpf/benchs/bench_trigger.c
>> @@ -230,8 +230,7 @@ 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 ksyms *ksyms = NULL;
>>
>> /* Some recursive functions will be skipped in
>> * bpf_get_ksyms -> skip_entry, as they can introduce sufficient
>> @@ -241,13 +240,13 @@ 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)) {
>
> hi,
>
> missing free_kallsyms_local call in here ?
Yeap, thanks.
>
>
>> 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..f81dcd609ee9 100644
>> --- a/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c
>> +++ b/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c
>> @@ -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)
>> diff --git a/tools/testing/selftests/bpf/trace_helpers.c b/tools/testing/selftests/bpf/trace_helpers.c
>> index eeaab7013ca2..0e63daf83ed5 100644
>> --- a/tools/testing/selftests/bpf/trace_helpers.c
>> +++ b/tools/testing/selftests/bpf/trace_helpers.c
>> @@ -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);
>> + }
>
> I think we could just call free_kallsyms_local unconditionally in here
> and fix callers to free syms pointer? seems easier than adding filtered*
> fields to ksyms
The strings in filtered_syms are ksyms->syms[i].name pointers (not
copied). I didn't want to do another strdup, and I also didn't like
passing three out parameters to bpf_get_ksyms().
So I decided to consolidate the data gathered by bpf_get_ksyms() in
struct ksyms. ksyms->filtered_syms essentially is a view into the
ksyms->syms, and it can be unused too.
Does this make sense?
>
> thanks,
> jirak
>
>
>> return err;
>> }
>>
>> diff --git a/tools/testing/selftests/bpf/trace_helpers.h b/tools/testing/selftests/bpf/trace_helpers.h
>> index a5576b2dfc26..d5bf1433675d 100644
>> --- a/tools/testing/selftests/bpf/trace_helpers.h
>> +++ b/tools/testing/selftests/bpf/trace_helpers.h
>> @@ -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
>> --
>> 2.53.0
>>
>>
^ permalink raw reply [flat|nested] 47+ messages in thread* Re: [PATCH bpf-next v1 04/14] selftests/bpf: Refactor bpf_get_ksyms() trace helper
2026-02-17 20:42 ` Ihor Solodrai
@ 2026-02-18 13:14 ` Jiri Olsa
0 siblings, 0 replies; 47+ messages in thread
From: Jiri Olsa @ 2026-02-18 13:14 UTC (permalink / raw)
To: Ihor Solodrai
Cc: Jiri Olsa, Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman, Amery Hung, Mykyta Yatsenko,
Alexis Lothoré, bpf, linux-kernel, kernel-team
On Tue, Feb 17, 2026 at 12:42:08PM -0800, Ihor Solodrai wrote:
> On 2/12/26 3:29 AM, Jiri Olsa wrote:
> > On Wed, Feb 11, 2026 at 05:13:46PM -0800, Ihor Solodrai wrote:
> >> ASAN reported a memory leak in bpf_get_ksyms(): it allocates a struct
> >> ksyms internally and never frees it.
> >>
> >> Moe 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>
> >> ---
> >> .../selftests/bpf/benchs/bench_trigger.c | 9 ++++----
> >> .../bpf/prog_tests/kprobe_multi_test.c | 12 ++++------
> >> tools/testing/selftests/bpf/trace_helpers.c | 23 ++++++++++---------
> >> tools/testing/selftests/bpf/trace_helpers.h | 11 +++++++--
> >> 4 files changed, 30 insertions(+), 25 deletions(-)
> >>
> >> diff --git a/tools/testing/selftests/bpf/benchs/bench_trigger.c b/tools/testing/selftests/bpf/benchs/bench_trigger.c
> >> index aeec9edd3851..7231b88cf21a 100644
> >> --- a/tools/testing/selftests/bpf/benchs/bench_trigger.c
> >> +++ b/tools/testing/selftests/bpf/benchs/bench_trigger.c
> >> @@ -230,8 +230,7 @@ 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 ksyms *ksyms = NULL;
> >>
> >> /* Some recursive functions will be skipped in
> >> * bpf_get_ksyms -> skip_entry, as they can introduce sufficient
> >> @@ -241,13 +240,13 @@ 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)) {
> >
> > hi,
> >
> > missing free_kallsyms_local call in here ?
>
> Yeap, thanks.
>
> >
> >
> >> 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..f81dcd609ee9 100644
> >> --- a/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c
> >> +++ b/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c
> >> @@ -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)
> >> diff --git a/tools/testing/selftests/bpf/trace_helpers.c b/tools/testing/selftests/bpf/trace_helpers.c
> >> index eeaab7013ca2..0e63daf83ed5 100644
> >> --- a/tools/testing/selftests/bpf/trace_helpers.c
> >> +++ b/tools/testing/selftests/bpf/trace_helpers.c
> >> @@ -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);
> >> + }
> >
> > I think we could just call free_kallsyms_local unconditionally in here
> > and fix callers to free syms pointer? seems easier than adding filtered*
> > fields to ksyms
>
> The strings in filtered_syms are ksyms->syms[i].name pointers (not
> copied). I didn't want to do another strdup, and I also didn't like
> passing three out parameters to bpf_get_ksyms().
>
> So I decided to consolidate the data gathered by bpf_get_ksyms() in
> struct ksyms. ksyms->filtered_syms essentially is a view into the
> ksyms->syms, and it can be unused too.
>
> Does this make sense?
yep, sounds good
thanks,
jirka
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH bpf-next v1 04/14] selftests/bpf: Refactor bpf_get_ksyms() trace helper
2026-02-12 1:13 ` [PATCH bpf-next v1 04/14] selftests/bpf: Refactor bpf_get_ksyms() trace helper Ihor Solodrai
2026-02-12 11:29 ` Jiri Olsa
@ 2026-02-13 9:56 ` Alexis Lothoré
1 sibling, 0 replies; 47+ messages in thread
From: Alexis Lothoré @ 2026-02-13 9:56 UTC (permalink / raw)
To: Ihor Solodrai, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann, Eduard Zingerman
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
Hi Ihor,
On Thu Feb 12, 2026 at 2:13 AM CET, Ihor Solodrai wrote:
> ASAN reported a memory leak in bpf_get_ksyms(): it allocates a struct
> ksyms internally and never frees it.
>
> Moe 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().
small typo: s/Moe/Move/g
Alexis
--
Alexis Lothoré, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH bpf-next v1 05/14] selftests/bpf: Fix memory leaks in tests
2026-02-12 1:13 [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN Ihor Solodrai
` (3 preceding siblings ...)
2026-02-12 1:13 ` [PATCH bpf-next v1 04/14] selftests/bpf: Refactor bpf_get_ksyms() trace helper Ihor Solodrai
@ 2026-02-12 1:13 ` Ihor Solodrai
2026-02-12 23:08 ` Eduard Zingerman
2026-02-12 1:13 ` [PATCH bpf-next v1 06/14] selftests/bpf: Fix cleanup in check_fd_array_cnt__fd_array_too_big() Ihor Solodrai
` (10 subsequent siblings)
15 siblings, 1 reply; 47+ messages in thread
From: Ihor Solodrai @ 2026-02-12 1:13 UTC (permalink / raw)
To: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
Fix trivial memory leaks detected by userspace ASAN:
- htab_update: free value buffer in test_reenter_update cleanup
- test_xsk: delete old pkt_stream before replacing in stats tests
- testing_helpers: free buffer allocated by getline() in
parse_test_list_file
Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
---
tools/testing/selftests/bpf/prog_tests/htab_update.c | 1 +
tools/testing/selftests/bpf/prog_tests/test_xsk.c | 2 ++
tools/testing/selftests/bpf/testing_helpers.c | 1 +
3 files changed, 4 insertions(+)
diff --git a/tools/testing/selftests/bpf/prog_tests/htab_update.c b/tools/testing/selftests/bpf/prog_tests/htab_update.c
index d0b405eb2966..ea1a6766fbe9 100644
--- a/tools/testing/selftests/bpf/prog_tests/htab_update.c
+++ b/tools/testing/selftests/bpf/prog_tests/htab_update.c
@@ -61,6 +61,7 @@ static void test_reenter_update(void)
ASSERT_EQ(skel->bss->update_err, -EDEADLK, "no reentrancy");
out:
+ free(value);
htab_update__destroy(skel);
}
diff --git a/tools/testing/selftests/bpf/prog_tests/test_xsk.c b/tools/testing/selftests/bpf/prog_tests/test_xsk.c
index bab4a31621c7..dac90ddcdd7e 100644
--- a/tools/testing/selftests/bpf/prog_tests/test_xsk.c
+++ b/tools/testing/selftests/bpf/prog_tests/test_xsk.c
@@ -2005,6 +2005,7 @@ int testapp_stats_rx_full(struct test_spec *test)
{
if (pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, MIN_PKT_SIZE))
return TEST_FAILURE;
+ pkt_stream_delete(test->ifobj_rx->xsk->pkt_stream);
test->ifobj_rx->xsk->pkt_stream = pkt_stream_generate(DEFAULT_UMEM_BUFFERS, MIN_PKT_SIZE);
test->ifobj_rx->xsk->rxqsize = DEFAULT_UMEM_BUFFERS;
@@ -2017,6 +2018,7 @@ int testapp_stats_fill_empty(struct test_spec *test)
{
if (pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, MIN_PKT_SIZE))
return TEST_FAILURE;
+ pkt_stream_delete(test->ifobj_rx->xsk->pkt_stream);
test->ifobj_rx->xsk->pkt_stream = pkt_stream_generate(DEFAULT_UMEM_BUFFERS, MIN_PKT_SIZE);
test->ifobj_rx->use_fill_ring = false;
diff --git a/tools/testing/selftests/bpf/testing_helpers.c b/tools/testing/selftests/bpf/testing_helpers.c
index 16eb37e5bad6..66af0d13751a 100644
--- a/tools/testing/selftests/bpf/testing_helpers.c
+++ b/tools/testing/selftests/bpf/testing_helpers.c
@@ -212,6 +212,7 @@ int parse_test_list_file(const char *path,
break;
}
+ free(buf);
fclose(f);
return err;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* Re: [PATCH bpf-next v1 05/14] selftests/bpf: Fix memory leaks in tests
2026-02-12 1:13 ` [PATCH bpf-next v1 05/14] selftests/bpf: Fix memory leaks in tests Ihor Solodrai
@ 2026-02-12 23:08 ` Eduard Zingerman
0 siblings, 0 replies; 47+ messages in thread
From: Eduard Zingerman @ 2026-02-12 23:08 UTC (permalink / raw)
To: Ihor Solodrai, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
On Wed, 2026-02-11 at 17:13 -0800, Ihor Solodrai wrote:
[...]
> @@ -2005,6 +2005,7 @@ int testapp_stats_rx_full(struct test_spec *test)
> {
> if (pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, MIN_PKT_SIZE))
> return TEST_FAILURE;
> + pkt_stream_delete(test->ifobj_rx->xsk->pkt_stream);
This one is a bit strange.
pkt_stream_replace() allocates test->ifobj_rx->xsk->pkt_stream and
test->ifobj_tx->xsk->pkt_stream (rx and tx streams), and proceeds to
immediately free the rx stream and allocate another one for it.
The following seem to be a better fit:
- if (pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, MIN_PKT_SIZE))
- return TEST_FAILURE;
- pkt_stream_delete(test->ifobj_rx->xsk->pkt_stream);
+ test->ifobj_tx->xsk->pkt_stream = pkt_stream_generate(DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, MIN_PKT_SIZE);
test->ifobj_rx->xsk->pkt_stream = pkt_stream_generate(DEFAULT_UMEM_BUFFERS, MIN_PKT_SIZE);
(I effectively inlined pkt_stream_replace()).
> test->ifobj_rx->xsk->pkt_stream = pkt_stream_generate(DEFAULT_UMEM_BUFFERS, MIN_PKT_SIZE);
>
> test->ifobj_rx->xsk->rxqsize = DEFAULT_UMEM_BUFFERS;
> @@ -2017,6 +2018,7 @@ int testapp_stats_fill_empty(struct test_spec *test)
> {
> if (pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, MIN_PKT_SIZE))
> return TEST_FAILURE;
> + pkt_stream_delete(test->ifobj_rx->xsk->pkt_stream);
> test->ifobj_rx->xsk->pkt_stream = pkt_stream_generate(DEFAULT_UMEM_BUFFERS, MIN_PKT_SIZE);
Same here.
[...]
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH bpf-next v1 06/14] selftests/bpf: Fix cleanup in check_fd_array_cnt__fd_array_too_big()
2026-02-12 1:13 [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN Ihor Solodrai
` (4 preceding siblings ...)
2026-02-12 1:13 ` [PATCH bpf-next v1 05/14] selftests/bpf: Fix memory leaks in tests Ihor Solodrai
@ 2026-02-12 1:13 ` Ihor Solodrai
2026-02-12 23:17 ` Eduard Zingerman
2026-02-12 1:13 ` [PATCH bpf-next v1 07/14] veristat: Fix a memory leak for preset ENUMERATOR Ihor Solodrai
` (9 subsequent siblings)
15 siblings, 1 reply; 47+ messages in thread
From: Ihor Solodrai @ 2026-02-12 1:13 UTC (permalink / raw)
To: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
The Close() macro uses the passed in expression three times, which
leads to repeated execution in case it has side effects. That is,
Close(i--) would decrement i three times.
ASAN caught a stack-buffer-undeflow error at a point where this was
overlooked. Fix it.
Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
---
tools/testing/selftests/bpf/prog_tests/fd_array.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/bpf/prog_tests/fd_array.c b/tools/testing/selftests/bpf/prog_tests/fd_array.c
index c534b4d5f9da..3078d8264deb 100644
--- a/tools/testing/selftests/bpf/prog_tests/fd_array.c
+++ b/tools/testing/selftests/bpf/prog_tests/fd_array.c
@@ -412,8 +412,8 @@ static void check_fd_array_cnt__fd_array_too_big(void)
ASSERT_EQ(prog_fd, -E2BIG, "prog should have been rejected with -E2BIG");
cleanup_fds:
- while (i > 0)
- Close(extra_fds[--i]);
+ while (i-- > 0)
+ Close(extra_fds[i]);
}
void test_fd_array_cnt(void)
--
2.53.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* Re: [PATCH bpf-next v1 06/14] selftests/bpf: Fix cleanup in check_fd_array_cnt__fd_array_too_big()
2026-02-12 1:13 ` [PATCH bpf-next v1 06/14] selftests/bpf: Fix cleanup in check_fd_array_cnt__fd_array_too_big() Ihor Solodrai
@ 2026-02-12 23:17 ` Eduard Zingerman
0 siblings, 0 replies; 47+ messages in thread
From: Eduard Zingerman @ 2026-02-12 23:17 UTC (permalink / raw)
To: Ihor Solodrai, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
On Wed, 2026-02-11 at 17:13 -0800, Ihor Solodrai wrote:
> The Close() macro uses the passed in expression three times, which
> leads to repeated execution in case it has side effects. That is,
> Close(i--) would decrement i three times.
>
> ASAN caught a stack-buffer-undeflow error at a point where this was
> overlooked. Fix it.
>
> Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
> ---
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
(However, in bpf headers the common pattern is to define a variable
in the macro body, something like `int ___fd = (FD);).
[...]
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH bpf-next v1 07/14] veristat: Fix a memory leak for preset ENUMERATOR
2026-02-12 1:13 [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN Ihor Solodrai
` (5 preceding siblings ...)
2026-02-12 1:13 ` [PATCH bpf-next v1 06/14] selftests/bpf: Fix cleanup in check_fd_array_cnt__fd_array_too_big() Ihor Solodrai
@ 2026-02-12 1:13 ` Ihor Solodrai
2026-02-12 13:37 ` Mykyta Yatsenko
2026-02-12 1:13 ` [PATCH bpf-next v1 08/14] selftests/bpf: Fix use-after-free in xdp_metadata test Ihor Solodrai
` (8 subsequent siblings)
15 siblings, 1 reply; 47+ messages in thread
From: Ihor Solodrai @ 2026-02-12 1:13 UTC (permalink / raw)
To: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
ASAN detected a memory leak in veristat. The cleanup code handling
ENUMERATOR value missed freeing strdup-ed svalue. Fix it.
Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
---
tools/testing/selftests/bpf/veristat.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/tools/testing/selftests/bpf/veristat.c b/tools/testing/selftests/bpf/veristat.c
index 1be1e353d40a..75f85e0362f5 100644
--- a/tools/testing/selftests/bpf/veristat.c
+++ b/tools/testing/selftests/bpf/veristat.c
@@ -3378,6 +3378,8 @@ int main(int argc, char **argv)
}
}
free(env.presets[i].atoms);
+ if (env.presets[i].value.type == ENUMERATOR)
+ free(env.presets[i].value.svalue);
}
free(env.presets);
return -err;
--
2.53.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* Re: [PATCH bpf-next v1 07/14] veristat: Fix a memory leak for preset ENUMERATOR
2026-02-12 1:13 ` [PATCH bpf-next v1 07/14] veristat: Fix a memory leak for preset ENUMERATOR Ihor Solodrai
@ 2026-02-12 13:37 ` Mykyta Yatsenko
0 siblings, 0 replies; 47+ messages in thread
From: Mykyta Yatsenko @ 2026-02-12 13:37 UTC (permalink / raw)
To: Ihor Solodrai, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann, Eduard Zingerman
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
On 2/12/26 01:13, Ihor Solodrai wrote:
> ASAN detected a memory leak in veristat. The cleanup code handling
> ENUMERATOR value missed freeing strdup-ed svalue. Fix it.
>
> Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
> ---
> tools/testing/selftests/bpf/veristat.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/tools/testing/selftests/bpf/veristat.c b/tools/testing/selftests/bpf/veristat.c
> index 1be1e353d40a..75f85e0362f5 100644
> --- a/tools/testing/selftests/bpf/veristat.c
> +++ b/tools/testing/selftests/bpf/veristat.c
> @@ -3378,6 +3378,8 @@ int main(int argc, char **argv)
> }
> }
> free(env.presets[i].atoms);
> + if (env.presets[i].value.type == ENUMERATOR)
> + free(env.presets[i].value.svalue);
> }
> free(env.presets);
> return -err;
Thanks for fixing!
Acked-by: Mykyta Yatsenko <yatsenko@meta.com>
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH bpf-next v1 08/14] selftests/bpf: Fix use-after-free in xdp_metadata test
2026-02-12 1:13 [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN Ihor Solodrai
` (6 preceding siblings ...)
2026-02-12 1:13 ` [PATCH bpf-next v1 07/14] veristat: Fix a memory leak for preset ENUMERATOR Ihor Solodrai
@ 2026-02-12 1:13 ` Ihor Solodrai
2026-02-12 13:40 ` Mykyta Yatsenko
2026-02-12 1:13 ` [PATCH bpf-next v1 09/14] selftests/bpf: Fix double thread join in uprobe_multi_test Ihor Solodrai
` (7 subsequent siblings)
15 siblings, 1 reply; 47+ messages in thread
From: Ihor Solodrai @ 2026-02-12 1:13 UTC (permalink / raw)
To: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
ASAN reported a use-after-free in close_xsk().
The xsk->socket internally references xsk->umem via socket->ctx->umem,
so the socket must be deleted before the umem. Fix the order of
operations in close_xsk().
Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
---
tools/testing/selftests/bpf/prog_tests/xdp_metadata.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c b/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c
index 19f92affc2da..5c31054ad4a4 100644
--- a/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c
+++ b/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c
@@ -126,10 +126,10 @@ static int open_xsk(int ifindex, struct xsk *xsk)
static void close_xsk(struct xsk *xsk)
{
- if (xsk->umem)
- xsk_umem__delete(xsk->umem);
if (xsk->socket)
xsk_socket__delete(xsk->socket);
+ if (xsk->umem)
+ xsk_umem__delete(xsk->umem);
munmap(xsk->umem_area, UMEM_SIZE);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* Re: [PATCH bpf-next v1 08/14] selftests/bpf: Fix use-after-free in xdp_metadata test
2026-02-12 1:13 ` [PATCH bpf-next v1 08/14] selftests/bpf: Fix use-after-free in xdp_metadata test Ihor Solodrai
@ 2026-02-12 13:40 ` Mykyta Yatsenko
0 siblings, 0 replies; 47+ messages in thread
From: Mykyta Yatsenko @ 2026-02-12 13:40 UTC (permalink / raw)
To: Ihor Solodrai, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann, Eduard Zingerman
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
On 2/12/26 01:13, Ihor Solodrai wrote:
> ASAN reported a use-after-free in close_xsk().
>
> The xsk->socket internally references xsk->umem via socket->ctx->umem,
> so the socket must be deleted before the umem. Fix the order of
> operations in close_xsk().
>
> Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
> ---
> tools/testing/selftests/bpf/prog_tests/xdp_metadata.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c b/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c
> index 19f92affc2da..5c31054ad4a4 100644
> --- a/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c
> +++ b/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c
> @@ -126,10 +126,10 @@ static int open_xsk(int ifindex, struct xsk *xsk)
>
> static void close_xsk(struct xsk *xsk)
> {
> - if (xsk->umem)
> - xsk_umem__delete(xsk->umem);
> if (xsk->socket)
> xsk_socket__delete(xsk->socket);
> + if (xsk->umem)
> + xsk_umem__delete(xsk->umem);
> munmap(xsk->umem_area, UMEM_SIZE);
> }
>
xsk_umem__delete() is indeed referencing umem, the change makes sense.
Acked-by: Mykyta Yatsenko <yatsenko@meta.com>
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH bpf-next v1 09/14] selftests/bpf: Fix double thread join in uprobe_multi_test
2026-02-12 1:13 [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN Ihor Solodrai
` (7 preceding siblings ...)
2026-02-12 1:13 ` [PATCH bpf-next v1 08/14] selftests/bpf: Fix use-after-free in xdp_metadata test Ihor Solodrai
@ 2026-02-12 1:13 ` Ihor Solodrai
2026-02-12 11:29 ` Jiri Olsa
2026-02-12 14:49 ` Mykyta Yatsenko
2026-02-12 1:13 ` [PATCH bpf-next v1 10/14] selftests/bpf: Fix resource leaks caused by missing cleanups Ihor Solodrai
` (6 subsequent siblings)
15 siblings, 2 replies; 47+ messages in thread
From: Ihor Solodrai @ 2026-02-12 1:13 UTC (permalink / raw)
To: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
ASAN reported a "joining already joined thread" error. The
release_child() may be called multiple times for the same struct
child.
Fix by setting child->thread to 0 after pthread_join.
Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
---
tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c b/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
index 2ee17ef1dae2..17881e009eee 100644
--- a/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
+++ b/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
@@ -62,8 +62,10 @@ static void release_child(struct child *child)
return;
close(child->go[1]);
close(child->go[0]);
- if (child->thread)
+ if (child->thread) {
pthread_join(child->thread, NULL);
+ child->thread = 0;
+ }
close(child->c2p[0]);
close(child->c2p[1]);
if (child->pid > 0)
--
2.53.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* Re: [PATCH bpf-next v1 09/14] selftests/bpf: Fix double thread join in uprobe_multi_test
2026-02-12 1:13 ` [PATCH bpf-next v1 09/14] selftests/bpf: Fix double thread join in uprobe_multi_test Ihor Solodrai
@ 2026-02-12 11:29 ` Jiri Olsa
2026-02-12 14:49 ` Mykyta Yatsenko
1 sibling, 0 replies; 47+ messages in thread
From: Jiri Olsa @ 2026-02-12 11:29 UTC (permalink / raw)
To: Ihor Solodrai
Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman, Amery Hung, Mykyta Yatsenko,
Alexis Lothoré, bpf, linux-kernel, kernel-team
On Wed, Feb 11, 2026 at 05:13:51PM -0800, Ihor Solodrai wrote:
> ASAN reported a "joining already joined thread" error. The
> release_child() may be called multiple times for the same struct
> child.
>
> Fix by setting child->thread to 0 after pthread_join.
>
> Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
Acked-by: Jiri Olsa <jolsa@kernel.org>
thanks,
jirka
> ---
> tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c b/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
> index 2ee17ef1dae2..17881e009eee 100644
> --- a/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
> +++ b/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
> @@ -62,8 +62,10 @@ static void release_child(struct child *child)
> return;
> close(child->go[1]);
> close(child->go[0]);
> - if (child->thread)
> + if (child->thread) {
> pthread_join(child->thread, NULL);
> + child->thread = 0;
> + }
> close(child->c2p[0]);
> close(child->c2p[1]);
> if (child->pid > 0)
> --
> 2.53.0
>
>
^ permalink raw reply [flat|nested] 47+ messages in thread* Re: [PATCH bpf-next v1 09/14] selftests/bpf: Fix double thread join in uprobe_multi_test
2026-02-12 1:13 ` [PATCH bpf-next v1 09/14] selftests/bpf: Fix double thread join in uprobe_multi_test Ihor Solodrai
2026-02-12 11:29 ` Jiri Olsa
@ 2026-02-12 14:49 ` Mykyta Yatsenko
2026-02-13 16:48 ` Jiri Olsa
1 sibling, 1 reply; 47+ messages in thread
From: Mykyta Yatsenko @ 2026-02-12 14:49 UTC (permalink / raw)
To: Ihor Solodrai, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann, Eduard Zingerman
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
On 2/12/26 01:13, Ihor Solodrai wrote:
> ASAN reported a "joining already joined thread" error. The
> release_child() may be called multiple times for the same struct
> child.
>
> Fix by setting child->thread to 0 after pthread_join.
>
> Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
> ---
> tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c b/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
> index 2ee17ef1dae2..17881e009eee 100644
> --- a/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
> +++ b/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
> @@ -62,8 +62,10 @@ static void release_child(struct child *child)
> return;
> close(child->go[1]);
> close(child->go[0]);
> - if (child->thread)
> + if (child->thread) {
> pthread_join(child->thread, NULL);
> + child->thread = 0;
> + }
> close(child->c2p[0]);
> close(child->c2p[1]);
> if (child->pid > 0)
As far as I understand the problem is due to `static struct child child` in
the test_attach_api(), once we initialize thread field of the child
it's not reset before the next test run.
Maybe we should also add memset(&child, 0, sizeof(child));
in test_attach_api() before each test to make sure all fields are reset.
Acked-by: Mykyta Yatsenko <yatsenko@meta.com>
^ permalink raw reply [flat|nested] 47+ messages in thread* Re: [PATCH bpf-next v1 09/14] selftests/bpf: Fix double thread join in uprobe_multi_test
2026-02-12 14:49 ` Mykyta Yatsenko
@ 2026-02-13 16:48 ` Jiri Olsa
0 siblings, 0 replies; 47+ messages in thread
From: Jiri Olsa @ 2026-02-13 16:48 UTC (permalink / raw)
To: Mykyta Yatsenko
Cc: Ihor Solodrai, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann, Eduard Zingerman, Amery Hung, Mykyta Yatsenko,
Alexis Lothoré, bpf, linux-kernel, kernel-team
On Thu, Feb 12, 2026 at 02:49:09PM +0000, Mykyta Yatsenko wrote:
> On 2/12/26 01:13, Ihor Solodrai wrote:
> > ASAN reported a "joining already joined thread" error. The
> > release_child() may be called multiple times for the same struct
> > child.
> >
> > Fix by setting child->thread to 0 after pthread_join.
> >
> > Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
> > ---
> > tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c | 4 +++-
> > 1 file changed, 3 insertions(+), 1 deletion(-)
> >
> > diff --git a/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c b/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
> > index 2ee17ef1dae2..17881e009eee 100644
> > --- a/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
> > +++ b/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
> > @@ -62,8 +62,10 @@ static void release_child(struct child *child)
> > return;
> > close(child->go[1]);
> > close(child->go[0]);
> > - if (child->thread)
> > + if (child->thread) {
> > pthread_join(child->thread, NULL);
> > + child->thread = 0;
> > + }
> > close(child->c2p[0]);
> > close(child->c2p[1]);
> > if (child->pid > 0)
> As far as I understand the problem is due to `static struct child child` in
> the test_attach_api(), once we initialize thread field of the child
> it's not reset before the next test run.
> Maybe we should also add memset(&child, 0, sizeof(child));
> in test_attach_api() before each test to make sure all fields are reset.
right, perhaps we could do memset right away in release_child,
jirka
>
> Acked-by: Mykyta Yatsenko <yatsenko@meta.com>
>
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH bpf-next v1 10/14] selftests/bpf: Fix resource leaks caused by missing cleanups
2026-02-12 1:13 [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN Ihor Solodrai
` (8 preceding siblings ...)
2026-02-12 1:13 ` [PATCH bpf-next v1 09/14] selftests/bpf: Fix double thread join in uprobe_multi_test Ihor Solodrai
@ 2026-02-12 1:13 ` Ihor Solodrai
2026-02-13 0:45 ` Eduard Zingerman
2026-02-12 1:13 ` [PATCH bpf-next v1 11/14] selftests/bpf: Free bpf_object in test_sysctl Ihor Solodrai
` (5 subsequent siblings)
15 siblings, 1 reply; 47+ messages in thread
From: Ihor Solodrai @ 2026-02-12 1:13 UTC (permalink / raw)
To: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
ASAN reported a number of resource leaks:
- Add missing *__destroy(skel) calls
- Replace bpf_link__detach() with bpf_link__destroy() where appropriate
- cgrp_local_storage: Add bpf_link__destroy() when bpf_iter_create fails
- dynptr: Add missing bpf_object__close()
Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
---
.../bpf/prog_tests/cgrp_local_storage.c | 4 +++-
.../testing/selftests/bpf/prog_tests/dynptr.c | 5 ++++-
.../selftests/bpf/prog_tests/sockmap_basic.c | 18 +++++++++++-------
.../selftests/bpf/prog_tests/sockmap_listen.c | 2 +-
.../bpf/prog_tests/struct_ops_private_stack.c | 1 +
.../testing/selftests/bpf/prog_tests/tc_opts.c | 1 +
.../selftests/bpf/prog_tests/test_tc_tunnel.c | 5 ++++-
7 files changed, 25 insertions(+), 11 deletions(-)
diff --git a/tools/testing/selftests/bpf/prog_tests/cgrp_local_storage.c b/tools/testing/selftests/bpf/prog_tests/cgrp_local_storage.c
index 9015e2c2ab12..478a77cb67e6 100644
--- a/tools/testing/selftests/bpf/prog_tests/cgrp_local_storage.c
+++ b/tools/testing/selftests/bpf/prog_tests/cgrp_local_storage.c
@@ -202,7 +202,7 @@ static void test_cgroup_iter_sleepable(int cgroup_fd, __u64 cgroup_id)
iter_fd = bpf_iter_create(bpf_link__fd(link));
if (!ASSERT_GE(iter_fd, 0, "iter_create"))
- goto out;
+ goto out_link;
/* trigger the program run */
(void)read(iter_fd, buf, sizeof(buf));
@@ -210,6 +210,8 @@ static void test_cgroup_iter_sleepable(int cgroup_fd, __u64 cgroup_id)
ASSERT_EQ(skel->bss->cgroup_id, cgroup_id, "cgroup_id");
close(iter_fd);
+out_link:
+ bpf_link__destroy(link);
out:
cgrp_ls_sleepable__destroy(skel);
}
diff --git a/tools/testing/selftests/bpf/prog_tests/dynptr.c b/tools/testing/selftests/bpf/prog_tests/dynptr.c
index b9f86cb91e81..5fda11590708 100644
--- a/tools/testing/selftests/bpf/prog_tests/dynptr.c
+++ b/tools/testing/selftests/bpf/prog_tests/dynptr.c
@@ -137,11 +137,14 @@ static void verify_success(const char *prog_name, enum test_setup_type setup_typ
);
link = bpf_program__attach(prog);
- if (!ASSERT_OK_PTR(link, "bpf_program__attach"))
+ if (!ASSERT_OK_PTR(link, "bpf_program__attach")) {
+ bpf_object__close(obj);
goto cleanup;
+ }
err = bpf_prog_test_run_opts(aux_prog_fd, &topts);
bpf_link__destroy(link);
+ bpf_object__close(obj);
if (!ASSERT_OK(err, "test_run"))
goto cleanup;
diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c
index 256707e7d20d..ce010602a443 100644
--- a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c
+++ b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c
@@ -204,7 +204,7 @@ static void test_skmsg_helpers_with_link(enum bpf_map_type map_type)
/* Fail since bpf_link for the same prog type has been created. */
link2 = bpf_program__attach_sockmap(prog_clone, map);
if (!ASSERT_ERR_PTR(link2, "bpf_program__attach_sockmap")) {
- bpf_link__detach(link2);
+ bpf_link__destroy(link2);
goto out;
}
@@ -230,7 +230,7 @@ static void test_skmsg_helpers_with_link(enum bpf_map_type map_type)
if (!ASSERT_OK(err, "bpf_link_update"))
goto out;
out:
- bpf_link__detach(link);
+ bpf_link__destroy(link);
test_skmsg_load_helpers__destroy(skel);
}
@@ -417,7 +417,7 @@ static void test_sockmap_skb_verdict_attach_with_link(void)
if (!ASSERT_OK_PTR(link, "bpf_program__attach_sockmap"))
goto out;
- bpf_link__detach(link);
+ bpf_link__destroy(link);
err = bpf_prog_attach(bpf_program__fd(prog), map, BPF_SK_SKB_STREAM_VERDICT, 0);
if (!ASSERT_OK(err, "bpf_prog_attach"))
@@ -426,7 +426,7 @@ static void test_sockmap_skb_verdict_attach_with_link(void)
/* Fail since attaching with the same prog/map has been done. */
link = bpf_program__attach_sockmap(prog, map);
if (!ASSERT_ERR_PTR(link, "bpf_program__attach_sockmap"))
- bpf_link__detach(link);
+ bpf_link__destroy(link);
err = bpf_prog_detach2(bpf_program__fd(prog), map, BPF_SK_SKB_STREAM_VERDICT);
if (!ASSERT_OK(err, "bpf_prog_detach2"))
@@ -747,7 +747,7 @@ static void test_sockmap_skb_verdict_peek_with_link(void)
test_sockmap_skb_verdict_peek_helper(map);
ASSERT_EQ(pass->bss->clone_called, 1, "clone_called");
out:
- bpf_link__detach(link);
+ bpf_link__destroy(link);
test_sockmap_pass_prog__destroy(pass);
}
@@ -763,12 +763,15 @@ static void test_sockmap_unconnected_unix(void)
map = bpf_map__fd(skel->maps.sock_map_rx);
stream = xsocket(AF_UNIX, SOCK_STREAM, 0);
- if (stream < 0)
+ if (stream < 0) {
+ test_sockmap_pass_prog__destroy(skel);
return;
+ }
dgram = xsocket(AF_UNIX, SOCK_DGRAM, 0);
if (dgram < 0) {
close(stream);
+ test_sockmap_pass_prog__destroy(skel);
return;
}
@@ -780,6 +783,7 @@ static void test_sockmap_unconnected_unix(void)
close(stream);
close(dgram);
+ test_sockmap_pass_prog__destroy(skel);
}
static void test_sockmap_many_socket(void)
@@ -1027,7 +1031,7 @@ static void test_sockmap_skb_verdict_vsock_poll(void)
if (xrecv_nonblock(conn, &buf, 1, 0) != 1)
FAIL("xrecv_nonblock");
detach:
- bpf_link__detach(link);
+ bpf_link__destroy(link);
close:
xclose(conn);
xclose(peer);
diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
index f1bdccc7e4e7..cc0c68bab907 100644
--- a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
+++ b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
@@ -899,7 +899,7 @@ static void test_msg_redir_to_listening_with_link(struct test_sockmap_listen *sk
redir_to_listening(family, sotype, sock_map, verdict_map, REDIR_EGRESS);
- bpf_link__detach(link);
+ bpf_link__destroy(link);
}
static void redir_partial(int family, int sotype, int sock_map, int parser_map)
diff --git a/tools/testing/selftests/bpf/prog_tests/struct_ops_private_stack.c b/tools/testing/selftests/bpf/prog_tests/struct_ops_private_stack.c
index 4006879ca3fe..c36aa2354d2f 100644
--- a/tools/testing/selftests/bpf/prog_tests/struct_ops_private_stack.c
+++ b/tools/testing/selftests/bpf/prog_tests/struct_ops_private_stack.c
@@ -56,6 +56,7 @@ static void test_private_stack_fail(void)
err = struct_ops_private_stack_fail__load(skel);
if (!ASSERT_ERR(err, "struct_ops_private_stack_fail__load"))
goto cleanup;
+ struct_ops_private_stack_fail__destroy(skel);
return;
cleanup:
diff --git a/tools/testing/selftests/bpf/prog_tests/tc_opts.c b/tools/testing/selftests/bpf/prog_tests/tc_opts.c
index dd7a138d8c3d..2a4fd367da0a 100644
--- a/tools/testing/selftests/bpf/prog_tests/tc_opts.c
+++ b/tools/testing/selftests/bpf/prog_tests/tc_opts.c
@@ -1363,6 +1363,7 @@ static void test_tc_opts_dev_cleanup_target(int target)
ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");
ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");
ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");
+ test_tc_link__destroy(skel);
return;
cleanup3:
err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
diff --git a/tools/testing/selftests/bpf/prog_tests/test_tc_tunnel.c b/tools/testing/selftests/bpf/prog_tests/test_tc_tunnel.c
index 0fe0a8f62486..7fc4d7dd70ef 100644
--- a/tools/testing/selftests/bpf/prog_tests/test_tc_tunnel.c
+++ b/tools/testing/selftests/bpf/prog_tests/test_tc_tunnel.c
@@ -699,7 +699,7 @@ void test_tc_tunnel(void)
return;
if (!ASSERT_OK(setup(), "global setup"))
- return;
+ goto out;
for (i = 0; i < ARRAY_SIZE(subtests_cfg); i++) {
cfg = &subtests_cfg[i];
@@ -711,4 +711,7 @@ void test_tc_tunnel(void)
subtest_cleanup(cfg);
}
cleanup();
+
+out:
+ test_tc_tunnel__destroy(skel);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* Re: [PATCH bpf-next v1 10/14] selftests/bpf: Fix resource leaks caused by missing cleanups
2026-02-12 1:13 ` [PATCH bpf-next v1 10/14] selftests/bpf: Fix resource leaks caused by missing cleanups Ihor Solodrai
@ 2026-02-13 0:45 ` Eduard Zingerman
0 siblings, 0 replies; 47+ messages in thread
From: Eduard Zingerman @ 2026-02-13 0:45 UTC (permalink / raw)
To: Ihor Solodrai, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
On Wed, 2026-02-11 at 17:13 -0800, Ihor Solodrai wrote:
> ASAN reported a number of resource leaks:
> - Add missing *__destroy(skel) calls
> - Replace bpf_link__detach() with bpf_link__destroy() where appropriate
> - cgrp_local_storage: Add bpf_link__destroy() when bpf_iter_create fails
> - dynptr: Add missing bpf_object__close()
>
> Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
> ---
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
[...]
> diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c
> b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c
> index 256707e7d20d..ce010602a443 100644
> --- a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c
> +++ b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c
[...]
> @@ -763,12 +763,15 @@ static void test_sockmap_unconnected_unix(void)
> map = bpf_map__fd(skel->maps.sock_map_rx);
>
> stream = xsocket(AF_UNIX, SOCK_STREAM, 0);
> - if (stream < 0)
> + if (stream < 0) {
> + test_sockmap_pass_prog__destroy(skel);
> return;
> + }
>
> dgram = xsocket(AF_UNIX, SOCK_DGRAM, 0);
> if (dgram < 0) {
> close(stream);
> + test_sockmap_pass_prog__destroy(skel);
> return;
> }
Nit: initialize `stream` and `dgram` as -1 and add an exit label?
> @@ -780,6 +783,7 @@ static void test_sockmap_unconnected_unix(void)
>
> close(stream);
> close(dgram);
> + test_sockmap_pass_prog__destroy(skel);
> }
[...]
> diff --git a/tools/testing/selftests/bpf/prog_tests/struct_ops_private_stack.c
> b/tools/testing/selftests/bpf/prog_tests/struct_ops_private_stack.c
> index 4006879ca3fe..c36aa2354d2f 100644
> --- a/tools/testing/selftests/bpf/prog_tests/struct_ops_private_stack.c
> +++ b/tools/testing/selftests/bpf/prog_tests/struct_ops_private_stack.c
> @@ -56,6 +56,7 @@ static void test_private_stack_fail(void)
> err = struct_ops_private_stack_fail__load(skel);
> if (!ASSERT_ERR(err, "struct_ops_private_stack_fail__load"))
> goto cleanup;
> + struct_ops_private_stack_fail__destroy(skel);
> return;
Nit: just remove 'return' instead?
`cleanup` already calls `destroy`.
>
> cleanup:
> diff --git a/tools/testing/selftests/bpf/prog_tests/tc_opts.c
> b/tools/testing/selftests/bpf/prog_tests/tc_opts.c
> index dd7a138d8c3d..2a4fd367da0a 100644
> --- a/tools/testing/selftests/bpf/prog_tests/tc_opts.c
> +++ b/tools/testing/selftests/bpf/prog_tests/tc_opts.c
> @@ -1363,6 +1363,7 @@ static void test_tc_opts_dev_cleanup_target(int target)
> ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");
> ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");
> ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");
> + test_tc_link__destroy(skel);
Nit: this is exact copy of the `cleanup` label below.
One can replace the three ASSERTs and the `destroy` call
with `goto cleanup`.
[...]
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH bpf-next v1 11/14] selftests/bpf: Free bpf_object in test_sysctl
2026-02-12 1:13 [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN Ihor Solodrai
` (9 preceding siblings ...)
2026-02-12 1:13 ` [PATCH bpf-next v1 10/14] selftests/bpf: Fix resource leaks caused by missing cleanups Ihor Solodrai
@ 2026-02-12 1:13 ` Ihor Solodrai
2026-02-13 0:54 ` Eduard Zingerman
2026-02-12 1:13 ` [PATCH bpf-next v1 12/14] selftests/bpf: Fix array bounds warning in jit_disasm_helpers Ihor Solodrai
` (4 subsequent siblings)
15 siblings, 1 reply; 47+ messages in thread
From: Ihor Solodrai @ 2026-02-12 1:13 UTC (permalink / raw)
To: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
ASAN reported a resource leak due to the bpf_object not being tracked
in test_sysctl. Add an out parameter to load_sysctl_prog() to properly
clean up bpf_object if a program was loaded from a file.
Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
---
.../selftests/bpf/prog_tests/test_sysctl.c | 22 +++++++++++++------
1 file changed, 15 insertions(+), 7 deletions(-)
diff --git a/tools/testing/selftests/bpf/prog_tests/test_sysctl.c b/tools/testing/selftests/bpf/prog_tests/test_sysctl.c
index 273dd41ca09e..31f4bba87c3e 100644
--- a/tools/testing/selftests/bpf/prog_tests/test_sysctl.c
+++ b/tools/testing/selftests/bpf/prog_tests/test_sysctl.c
@@ -1459,7 +1459,8 @@ static int load_sysctl_prog_insns(struct sysctl_test *test,
return ret;
}
-static int load_sysctl_prog_file(struct sysctl_test *test)
+static int load_sysctl_prog_file(struct sysctl_test *test,
+ struct bpf_object **objp)
{
struct bpf_object *obj;
int prog_fd;
@@ -1471,14 +1472,17 @@ static int load_sysctl_prog_file(struct sysctl_test *test)
return -1;
}
+ *objp = obj;
return prog_fd;
}
-static int load_sysctl_prog(struct sysctl_test *test, const char *sysctl_path)
+static int load_sysctl_prog(struct sysctl_test *test, const char *sysctl_path,
+ struct bpf_object **objp)
{
- return test->prog_file
- ? load_sysctl_prog_file(test)
- : load_sysctl_prog_insns(test, sysctl_path);
+ if (test->prog_file)
+ return load_sysctl_prog_file(test, objp);
+ *objp = NULL;
+ return load_sysctl_prog_insns(test, sysctl_path);
}
static int access_sysctl(const char *sysctl_path,
@@ -1529,6 +1533,7 @@ static int access_sysctl(const char *sysctl_path,
static int run_test_case(int cgfd, struct sysctl_test *test)
{
enum bpf_attach_type atype = test->attach_type;
+ struct bpf_object *obj = NULL;
char sysctl_path[128];
int progfd = -1;
int err = 0;
@@ -1538,7 +1543,7 @@ static int run_test_case(int cgfd, struct sysctl_test *test)
snprintf(sysctl_path, sizeof(sysctl_path), "/proc/sys/%s",
test->sysctl);
- progfd = load_sysctl_prog(test, sysctl_path);
+ progfd = load_sysctl_prog(test, sysctl_path, &obj);
if (progfd < 0) {
if (test->result == LOAD_REJECT)
goto out;
@@ -1573,7 +1578,10 @@ static int run_test_case(int cgfd, struct sysctl_test *test)
/* Detaching w/o checking return code: best effort attempt. */
if (progfd != -1)
bpf_prog_detach(cgfd, atype);
- close(progfd);
+ if (obj)
+ bpf_object__close(obj);
+ else if (progfd != -1)
+ close(progfd);
printf("[%s]\n", err ? "FAIL" : "PASS");
return err;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* Re: [PATCH bpf-next v1 11/14] selftests/bpf: Free bpf_object in test_sysctl
2026-02-12 1:13 ` [PATCH bpf-next v1 11/14] selftests/bpf: Free bpf_object in test_sysctl Ihor Solodrai
@ 2026-02-13 0:54 ` Eduard Zingerman
0 siblings, 0 replies; 47+ messages in thread
From: Eduard Zingerman @ 2026-02-13 0:54 UTC (permalink / raw)
To: Ihor Solodrai, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
On Wed, 2026-02-11 at 17:13 -0800, Ihor Solodrai wrote:
> ASAN reported a resource leak due to the bpf_object not being tracked
> in test_sysctl. Add an out parameter to load_sysctl_prog() to properly
> clean up bpf_object if a program was loaded from a file.
>
> Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
> ---
Maybe make 'obj' a member of the `struct sysctl_test`?
[...]
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH bpf-next v1 12/14] selftests/bpf: Fix array bounds warning in jit_disasm_helpers
2026-02-12 1:13 [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN Ihor Solodrai
` (10 preceding siblings ...)
2026-02-12 1:13 ` [PATCH bpf-next v1 11/14] selftests/bpf: Free bpf_object in test_sysctl Ihor Solodrai
@ 2026-02-12 1:13 ` Ihor Solodrai
2026-02-13 1:02 ` Eduard Zingerman
2026-02-12 1:13 ` [PATCH bpf-next v1 13/14] selftests/bpf: Fix out-of-bounds array access bugs reported by ASAN Ihor Solodrai
` (3 subsequent siblings)
15 siblings, 1 reply; 47+ messages in thread
From: Ihor Solodrai @ 2026-02-12 1:13 UTC (permalink / raw)
To: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
Compiler cannot infer upper bound for labels.cnt and warns about
potential buffer overflow in snprintf. Add an explicit bounds
check (... && i < MAX_LOCAL_LABELS) in the loop condition to fix the
warning.
Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
---
.../testing/selftests/bpf/jit_disasm_helpers.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/tools/testing/selftests/bpf/jit_disasm_helpers.c b/tools/testing/selftests/bpf/jit_disasm_helpers.c
index febd6b12e372..364c557c5115 100644
--- a/tools/testing/selftests/bpf/jit_disasm_helpers.c
+++ b/tools/testing/selftests/bpf/jit_disasm_helpers.c
@@ -122,15 +122,15 @@ static int disasm_one_func(FILE *text_out, uint8_t *image, __u32 len)
pc += cnt;
}
qsort(labels.pcs, labels.cnt, sizeof(*labels.pcs), cmp_u32);
- for (i = 0; i < labels.cnt; ++i)
- /* gcc is unable to infer upper bound for labels.cnt and assumes
- * it to be U32_MAX. U32_MAX takes 10 decimal digits.
- * snprintf below prints into labels.names[*],
- * which has space only for two digits and a letter.
- * To avoid truncation warning use (i % MAX_LOCAL_LABELS),
- * which informs gcc about printed value upper bound.
- */
- snprintf(labels.names[i], sizeof(labels.names[i]), "L%d", i % MAX_LOCAL_LABELS);
+ /* gcc is unable to infer upper bound for labels.cnt and
+ * assumes it to be U32_MAX. U32_MAX takes 10 decimal digits.
+ * snprintf below prints into labels.names[*], which has space
+ * only for two digits and a letter. To avoid truncation
+ * warning use (i < MAX_LOCAL_LABELS), which informs gcc about
+ * printed value upper bound.
+ */
+ for (i = 0; i < labels.cnt && i < MAX_LOCAL_LABELS; ++i)
+ snprintf(labels.names[i], sizeof(labels.names[i]), "L%d", i);
/* now print with labels */
labels.print_phase = true;
--
2.53.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* Re: [PATCH bpf-next v1 12/14] selftests/bpf: Fix array bounds warning in jit_disasm_helpers
2026-02-12 1:13 ` [PATCH bpf-next v1 12/14] selftests/bpf: Fix array bounds warning in jit_disasm_helpers Ihor Solodrai
@ 2026-02-13 1:02 ` Eduard Zingerman
0 siblings, 0 replies; 47+ messages in thread
From: Eduard Zingerman @ 2026-02-13 1:02 UTC (permalink / raw)
To: Ihor Solodrai, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
On Wed, 2026-02-11 at 17:13 -0800, Ihor Solodrai wrote:
> Compiler cannot infer upper bound for labels.cnt and warns about
> potential buffer overflow in snprintf. Add an explicit bounds
> check (... && i < MAX_LOCAL_LABELS) in the loop condition to fix the
> warning.
>
> Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
> ---
This annoying false positive strikes again :(
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
[...]
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH bpf-next v1 13/14] selftests/bpf: Fix out-of-bounds array access bugs reported by ASAN
2026-02-12 1:13 [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN Ihor Solodrai
` (11 preceding siblings ...)
2026-02-12 1:13 ` [PATCH bpf-next v1 12/14] selftests/bpf: Fix array bounds warning in jit_disasm_helpers Ihor Solodrai
@ 2026-02-12 1:13 ` Ihor Solodrai
2026-02-13 1:11 ` Eduard Zingerman
2026-02-12 1:13 ` [PATCH bpf-next v1 14/14] selftests/bpf: Check BPFTOOL env var in detect_bpftool_path() Ihor Solodrai
` (2 subsequent siblings)
15 siblings, 1 reply; 47+ messages in thread
From: Ihor Solodrai @ 2026-02-12 1:13 UTC (permalink / raw)
To: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
- kmem_cache_iter: remove unnecessary debug output
- lwt_seg6local: change the type of foobar to char[]
- the sizeof(foobar) returned the pointer size and not a string
length as intended
- verifier_log: increase prog_name buffer size in verif_log_subtest()
- compiler has a conservative estimate of fixed_log_sz value, making
ASAN complain on snprint() call
Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
---
tools/testing/selftests/bpf/prog_tests/kmem_cache_iter.c | 7 ++-----
tools/testing/selftests/bpf/prog_tests/lwt_seg6local.c | 2 +-
tools/testing/selftests/bpf/prog_tests/verifier_log.c | 2 +-
3 files changed, 4 insertions(+), 7 deletions(-)
diff --git a/tools/testing/selftests/bpf/prog_tests/kmem_cache_iter.c b/tools/testing/selftests/bpf/prog_tests/kmem_cache_iter.c
index 6e35e13c2022..399fe9103f83 100644
--- a/tools/testing/selftests/bpf/prog_tests/kmem_cache_iter.c
+++ b/tools/testing/selftests/bpf/prog_tests/kmem_cache_iter.c
@@ -104,11 +104,8 @@ void test_kmem_cache_iter(void)
if (!ASSERT_GE(iter_fd, 0, "iter_create"))
goto destroy;
- memset(buf, 0, sizeof(buf));
- while (read(iter_fd, buf, sizeof(buf)) > 0) {
- /* Read out all contents */
- printf("%s", buf);
- }
+ while (read(iter_fd, buf, sizeof(buf)) > 0)
+ ; /* Read out all contents */
/* Next reads should return 0 */
ASSERT_EQ(read(iter_fd, buf, sizeof(buf)), 0, "read");
diff --git a/tools/testing/selftests/bpf/prog_tests/lwt_seg6local.c b/tools/testing/selftests/bpf/prog_tests/lwt_seg6local.c
index 3bc730b7c7fa..1b25d5c5f8fb 100644
--- a/tools/testing/selftests/bpf/prog_tests/lwt_seg6local.c
+++ b/tools/testing/selftests/bpf/prog_tests/lwt_seg6local.c
@@ -117,7 +117,7 @@ void test_lwt_seg6local(void)
const char *ns1 = NETNS_BASE "1";
const char *ns6 = NETNS_BASE "6";
struct nstoken *nstoken = NULL;
- const char *foobar = "foobar";
+ const char foobar[] = "foobar";
ssize_t bytes;
int sfd, cfd;
char buf[7];
diff --git a/tools/testing/selftests/bpf/prog_tests/verifier_log.c b/tools/testing/selftests/bpf/prog_tests/verifier_log.c
index 8337c6bc5b95..aaa2854974c0 100644
--- a/tools/testing/selftests/bpf/prog_tests/verifier_log.c
+++ b/tools/testing/selftests/bpf/prog_tests/verifier_log.c
@@ -47,7 +47,7 @@ static int load_prog(struct bpf_prog_load_opts *opts, bool expect_load_error)
static void verif_log_subtest(const char *name, bool expect_load_error, int log_level)
{
LIBBPF_OPTS(bpf_prog_load_opts, opts);
- char *exp_log, prog_name[16], op_name[32];
+ char *exp_log, prog_name[24], op_name[32];
struct test_log_buf *skel;
struct bpf_program *prog;
size_t fixed_log_sz;
--
2.53.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* Re: [PATCH bpf-next v1 13/14] selftests/bpf: Fix out-of-bounds array access bugs reported by ASAN
2026-02-12 1:13 ` [PATCH bpf-next v1 13/14] selftests/bpf: Fix out-of-bounds array access bugs reported by ASAN Ihor Solodrai
@ 2026-02-13 1:11 ` Eduard Zingerman
2026-02-17 23:27 ` Ihor Solodrai
0 siblings, 1 reply; 47+ messages in thread
From: Eduard Zingerman @ 2026-02-13 1:11 UTC (permalink / raw)
To: Ihor Solodrai, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
On Wed, 2026-02-11 at 17:13 -0800, Ihor Solodrai wrote:
> - kmem_cache_iter: remove unnecessary debug output
> - lwt_seg6local: change the type of foobar to char[]
> - the sizeof(foobar) returned the pointer size and not a string
> length as intended
> - verifier_log: increase prog_name buffer size in verif_log_subtest()
> - compiler has a conservative estimate of fixed_log_sz value, making
> ASAN complain on snprint() call
>
> Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
> ---
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
[...]
> diff --git a/tools/testing/selftests/bpf/prog_tests/kmem_cache_iter.c
> b/tools/testing/selftests/bpf/prog_tests/kmem_cache_iter.c
> index 6e35e13c2022..399fe9103f83 100644
> --- a/tools/testing/selftests/bpf/prog_tests/kmem_cache_iter.c
> +++ b/tools/testing/selftests/bpf/prog_tests/kmem_cache_iter.c
> @@ -104,11 +104,8 @@ void test_kmem_cache_iter(void)
> if (!ASSERT_GE(iter_fd, 0, "iter_create"))
> goto destroy;
>
> - memset(buf, 0, sizeof(buf));
> - while (read(iter_fd, buf, sizeof(buf)) > 0) {
> - /* Read out all contents */
> - printf("%s", buf);
> - }
> + while (read(iter_fd, buf, sizeof(buf)) > 0)
> + ; /* Read out all contents */
Nit:
- while (read(iter_fd, buf, sizeof(buf)) > 0) {
+ while (read(iter_fd, buf, sizeof(buf) - 1) > 0) {
And keep the log?
[...]
^ permalink raw reply [flat|nested] 47+ messages in thread* Re: [PATCH bpf-next v1 13/14] selftests/bpf: Fix out-of-bounds array access bugs reported by ASAN
2026-02-13 1:11 ` Eduard Zingerman
@ 2026-02-17 23:27 ` Ihor Solodrai
0 siblings, 0 replies; 47+ messages in thread
From: Ihor Solodrai @ 2026-02-17 23:27 UTC (permalink / raw)
To: Eduard Zingerman, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
On 2/12/26 5:11 PM, Eduard Zingerman wrote:
> On Wed, 2026-02-11 at 17:13 -0800, Ihor Solodrai wrote:
>> - kmem_cache_iter: remove unnecessary debug output
>> - lwt_seg6local: change the type of foobar to char[]
>> - the sizeof(foobar) returned the pointer size and not a string
>> length as intended
>> - verifier_log: increase prog_name buffer size in verif_log_subtest()
>> - compiler has a conservative estimate of fixed_log_sz value, making
>> ASAN complain on snprint() call
>>
>> Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
>> ---
>
> Acked-by: Eduard Zingerman <eddyz87@gmail.com>
>
> [...]
>
>> diff --git a/tools/testing/selftests/bpf/prog_tests/kmem_cache_iter.c
>> b/tools/testing/selftests/bpf/prog_tests/kmem_cache_iter.c
>> index 6e35e13c2022..399fe9103f83 100644
>> --- a/tools/testing/selftests/bpf/prog_tests/kmem_cache_iter.c
>> +++ b/tools/testing/selftests/bpf/prog_tests/kmem_cache_iter.c
>> @@ -104,11 +104,8 @@ void test_kmem_cache_iter(void)
>> if (!ASSERT_GE(iter_fd, 0, "iter_create"))
>> goto destroy;
>>
>> - memset(buf, 0, sizeof(buf));
>> - while (read(iter_fd, buf, sizeof(buf)) > 0) {
>> - /* Read out all contents */
>> - printf("%s", buf);
>> - }
>> + while (read(iter_fd, buf, sizeof(buf)) > 0)
>> + ; /* Read out all contents */
>
> Nit:
> - while (read(iter_fd, buf, sizeof(buf)) > 0) {
> + while (read(iter_fd, buf, sizeof(buf) - 1) > 0) {
>
> And keep the log?
AFAIU it's not necessary for the test, it seems to be a debug print.
There is an exact copy of this loop without printf in dmabuf_iter.c.
>
> [...]
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH bpf-next v1 14/14] selftests/bpf: Check BPFTOOL env var in detect_bpftool_path()
2026-02-12 1:13 [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN Ihor Solodrai
` (12 preceding siblings ...)
2026-02-12 1:13 ` [PATCH bpf-next v1 13/14] selftests/bpf: Fix out-of-bounds array access bugs reported by ASAN Ihor Solodrai
@ 2026-02-12 1:13 ` Ihor Solodrai
2026-02-12 15:03 ` Mykyta Yatsenko
2026-02-13 10:36 ` Alexis Lothoré
2026-02-12 22:00 ` [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN Eduard Zingerman
2026-02-12 23:26 ` Eduard Zingerman
15 siblings, 2 replies; 47+ messages in thread
From: Ihor Solodrai @ 2026-02-12 1:13 UTC (permalink / raw)
To: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
The bpftool_maps_access and bpftool_metadata tests may fail on BPF CI
with "command not found", depending on a workflow.
This happens because detect_bpftool_path() only checks two hardcoded
relative paths:
- ./tools/sbin/bpftool
- ../tools/sbin/bpftool
Add support for a BPFTOOL environment variable that allows specifying
the exact path to the bpftool binary.
Also replace strncpy() with snprintf() for proper null-termination.
Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
---
tools/testing/selftests/bpf/bpftool_helpers.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/bpf/bpftool_helpers.c b/tools/testing/selftests/bpf/bpftool_helpers.c
index a5824945a4a5..5435ecd720d1 100644
--- a/tools/testing/selftests/bpf/bpftool_helpers.c
+++ b/tools/testing/selftests/bpf/bpftool_helpers.c
@@ -12,13 +12,21 @@
static int detect_bpftool_path(char *buffer)
{
char tmp[BPFTOOL_PATH_MAX_LEN];
+ const char *env_path;
+
+ /* First, check if BPFTOOL environment variable is set */
+ env_path = getenv("BPFTOOL");
+ if (env_path && access(env_path, X_OK) == 0) {
+ snprintf(buffer, BPFTOOL_PATH_MAX_LEN, "%s", env_path);
+ return 0;
+ }
/* Check default bpftool location (will work if we are running the
* default flavor of test_progs)
*/
snprintf(tmp, BPFTOOL_PATH_MAX_LEN, "./%s", BPFTOOL_DEFAULT_PATH);
if (access(tmp, X_OK) == 0) {
- strncpy(buffer, tmp, BPFTOOL_PATH_MAX_LEN);
+ snprintf(buffer, BPFTOOL_PATH_MAX_LEN, "%s", tmp);
return 0;
}
@@ -27,7 +35,7 @@ static int detect_bpftool_path(char *buffer)
*/
snprintf(tmp, BPFTOOL_PATH_MAX_LEN, "../%s", BPFTOOL_DEFAULT_PATH);
if (access(tmp, X_OK) == 0) {
- strncpy(buffer, tmp, BPFTOOL_PATH_MAX_LEN);
+ snprintf(buffer, BPFTOOL_PATH_MAX_LEN, "%s", tmp);
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* Re: [PATCH bpf-next v1 14/14] selftests/bpf: Check BPFTOOL env var in detect_bpftool_path()
2026-02-12 1:13 ` [PATCH bpf-next v1 14/14] selftests/bpf: Check BPFTOOL env var in detect_bpftool_path() Ihor Solodrai
@ 2026-02-12 15:03 ` Mykyta Yatsenko
2026-02-13 10:36 ` Alexis Lothoré
1 sibling, 0 replies; 47+ messages in thread
From: Mykyta Yatsenko @ 2026-02-12 15:03 UTC (permalink / raw)
To: Ihor Solodrai, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann, Eduard Zingerman
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
On 2/12/26 01:13, Ihor Solodrai wrote:
> The bpftool_maps_access and bpftool_metadata tests may fail on BPF CI
> with "command not found", depending on a workflow.
> This happens because detect_bpftool_path() only checks two hardcoded
> relative paths:
> - ./tools/sbin/bpftool
> - ../tools/sbin/bpftool
>
> Add support for a BPFTOOL environment variable that allows specifying
> the exact path to the bpftool binary.
>
> Also replace strncpy() with snprintf() for proper null-termination.
>
> Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
> ---
> tools/testing/selftests/bpf/bpftool_helpers.c | 12 ++++++++++--
> 1 file changed, 10 insertions(+), 2 deletions(-)
>
> diff --git a/tools/testing/selftests/bpf/bpftool_helpers.c b/tools/testing/selftests/bpf/bpftool_helpers.c
> index a5824945a4a5..5435ecd720d1 100644
> --- a/tools/testing/selftests/bpf/bpftool_helpers.c
> +++ b/tools/testing/selftests/bpf/bpftool_helpers.c
> @@ -12,13 +12,21 @@
> static int detect_bpftool_path(char *buffer)
> {
> char tmp[BPFTOOL_PATH_MAX_LEN];
> + const char *env_path;
> +
> + /* First, check if BPFTOOL environment variable is set */
> + env_path = getenv("BPFTOOL");
> + if (env_path && access(env_path, X_OK) == 0) {
nit: we are checking access(path, X_OK) in multiple places in this function,
but never report any failures if those checks fail, it may be confusing
for user,
as file is there but function fails to find bpftool binary.
> + snprintf(buffer, BPFTOOL_PATH_MAX_LEN, "%s", env_path);
> + return 0;
> + }
>
> /* Check default bpftool location (will work if we are running the
> * default flavor of test_progs)
> */
> snprintf(tmp, BPFTOOL_PATH_MAX_LEN, "./%s", BPFTOOL_DEFAULT_PATH);
> if (access(tmp, X_OK) == 0) {
> - strncpy(buffer, tmp, BPFTOOL_PATH_MAX_LEN);
> + snprintf(buffer, BPFTOOL_PATH_MAX_LEN, "%s", tmp);
> return 0;
> }
>
> @@ -27,7 +35,7 @@ static int detect_bpftool_path(char *buffer)
> */
> snprintf(tmp, BPFTOOL_PATH_MAX_LEN, "../%s", BPFTOOL_DEFAULT_PATH);
> if (access(tmp, X_OK) == 0) {
> - strncpy(buffer, tmp, BPFTOOL_PATH_MAX_LEN);
> + snprintf(buffer, BPFTOOL_PATH_MAX_LEN, "%s", tmp);
> return 0;
> }
>
^ permalink raw reply [flat|nested] 47+ messages in thread* Re: [PATCH bpf-next v1 14/14] selftests/bpf: Check BPFTOOL env var in detect_bpftool_path()
2026-02-12 1:13 ` [PATCH bpf-next v1 14/14] selftests/bpf: Check BPFTOOL env var in detect_bpftool_path() Ihor Solodrai
2026-02-12 15:03 ` Mykyta Yatsenko
@ 2026-02-13 10:36 ` Alexis Lothoré
1 sibling, 0 replies; 47+ messages in thread
From: Alexis Lothoré @ 2026-02-13 10:36 UTC (permalink / raw)
To: Ihor Solodrai, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann, Eduard Zingerman
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
Hi Ihor,
On Thu Feb 12, 2026 at 2:13 AM CET, Ihor Solodrai wrote:
> The bpftool_maps_access and bpftool_metadata tests may fail on BPF CI
> with "command not found", depending on a workflow.
> This happens because detect_bpftool_path() only checks two hardcoded
> relative paths:
> - ./tools/sbin/bpftool
> - ../tools/sbin/bpftool
>
> Add support for a BPFTOOL environment variable that allows specifying
> the exact path to the bpftool binary.
>
> Also replace strncpy() with snprintf() for proper null-termination.
>
> Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
LGTM, thanks for the improvement.
For the record, another issue that this path harcoding is aiming to
solve is that we definitely want a full bpftool binary (as those bpftool
helpers are used to find the binary under test), and not a _bootstrap_
version, which only exposes a few subcommands instead of the whole set.
So I'd say that it is not an issue yet, but it may be worth in the
future to enrich the checks in detect_bpftool_path to make sure that any
bpftool binary path provided by BPFTOOL env var is not pointing to a
bootstrap version.
Alexis
--
Alexis Lothoré, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN
2026-02-12 1:13 [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN Ihor Solodrai
` (13 preceding siblings ...)
2026-02-12 1:13 ` [PATCH bpf-next v1 14/14] selftests/bpf: Check BPFTOOL env var in detect_bpftool_path() Ihor Solodrai
@ 2026-02-12 22:00 ` Eduard Zingerman
2026-02-12 23:57 ` Ihor Solodrai
2026-02-12 23:26 ` Eduard Zingerman
15 siblings, 1 reply; 47+ messages in thread
From: Eduard Zingerman @ 2026-02-12 22:00 UTC (permalink / raw)
To: Ihor Solodrai, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
On Wed, 2026-02-11 at 17:13 -0800, Ihor Solodrai wrote:
> This series includes various fixes aiming to enable test_progs run
> with userspace address sanitizer on BPF CI.
>
> The first patch fixes the selftests/bpf/test_progs build with:
>
> SAN_CFLAGS="-fsanitize=address -fno-omit-frame-pointer"
>
> The subsequent patches fix bugs reported by the address sanitizer on
> attempt to run the tests.
>
> The series is a pre-requisite for enabling "test_progs with ASAN"
> workflow on BPF CI.
I did an experiment:
- applied the diff as at the bottom of the email;
- compiled with export SAN_CFLAGS="-fsanitize=address -fno-omit-frame-pointer"
(using gcc 15.2.1);
- double-checked that resulting executable depends on libasan;
- did a test run: ./test_progs -a verifier_and.
The error report looks as follows:
Caught signal #11!
Stack trace:
/lib64/libasan.so.8(+0x525e7) [0x7f6a506525e7]
./test_progs(crash_handler+0xb5) [0xd152c9]
/lib64/libc.so.6(+0x19c30) [0x7f6a50427c30]
/lib64/libasan.so.8(+0xdf4a) [0x7f6a5060df4a]
/lib64/libasan.so.8(+0xe5bba) [0x7f6a506e5bba]
./test_progs() [0xd19ccc]
./test_progs(main+0xcf6) [0xd1aa79]
/lib64/libc.so.6(+0x35f5) [0x7f6a504115f5]
/lib64/libc.so.6(__libc_start_main+0x88) [0x7f6a504116a8]
./test_progs(_start+0x25) [0x401935]
Am I doing something wrong, or does test_progs signal handler
interfere with ASAN reporting?
[...]
---
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index a0a594de9007..3820077e74e4 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -46,7 +46,7 @@ srctree := $(patsubst %/,%,$(dir $(srctree)))
endif
CFLAGS += -g $(OPT_FLAGS) -rdynamic -std=gnu11 \
- -Wall -Werror -fno-omit-frame-pointer \
+ -Wall -fno-omit-frame-pointer \
-Wno-unused-but-set-variable \
$(GENFLAGS) $(SAN_CFLAGS) $(LIBELF_CFLAGS) \
-I$(CURDIR) -I$(INCLUDE_DIR) -I$(GENDIR) -I$(LIBDIR) \
diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c
index 02a85dda30e6..8839e00167fa 100644
--- a/tools/testing/selftests/bpf/test_progs.c
+++ b/tools/testing/selftests/bpf/test_progs.c
@@ -1924,7 +1924,7 @@ static void free_test_states(void)
free_subtest_state(&test_state->subtest_states[j]);
free(test_state->subtest_states);
- free(test_state->log_buf);
+ free(test_state->log_buf + 10);
test_state->subtest_states = NULL;
test_state->log_buf = NULL;
^ permalink raw reply related [flat|nested] 47+ messages in thread* Re: [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN
2026-02-12 22:00 ` [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN Eduard Zingerman
@ 2026-02-12 23:57 ` Ihor Solodrai
2026-02-13 0:23 ` Eduard Zingerman
0 siblings, 1 reply; 47+ messages in thread
From: Ihor Solodrai @ 2026-02-12 23:57 UTC (permalink / raw)
To: Eduard Zingerman, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
On 2/12/26 2:00 PM, Eduard Zingerman wrote:
> On Wed, 2026-02-11 at 17:13 -0800, Ihor Solodrai wrote:
>> This series includes various fixes aiming to enable test_progs run
>> with userspace address sanitizer on BPF CI.
>>
>> The first patch fixes the selftests/bpf/test_progs build with:
>>
>> SAN_CFLAGS="-fsanitize=address -fno-omit-frame-pointer"
>>
>> The subsequent patches fix bugs reported by the address sanitizer on
>> attempt to run the tests.
>>
>> The series is a pre-requisite for enabling "test_progs with ASAN"
>> workflow on BPF CI.
>
> I did an experiment:
> - applied the diff as at the bottom of the email;
> - compiled with export SAN_CFLAGS="-fsanitize=address -fno-omit-frame-pointer"
> (using gcc 15.2.1);
> - double-checked that resulting executable depends on libasan;
> - did a test run: ./test_progs -a verifier_and.
>
> The error report looks as follows:
>
> Caught signal #11!
> Stack trace:
> /lib64/libasan.so.8(+0x525e7) [0x7f6a506525e7]
> ./test_progs(crash_handler+0xb5) [0xd152c9]
> /lib64/libc.so.6(+0x19c30) [0x7f6a50427c30]
> /lib64/libasan.so.8(+0xdf4a) [0x7f6a5060df4a]
> /lib64/libasan.so.8(+0xe5bba) [0x7f6a506e5bba]
> ./test_progs() [0xd19ccc]
> ./test_progs(main+0xcf6) [0xd1aa79]
> /lib64/libc.so.6(+0x35f5) [0x7f6a504115f5]
> /lib64/libc.so.6(__libc_start_main+0x88) [0x7f6a504116a8]
> ./test_progs(_start+0x25) [0x401935]
>
> Am I doing something wrong, or does test_progs signal handler
> interfere with ASAN reporting?
>
> [...]
>
> ---
>
> diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
> index a0a594de9007..3820077e74e4 100644
> --- a/tools/testing/selftests/bpf/Makefile
> +++ b/tools/testing/selftests/bpf/Makefile
> @@ -46,7 +46,7 @@ srctree := $(patsubst %/,%,$(dir $(srctree)))
> endif
>
> CFLAGS += -g $(OPT_FLAGS) -rdynamic -std=gnu11 \
> - -Wall -Werror -fno-omit-frame-pointer \
> + -Wall -fno-omit-frame-pointer \
I think you've cheated a little bit here, because with -Werror
free(test_state->log_buf + 10);
doesn't compile:
test_progs.c: In function ‘free_test_states’:
test_progs.c:1927:17: error: ‘free’ called on pointer ‘*test_state.log_buf’ with nonzero offset 10 [-Werror=free-nonheap-object]
1927 | free(test_state->log_buf + 10);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
make: *** [Makefile:767: /home/isolodrai/kernels/bpf-next/tools/testing/selftests/bpf/test_progs.o] Error 1
make: *** Waiting for unfinished jobs....
If it's removed, then I can reproduce the same stacktrace, which AFAIU
is an invalid dereference inside the ASAN itself.
I'm no expert here, but it appears ASAN only tracks exact pointers? Or
maybe the assumption is that dumb errors like this one are caught at
compile time, so no need to check for them at runtime?
It could also be a bug in ASAN or gcc. I don't want to assume that, but
after unexpected adventures with llvm-objcopy I wouldn't be surprised.
I think a conclusion here is that ASAN doesn't guarantee the absence
of segfaults at runtime. It just helps to catch certain bugs.
I tried to trigger use-after-free, but also get a segfault.
Apparently at that point log_buf is already NULL.
diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c
index 02a85dda30e6..5ff1d9fc5e4d 100644
--- a/tools/testing/selftests/bpf/test_progs.c
+++ b/tools/testing/selftests/bpf/test_progs.c
@@ -1924,7 +1924,10 @@ static void free_test_states(void)
free_subtest_state(&test_state->subtest_states[j]);
free(test_state->subtest_states);
+ printf("log_buf = %p\n", test_state->log_buf);
free(test_state->log_buf);
+ char c = test_state->log_buf[0];
+ printf("c: %c\n", c);
test_state->subtest_states = NULL;
test_state->log_buf = NULL;
}
#522/1 verifier_and/invalid and of negative number:OKtest_progs -v -a verifier_and
#522/2 verifier_and/invalid and of negative number @unpriv:OK
#522/3 verifier_and/invalid range check:OK
#522/4 verifier_and/invalid range check @unpriv:OK
#522/5 verifier_and/check known subreg with unknown reg:OK
#522/6 verifier_and/check known subreg with unknown reg @unpriv:OK
#522 verifier_and:OK
Summary: 1/6 PASSED, 0 SKIPPED, 0 FAILED
log_buf = (nil)
tester_init:PASS:tester_log_buf 0 nsec
process_subtest:PASS:obj_open_mem 0 nsec
process_subtest:PASS:specs_alloc 0 nsec
#522 verifier_and:FAIL
Caught signal #11!
Stack trace:
/lib64/libasan.so.8(+0x525e7) [0x7f311290e5e7]
./test_progs(crash_handler+0xb5) [0xd15af6]
/lib64/libc.so.6(+0x1a290) [0x7f311269f290]
./test_progs() [0xd1a595]
./test_progs(main+0xcf6) [0xd1b35d]
/lib64/libc.so.6(+0x35b5) [0x7f31126885b5]
/lib64/libc.so.6(__libc_start_main+0x88) [0x7f3112688668]
./test_progs(_start+0x25) [0x401865]
[ 246.835249] test_progs[232]: segfault at 0 ip 0000000000d1a595 sp 00007ffd8e64cc00 error 4 in test_progs[91a595,400000+a34000] likely on CPU 0 (core 0, socket 0)
[ 246.838738] Code: 48 81 c2 00 80 ff 7f 0f b6 12 84 d2 40 0f 95 c6 48 89 c7 83 e7 07 40 38 d7 0f 9d c2 21 f2 84 d2 74 08 48 89 c7 e8 1b 6a 6e ff <0f> b6 01 88 45 ef 0f be 45 ef 89 c6 bf c0 58 b2 01 b8 00 00 00 00
Segmentation fault ./test_progs -a verifier_and
> -Wno-unused-but-set-variable \
> $(GENFLAGS) $(SAN_CFLAGS) $(LIBELF_CFLAGS) \
> -I$(CURDIR) -I$(INCLUDE_DIR) -I$(GENDIR) -I$(LIBDIR) \
> diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c
> index 02a85dda30e6..8839e00167fa 100644
> --- a/tools/testing/selftests/bpf/test_progs.c
> +++ b/tools/testing/selftests/bpf/test_progs.c
> @@ -1924,7 +1924,7 @@ static void free_test_states(void)
> free_subtest_state(&test_state->subtest_states[j]);
>
> free(test_state->subtest_states);
> - free(test_state->log_buf);
> + free(test_state->log_buf + 10);
> test_state->subtest_states = NULL;
> test_state->log_buf = NULL;
^ permalink raw reply related [flat|nested] 47+ messages in thread* Re: [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN
2026-02-12 23:57 ` Ihor Solodrai
@ 2026-02-13 0:23 ` Eduard Zingerman
2026-02-13 16:13 ` Ihor Solodrai
0 siblings, 1 reply; 47+ messages in thread
From: Eduard Zingerman @ 2026-02-13 0:23 UTC (permalink / raw)
To: Ihor Solodrai, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
On Thu, 2026-02-12 at 15:57 -0800, Ihor Solodrai wrote:
[...]
> > CFLAGS += -g $(OPT_FLAGS) -rdynamic -std=gnu11 \
> > - -Wall -Werror -fno-omit-frame-pointer \
> > + -Wall -fno-omit-frame-pointer \
>
> I think you've cheated a little bit here, because with -Werror
It's just a model of a memory error, see below an example that does
not generate compiler warnings.
> If it's removed, then I can reproduce the same stacktrace, which AFAIU
> is an invalid dereference inside the ASAN itself.
See below, if I remove custom signal handler there is a regular ASAN
error message:
==156==ERROR: AddressSanitizer: SEGV on unknown address 0xfffffffffffffffa (pc 0x7fa03160df4a bp 0x7fa0317bc980 sp 0x7ffee7c85170 T0)
==156==The signal is caused by a WRITE memory access.
#0 0x7fa03160df4a in __asan::Allocator::Deallocate(void*, unsigned long, unsigned long, __sanitizer::BufferedStackTrace*, __asan::AllocType) (/lib64/libasan.so.8+0xdf4a) (BuildId: d3cb6206dff19da52969c009f4cd93611901c478)
#1 0x7fa0316e5bb9 in free.part.0 (/lib64/libasan.so.8+0xe5bb9) (BuildId: d3cb6206dff19da52969c009f4cd93611901c478)
#2 0x000000d19cd9 in free_test_states /home/eddy/work/bpf-next/tools/testing/selftests/bpf/test_progs.c:1930
#3 0x000000d1a897 in main /home/eddy/work/bpf-next/tools/testing/selftests/bpf/test_progs.c:2107
#4 0x7fa0313c45f4 in __libc_start_call_main (/lib64/libc.so.6+0x35f4) (BuildId: a1dda014206b55b07f58fe8db80121b752dc3d03)
#5 0x7fa0313c46a7 in __libc_start_main@@GLIBC_2.34 (/lib64/libc.so.6+0x36a7) (BuildId: a1dda014206b55b07f58fe8db80121b752dc3d03)
#6 0x000000401934 in _start (/home/eddy/work/bpf-next/tools/testing/selftests/bpf/test_progs+0x401934) (BuildId: 9190db005d475ee7a8e9294bb32cfbd520c330dc)
==156==Register values:
rax = 0x0000000000000002 rbx = 0x000000000000000a rcx = 0x0000000000000000 rdx = 0x0000000000000003
rdi = 0x000000000000000a rsi = 0x000000000000000a rbp = 0x00007fa0317bc980 rsp = 0x00007ffee7c85170
r8 = 0x00007ffee7c851d0 r9 = 0x0000000000000001 r10 = 0x0000000000000005 r11 = 0x0000000000401935
r12 = 0x00007ffee7c851d0 r13 = 0xfffffffffffffffa r14 = 0x0000000000000001 r15 = 0x0000000000000000
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/eddy/work/bpf-next/tools/testing/selftests/bpf/test_progs.c:1930 in free_test_states
So, there is indeed a conflict between test_progs signal handler and
ASAN default signal handler.
[...]
--- a/tools/testing/selftests/bpf/test_progs.c
+++ b/tools/testing/selftests/bpf/test_progs.c
@@ -1913,6 +1913,8 @@ static int worker_main(int sock)
return 0;
}
+void *ptr;
+
static void free_test_states(void)
{
int i, j;
@@ -1924,7 +1926,8 @@ static void free_test_states(void)
free_subtest_state(&test_state->subtest_states[j]);
free(test_state->subtest_states);
- free(test_state->log_buf);
+ ptr = test_state->log_buf + 10;
+ free(ptr);
test_state->subtest_states = NULL;
test_state->log_buf = NULL;
}
@@ -1944,13 +1947,15 @@ int main(int argc, char **argv)
.parser = parse_arg,
.doc = argp_program_doc,
};
- struct sigaction sigact = {
- .sa_handler = crash_handler,
- .sa_flags = SA_RESETHAND,
- };
+ /*
+ * struct sigaction sigact = {
+ * .sa_handler = crash_handler,
+ * .sa_flags = SA_RESETHAND,
+ * };
+ */
int err, i;
- sigaction(SIGSEGV, &sigact, NULL);
+ //sigaction(SIGSEGV, &sigact, NULL);
env.stdout_saved = stdout;
env.stderr_saved = stderr;
^ permalink raw reply [flat|nested] 47+ messages in thread* Re: [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN
2026-02-13 0:23 ` Eduard Zingerman
@ 2026-02-13 16:13 ` Ihor Solodrai
2026-02-13 18:06 ` Eduard Zingerman
0 siblings, 1 reply; 47+ messages in thread
From: Ihor Solodrai @ 2026-02-13 16:13 UTC (permalink / raw)
To: Eduard Zingerman, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
On 2/12/26 4:23 PM, Eduard Zingerman wrote:
> On Thu, 2026-02-12 at 15:57 -0800, Ihor Solodrai wrote:
>
> [...]
>
>>> CFLAGS += -g $(OPT_FLAGS) -rdynamic -std=gnu11 \
>>> - -Wall -Werror -fno-omit-frame-pointer \
>>> + -Wall -fno-omit-frame-pointer \
>>
>> I think you've cheated a little bit here, because with -Werror
>
> It's just a model of a memory error, see below an example that does
> not generate compiler warnings.
>
>> If it's removed, then I can reproduce the same stacktrace, which AFAIU
>> is an invalid dereference inside the ASAN itself.
>
> See below, if I remove custom signal handler there is a regular ASAN
> error message:
>
> ==156==ERROR: AddressSanitizer: SEGV on unknown address 0xfffffffffffffffa (pc 0x7fa03160df4a bp 0x7fa0317bc980 sp 0x7ffee7c85170 T0)
> ==156==The signal is caused by a WRITE memory access.
> #0 0x7fa03160df4a in __asan::Allocator::Deallocate(void*, unsigned long, unsigned long, __sanitizer::BufferedStackTrace*, __asan::AllocType) (/lib64/libasan.so.8+0xdf4a) (BuildId: d3cb6206dff19da52969c009f4cd93611901c478)
> #1 0x7fa0316e5bb9 in free.part.0 (/lib64/libasan.so.8+0xe5bb9) (BuildId: d3cb6206dff19da52969c009f4cd93611901c478)
> #2 0x000000d19cd9 in free_test_states /home/eddy/work/bpf-next/tools/testing/selftests/bpf/test_progs.c:1930
> #3 0x000000d1a897 in main /home/eddy/work/bpf-next/tools/testing/selftests/bpf/test_progs.c:2107
> #4 0x7fa0313c45f4 in __libc_start_call_main (/lib64/libc.so.6+0x35f4) (BuildId: a1dda014206b55b07f58fe8db80121b752dc3d03)
> #5 0x7fa0313c46a7 in __libc_start_main@@GLIBC_2.34 (/lib64/libc.so.6+0x36a7) (BuildId: a1dda014206b55b07f58fe8db80121b752dc3d03)
> #6 0x000000401934 in _start (/home/eddy/work/bpf-next/tools/testing/selftests/bpf/test_progs+0x401934) (BuildId: 9190db005d475ee7a8e9294bb32cfbd520c330dc)
>
> ==156==Register values:
> rax = 0x0000000000000002 rbx = 0x000000000000000a rcx = 0x0000000000000000 rdx = 0x0000000000000003
> rdi = 0x000000000000000a rsi = 0x000000000000000a rbp = 0x00007fa0317bc980 rsp = 0x00007ffee7c85170
> r8 = 0x00007ffee7c851d0 r9 = 0x0000000000000001 r10 = 0x0000000000000005 r11 = 0x0000000000401935
> r12 = 0x00007ffee7c851d0 r13 = 0xfffffffffffffffa r14 = 0x0000000000000001 r15 = 0x0000000000000000
> AddressSanitizer can not provide additional info.
> SUMMARY: AddressSanitizer: SEGV /home/eddy/work/bpf-next/tools/testing/selftests/bpf/test_progs.c:1930 in free_test_states
>
> So, there is indeed a conflict between test_progs signal handler and
> ASAN default signal handler.
As it turns out, only one signal handler can be installed at a time [1].
From man [2]:
The sigaction() system call is used to *change* the action taken by
a process on receipt of a specific signal.
So what happens is test_prog's custom signal handler *overwrites* ASAN's
signal handler leading to the weirdness we are seeing.
[1] https://stackoverflow.com/questions/17102919/is-it-valid-to-have-multiple-signal-handlers-for-same-signal
[2] https://man7.org/linux/man-pages/man2/sigaction.2.html
We should probably do then:
diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c
index 02a85dda30e6..77a36f6ca352 100644
--- a/tools/testing/selftests/bpf/test_progs.c
+++ b/tools/testing/selftests/bpf/test_progs.c
@@ -1672,14 +1672,15 @@ static void server_main(void)
{
pthread_t *dispatcher_threads;
struct dispatch_data *data;
+ int i;
+
+#ifndef __SANITIZE_ADDRESS__
struct sigaction sigact_int = {
.sa_handler = sigint_handler,
.sa_flags = SA_RESETHAND,
};
- int i;
-
sigaction(SIGINT, &sigact_int, NULL);
-
+#endif
dispatcher_threads = calloc(sizeof(pthread_t), env.workers);
data = calloc(sizeof(struct dispatch_data), env.workers);
>
> [...]
>
> --- a/tools/testing/selftests/bpf/test_progs.c
> +++ b/tools/testing/selftests/bpf/test_progs.c
> @@ -1913,6 +1913,8 @@ static int worker_main(int sock)
> return 0;
> }
>
> +void *ptr;
> +
> static void free_test_states(void)
> {
> int i, j;
> @@ -1924,7 +1926,8 @@ static void free_test_states(void)
> free_subtest_state(&test_state->subtest_states[j]);
>
> free(test_state->subtest_states);
> - free(test_state->log_buf);
> + ptr = test_state->log_buf + 10;
> + free(ptr);
> test_state->subtest_states = NULL;
> test_state->log_buf = NULL;
> }
> @@ -1944,13 +1947,15 @@ int main(int argc, char **argv)
> .parser = parse_arg,
> .doc = argp_program_doc,
> };
> - struct sigaction sigact = {
> - .sa_handler = crash_handler,
> - .sa_flags = SA_RESETHAND,
> - };
> + /*
> + * struct sigaction sigact = {
> + * .sa_handler = crash_handler,
> + * .sa_flags = SA_RESETHAND,
> + * };
> + */
> int err, i;
>
> - sigaction(SIGSEGV, &sigact, NULL);
> + //sigaction(SIGSEGV, &sigact, NULL);
>
> env.stdout_saved = stdout;
> env.stderr_saved = stderr;
^ permalink raw reply related [flat|nested] 47+ messages in thread* Re: [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN
2026-02-13 16:13 ` Ihor Solodrai
@ 2026-02-13 18:06 ` Eduard Zingerman
0 siblings, 0 replies; 47+ messages in thread
From: Eduard Zingerman @ 2026-02-13 18:06 UTC (permalink / raw)
To: Ihor Solodrai, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
On Fri, 2026-02-13 at 08:13 -0800, Ihor Solodrai wrote:
[...]
> So what happens is test_prog's custom signal handler *overwrites* ASAN's
> signal handler leading to the weirdness we are seeing.
That's what I meant by conflict.
>
> [1] https://stackoverflow.com/questions/17102919/is-it-valid-to-have-multiple-signal-handlers-for-same-signal
> [2] https://man7.org/linux/man-pages/man2/sigaction.2.html
>
> We should probably do then:
>
> diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c
> index 02a85dda30e6..77a36f6ca352 100644
> --- a/tools/testing/selftests/bpf/test_progs.c
> +++ b/tools/testing/selftests/bpf/test_progs.c
> @@ -1672,14 +1672,15 @@ static void server_main(void)
> {
> pthread_t *dispatcher_threads;
> struct dispatch_data *data;
> + int i;
> +
> +#ifndef __SANITIZE_ADDRESS__
> struct sigaction sigact_int = {
> .sa_handler = sigint_handler,
> .sa_flags = SA_RESETHAND,
> };
> - int i;
> -
> sigaction(SIGINT, &sigact_int, NULL);
> -
> +#endif
> dispatcher_threads = calloc(sizeof(pthread_t), env.workers);
> data = calloc(sizeof(struct dispatch_data), env.workers);
ASAN's stack trace looks nicer compared to what libunwind generates.
On the other hand, test_progs.c:carsh_handler() prints pending test log.
There is an option to remember old handler returned by sigaction and
call it from the crash_handler (thus invoking ASAN's handler),
but the complication is probably not worth it.
I think this part is good as it is, sorry for the noise.
[...]
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN
2026-02-12 1:13 [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN Ihor Solodrai
` (14 preceding siblings ...)
2026-02-12 22:00 ` [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN Eduard Zingerman
@ 2026-02-12 23:26 ` Eduard Zingerman
2026-02-13 17:56 ` Ihor Solodrai
15 siblings, 1 reply; 47+ messages in thread
From: Eduard Zingerman @ 2026-02-12 23:26 UTC (permalink / raw)
To: Ihor Solodrai, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
On Wed, 2026-02-11 at 17:13 -0800, Ihor Solodrai wrote:
> This series includes various fixes aiming to enable test_progs run
> with userspace address sanitizer on BPF CI.
>
> The first patch fixes the selftests/bpf/test_progs build with:
>
> SAN_CFLAGS="-fsanitize=address -fno-omit-frame-pointer"
>
> The subsequent patches fix bugs reported by the address sanitizer on
> attempt to run the tests.
>
> The series is a pre-requisite for enabling "test_progs with ASAN"
> workflow on BPF CI.
Also, do we want to have ASAN enabled by default?
If it would be enabled for CI, people will need to deal with local
configuration anyway. It might make sense to put the default flags in
to save everyone the trouble of figuring out which flags CI uses.
Wdyt?
[...]
^ permalink raw reply [flat|nested] 47+ messages in thread* Re: [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN
2026-02-12 23:26 ` Eduard Zingerman
@ 2026-02-13 17:56 ` Ihor Solodrai
2026-02-13 18:09 ` Eduard Zingerman
0 siblings, 1 reply; 47+ messages in thread
From: Ihor Solodrai @ 2026-02-13 17:56 UTC (permalink / raw)
To: Eduard Zingerman, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
On 2/12/26 3:26 PM, Eduard Zingerman wrote:
> On Wed, 2026-02-11 at 17:13 -0800, Ihor Solodrai wrote:
>> This series includes various fixes aiming to enable test_progs run
>> with userspace address sanitizer on BPF CI.
>>
>> The first patch fixes the selftests/bpf/test_progs build with:
>>
>> SAN_CFLAGS="-fsanitize=address -fno-omit-frame-pointer"
>>
>> The subsequent patches fix bugs reported by the address sanitizer on
>> attempt to run the tests.
>>
>> The series is a pre-requisite for enabling "test_progs with ASAN"
>> workflow on BPF CI.
>
> Also, do we want to have ASAN enabled by default?
I don't think so. At least not right away.
> If it would be enabled for CI, people will need to deal with local
> configuration anyway. It might make sense to put the default flags in
> to save everyone the trouble of figuring out which flags CI uses.
> Wdyt?
WIP CI changes add an *additional* test job, that builds only
test_progs default flavor with ASAN and runs it. Previous test jobs,
built with -static, are still there as usual.
There are tests that don't play well with ASAN such as BPF arena
tests, and some tests may be much slower when ASAN is enabled.
We still want to run them on CI.
I don't see why we should pick between asan everywhere or
nowhere. At the very least, CI should make sure selftests can build
successfully without the asan flags.
Additional job will catch most of bugs of the sort covered in this
series, and that is good enough I think.
>
> [...]
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN
2026-02-13 17:56 ` Ihor Solodrai
@ 2026-02-13 18:09 ` Eduard Zingerman
2026-02-13 18:29 ` Ihor Solodrai
0 siblings, 1 reply; 47+ messages in thread
From: Eduard Zingerman @ 2026-02-13 18:09 UTC (permalink / raw)
To: Ihor Solodrai, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
On Fri, 2026-02-13 at 09:56 -0800, Ihor Solodrai wrote:
> On 2/12/26 3:26 PM, Eduard Zingerman wrote:
> > On Wed, 2026-02-11 at 17:13 -0800, Ihor Solodrai wrote:
> > > This series includes various fixes aiming to enable test_progs run
> > > with userspace address sanitizer on BPF CI.
> > >
> > > The first patch fixes the selftests/bpf/test_progs build with:
> > >
> > > SAN_CFLAGS="-fsanitize=address -fno-omit-frame-pointer"
> > >
> > > The subsequent patches fix bugs reported by the address sanitizer on
> > > attempt to run the tests.
> > >
> > > The series is a pre-requisite for enabling "test_progs with ASAN"
> > > workflow on BPF CI.
> >
> > Also, do we want to have ASAN enabled by default?
>
> I don't think so. At least not right away.
>
> > If it would be enabled for CI, people will need to deal with local
> > configuration anyway. It might make sense to put the default flags in
> > to save everyone the trouble of figuring out which flags CI uses.
> > Wdyt?
>
> WIP CI changes add an *additional* test job, that builds only
> test_progs default flavor with ASAN and runs it. Previous test jobs,
> built with -static, are still there as usual.
>
> There are tests that don't play well with ASAN such as BPF arena
> tests, and some tests may be much slower when ASAN is enabled.
> We still want to run them on CI.
Fair enough.
> I don't see why we should pick between asan everywhere or
> nowhere. At the very least, CI should make sure selftests can build
> successfully without the asan flags.
>
> Additional job will catch most of bugs of the sort covered in this
> series, and that is good enough I think.
My main concern is that when this fails on CI I will have to dig
through CI config to recover exact SAN_CFLAGS used. If not enabled by
default I'd still like to have a single knob like 'ASAN=t'.
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN
2026-02-13 18:09 ` Eduard Zingerman
@ 2026-02-13 18:29 ` Ihor Solodrai
2026-02-13 18:35 ` Eduard Zingerman
0 siblings, 1 reply; 47+ messages in thread
From: Ihor Solodrai @ 2026-02-13 18:29 UTC (permalink / raw)
To: Eduard Zingerman, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
On 2/13/26 10:09 AM, Eduard Zingerman wrote:
> On Fri, 2026-02-13 at 09:56 -0800, Ihor Solodrai wrote:
>> On 2/12/26 3:26 PM, Eduard Zingerman wrote:
>>> On Wed, 2026-02-11 at 17:13 -0800, Ihor Solodrai wrote:
>>>> This series includes various fixes aiming to enable test_progs run
>>>> with userspace address sanitizer on BPF CI.
>>>>
>>>> The first patch fixes the selftests/bpf/test_progs build with:
>>>>
>>>> SAN_CFLAGS="-fsanitize=address -fno-omit-frame-pointer"
>>>>
>>>> The subsequent patches fix bugs reported by the address sanitizer on
>>>> attempt to run the tests.
>>>>
>>>> The series is a pre-requisite for enabling "test_progs with ASAN"
>>>> workflow on BPF CI.
>>>
>>> Also, do we want to have ASAN enabled by default?
>>
>> I don't think so. At least not right away.
>>
>>> If it would be enabled for CI, people will need to deal with local
>>> configuration anyway. It might make sense to put the default flags in
>>> to save everyone the trouble of figuring out which flags CI uses.
>>> Wdyt?
>>
>> WIP CI changes add an *additional* test job, that builds only
>> test_progs default flavor with ASAN and runs it. Previous test jobs,
>> built with -static, are still there as usual.
>>
>> There are tests that don't play well with ASAN such as BPF arena
>> tests, and some tests may be much slower when ASAN is enabled.
>> We still want to run them on CI.
>
> Fair enough.
>
>> I don't see why we should pick between asan everywhere or
>> nowhere. At the very least, CI should make sure selftests can build
>> successfully without the asan flags.
>>
>> Additional job will catch most of bugs of the sort covered in this
>> series, and that is good enough I think.
>
> My main concern is that when this fails on CI I will have to dig
> through CI config to recover exact SAN_CFLAGS used. If not enabled by
> default I'd still like to have a single knob like 'ASAN=t'.
I kinda have a switch like that [1]:
if [[ -n "${SELFTESTS_BPF_ASAN:-}" ]]; then
SELF_OPTS+=(SAN_CFLAGS="-fsanitize=address -fno-omit-frame-pointer")
[...]
Any ideas how to make this obvious in CI logs?
I could set -x in the script executing the make, but it may be noisy still.
[1] https://github.com/libbpf/ci/blob/selftests-asan/build-selftests/build_selftests.sh#L50-L51
^ permalink raw reply [flat|nested] 47+ messages in thread* Re: [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN
2026-02-13 18:29 ` Ihor Solodrai
@ 2026-02-13 18:35 ` Eduard Zingerman
0 siblings, 0 replies; 47+ messages in thread
From: Eduard Zingerman @ 2026-02-13 18:35 UTC (permalink / raw)
To: Ihor Solodrai, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann
Cc: Amery Hung, Mykyta Yatsenko, Alexis Lothoré, bpf,
linux-kernel, kernel-team
On Fri, 2026-02-13 at 10:29 -0800, Ihor Solodrai wrote:
[...]
> I kinda have a switch like that [1]:
>
> if [[ -n "${SELFTESTS_BPF_ASAN:-}" ]]; then
> SELF_OPTS+=(SAN_CFLAGS="-fsanitize=address -fno-omit-frame-pointer")
> [...]
>
> Any ideas how to make this obvious in CI logs?
> I could set -x in the script executing the make, but it may be noisy still.
>
> [1] https://github.com/libbpf/ci/blob/selftests-asan/build-selftests/build_selftests.sh#L50-L51
I'd just add one more knob to the selftests makefile, e.g.:
ifdef ASAN
SAN_CFLAGS:="-fsanitize=address -fno-omit-frame-pointer"
endif
And use it from CI as well.
^ permalink raw reply [flat|nested] 47+ messages in thread