On 6/4/26 1:22 PM, Alexis Lothoré (eBPF Foundation) wrote:
Add a basic KASAN test runner that loads and test-run programs that can
trigger memory management bugs. The test captures kernel logs and ensure
that the expected KASAN splat is emitted by searching for the
corresponding first lines in the report, hence validated that the needed
instrumentation has been inserted by the JIT compiler before the
relevant memory accesses.
The runner covers different cases and settings: in the nominal case, it
validates kasan reports on basic instructions (on all supported accesses
sizes) but also when report _should not_ be emitted (eg: for accesses on
program stack). The runner also comes with a few specialized tests that
are then not executed for all sizes/locations. A few of those tests
depends on cpuv4 (load_acquire and store_release).
# ./test_progs -a kasan
#164/1 kasan/st_1_not_on_stack:OK
#164/2 kasan/st_1_on_stack:OK
#164/3 kasan/st_2_not_on_stack:OK
#164/4 kasan/st_2_on_stack:OK
#164/5 kasan/st_4_not_on_stack:OK
#164/6 kasan/st_4_on_stack:OK
#164/7 kasan/st_8_not_on_stack:OK
#164/8 kasan/st_8_on_stack:OK
#164/9 kasan/stx_1_not_on_stack:OK
#164/10 kasan/stx_1_on_stack:OK
#164/11 kasan/stx_2_not_on_stack:OK
#164/12 kasan/stx_2_on_stack:OK
#164/13 kasan/stx_4_not_on_stack:OK
#164/14 kasan/stx_4_on_stack:OK
#164/15 kasan/stx_8_not_on_stack:OK
#164/16 kasan/stx_8_on_stack:OK
#164/17 kasan/ldx_1_not_on_stack:OK
#164/18 kasan/ldx_1_on_stack:OK
#164/19 kasan/ldx_2_not_on_stack:OK
#164/20 kasan/ldx_2_on_stack:OK
#164/21 kasan/ldx_4_not_on_stack:OK
#164/22 kasan/ldx_4_on_stack:OK
#164/23 kasan/ldx_8_not_on_stack:OK
#164/24 kasan/ldx_8_on_stack:OK
#164/25 kasan/simple_atomic_4_not_on_stack:OK
#164/26 kasan/simple_atomic_4_on_stack:OK
#164/27 kasan/simple_atomic_8_not_on_stack:OK
#164/28 kasan/simple_atomic_8_on_stack:OK
#164/29 kasan/load_acquire_1_not_on_stack:SKIP
#164/30 kasan/load_acquire_1_on_stack:SKIP
#164/31 kasan/load_acquire_2_not_on_stack:SKIP
#164/32 kasan/load_acquire_2_on_stack:SKIP
#164/33 kasan/load_acquire_4_not_on_stack:SKIP
#164/34 kasan/load_acquire_4_on_stack:SKIP
#164/35 kasan/load_acquire_8_not_on_stack:SKIP
#164/36 kasan/load_acquire_8_on_stack:SKIP
#164/37 kasan/store_release_1_not_on_stack:SKIP
#164/38 kasan/store_release_1_on_stack:SKIP
#164/39 kasan/store_release_2_not_on_stack:SKIP
#164/40 kasan/store_release_2_on_stack:SKIP
#164/41 kasan/store_release_4_not_on_stack:SKIP
#164/42 kasan/store_release_4_on_stack:SKIP
#164/43 kasan/store_release_8_not_on_stack:SKIP
#164/44 kasan/store_release_8_on_stack:SKIP
#164/45 kasan/ldx_patched:OK
#164/46 kasan/stack_and_non_stack:OK
#164 kasan:OK (SKIP: 16/46)
Summary: 1/30 PASSED, 16 SKIPPED, 0 FAILED
On my qemu run, I got a bunch of failures like below:
[root@arch-fb-vm1 bpf]# ./test_progs -n 164
test_kasan:PASS:alloc test ctx 0 nsec
gzopen /boot/config-7.1.0-rc5-gec86c8156bd6: No such file or directory
test_kasan:PASS:open prog 0 nsec
test_kasan:PASS:find rnd_hi32 prog 0 nsec
...
All error logs:
test_kasan:PASS:alloc test ctx 0 nsec
gzopen /boot/config-7.1.0-rc5-gec86c8156bd6: No such file or directory
test_kasan:PASS:open prog 0 nsec
test_kasan:PASS:find rnd_hi32 prog 0 nsec
test_kasan:PASS:load prog 0 nsec
test_kasan:PASS:open kernel logs 0 nsec
test_kasan:PASS:get map 0 nsec
test_kasan:PASS:set map 0 nsec
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected
error: 1 (errno 11)
#164/1 kasan/st_1_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected
error: 1 (errno 11)
#164/3 kasan/st_2_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected
error: 1 (errno 11)
#164/5 kasan/st_4_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected
error: 1 (errno 11)
#164/7 kasan/st_8_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected
error: 1 (errno 11)
#164/9 kasan/stx_1_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected
error: 1 (errno 11)
#164/11 kasan/stx_2_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected
error: 1 (errno 11)
#164/13 kasan/stx_4_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected
error: 1 (errno 11)
#164/15 kasan/stx_8_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected
error: 1 (errno 11)
#164/17 kasan/ldx_1_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected
error: 1 (errno 11)
#164/19 kasan/ldx_2_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected
error: 1 (errno 11)
#164/21 kasan/ldx_4_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected
error: 1 (errno 11)
#164/23 kasan/ldx_8_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected
error: 1 (errno 11)
#164/25 kasan/simple_atomic_4_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected
error: 1 (errno 11)
#164/27 kasan/simple_atomic_8_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected
error: 1 (errno 11)
#164/45 kasan/ldx_patched:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected
error: 1 (errno 11)
#164/46 kasan/stack_and_non_stack:FAIL
#164 kasan:FAIL
I checked the subtest 164/1,
For
ret = check_kasan_report_in_kernel_logs(klog_buffer, ctx,
test->is_write, access_size);
if (on_stack || test->expect_no_report)
ASSERT_NEQ(ret, 0, "no report should be generated");
else
ASSERT_OK(ret, "report should be generated");
the ret is equal to 1 as klog_buffer is empty. This caused the failure.
Signed-off-by: Alexis Lothoré (eBPF Foundation) <[email protected]>
---
Changes in v2:
- simplify tests by just manually poisoning test areas with a dedicated
kfunc
- introduce one prog per covered instruction family
- make sure that tests do not consume kernel logs (use /dev/kmgs rather
than klogctl)
- add tests for stack accesses:
- marking correctly set when there are diverging verifier states
leading to different memory types
- marking kept in sync with prog when it is patched
---
tools/testing/selftests/bpf/prog_tests/kasan.c | 356 +++++++++++++++++++
tools/testing/selftests/bpf/progs/kasan.c | 382 +++++++++++++++++++++
.../testing/selftests/bpf/test_kmods/bpf_testmod.c | 22 ++
3 files changed, 760 insertions(+)
diff --git a/tools/testing/selftests/bpf/prog_tests/kasan.c
b/tools/testing/selftests/bpf/prog_tests/kasan.c
new file mode 100644
index 000000000000..adf61e230ec9
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/kasan.c
@@ -0,0 +1,356 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+#include <bpf/bpf.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/if_ether.h>
+#include <unistd.h>
+#include <test_progs.h>
+#include <unpriv_helpers.h>
+#include "kasan.skel.h"
+
+#define SUBTEST_NAME_MAX_LEN 128
+#define PROG_NAME_MAX_LEN 128
+
+#define MAX_LOG_SIZE (8 * 1024)
+#define READ_CHUNK_SIZE 256
+
+#define KASAN_PATTERN_SLAB_UAF "BUG: KASAN: slab-use-after-free " \
+ "in bpf_prog_%02x%02x%02x%02x%02x%02x%02x%02x_%s"
+#define KASAN_PATTERN_REPORT "%s of size %d at addr"
+
+static char klog_buffer[MAX_LOG_SIZE];
+
+struct test_spec {
+ char *prog_type;
+ bool is_write;
+ bool only_32_or_64;
+ bool needs_load_acq_store_rel;
+ bool skip_multi_size_testing;
+ bool skip_on_stack_testing;
+ int run_size;
+ bool expect_no_report;
expect_no_report is not set in the code. The only usage is in
if (on_stack || test->expect_no_report)
ASSERT_NEQ(ret, 0, "no report should be generated");
else
ASSERT_OK(ret, "report should be generated");
+ bool rnd_hi32;
+};
+
+struct kasan_write_val {
+ __u8 data_1;
+ __u16 data_2;
+ __u32 data_4;
+ __u64 data_8;
+};
+
[...]