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;
+};
+

[...]


Reply via email to