Re: [PATCH bpf-next v1 00/14] selftests/bpf: Fixes for userspace ASAN

From: Ihor Solodrai

Date: Thu Feb 12 2026 - 18:58:03 EST


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;