diff options
| author | Alexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin.com> | 2026-09-03 15:51:37 +0200 |
|---|---|---|
| committer | Alexei Starovoitov <ast@kernel.org> | 2026-09-04 09:54:19 -0700 |
| commit | 2cbbb035977a79b78952404d3e2c3c6dfe318259 (patch) | |
| tree | aa6c44661508e0f64e89fbc3ddc913330f3fb60f /tools/testing/selftests/bpf/test_kmods | |
| parent | 9123a4d4c4f3321efbb40569b81985d9654abe25 (diff) | |
| download | linux-next-2cbbb035977a79b78952404d3e2c3c6dfe318259.tar.gz linux-next-2cbbb035977a79b78952404d3e2c3c6dfe318259.zip | |
selftests/bpf: add tests to validate KASAN on JIT programs
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. To allow each test to trigger the expected
report, the kernel must run with the kasan_multi_shot configuration.
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:
- specific atomic ops
- test for instructions involving different verifier states, with some
states flagging memory as stack, and other states as non-stack memory
- tests that validate the stack marking shifting when a patch is emitted
by the verifier (zext/rnd_hi32, constant blindind).
Most of those tests are able to trigger kasan reports by altering the
shadow memory (triggering faulty accesses is otherwise complex, because
of the verifier). A few tests trigger actual faulty accesses (eg
out-of-bound accesses)
A few of those tests depends on cpuv4 (load_acquire/store_release, st,
st_blinded), and so are executed only with test_progs-cpuv4
# ./test_progs -a kasan
#175/1 kasan/st_1_not_on_stack:SKIP
#175/2 kasan/st_1_on_stack:SKIP
#175/3 kasan/st_2_not_on_stack:SKIP
#175/4 kasan/st_2_on_stack:SKIP
#175/5 kasan/st_4_not_on_stack:SKIP
#175/6 kasan/st_4_on_stack:SKIP
#175/7 kasan/st_8_not_on_stack:SKIP
#175/8 kasan/st_8_on_stack:SKIP
#175/9 kasan/stx_1_not_on_stack:OK
#175/10 kasan/stx_1_on_stack:OK
#175/11 kasan/stx_2_not_on_stack:OK
#175/12 kasan/stx_2_on_stack:OK
#175/13 kasan/stx_4_not_on_stack:OK
#175/14 kasan/stx_4_on_stack:OK
#175/15 kasan/stx_8_not_on_stack:OK
#175/16 kasan/stx_8_on_stack:OK
#175/17 kasan/ldx_1_not_on_stack:OK
#175/18 kasan/ldx_1_on_stack:OK
#175/19 kasan/ldx_2_not_on_stack:OK
#175/20 kasan/ldx_2_on_stack:OK
#175/21 kasan/ldx_4_not_on_stack:OK
#175/22 kasan/ldx_4_on_stack:OK
#175/23 kasan/ldx_8_not_on_stack:OK
#175/24 kasan/ldx_8_on_stack:OK
#175/25 kasan/simple_atomic_4_not_on_stack:OK
#175/26 kasan/simple_atomic_4_on_stack:OK
#175/27 kasan/simple_atomic_8_not_on_stack:OK
#175/28 kasan/simple_atomic_8_on_stack:OK
#175/29 kasan/simple_atomic_fetch_not_on_stack:OK
#175/30 kasan/simple_atomic_fetch_on_stack:OK
#175/31 kasan/load_acquire_1_not_on_stack:SKIP
#175/32 kasan/load_acquire_1_on_stack:SKIP
#175/33 kasan/load_acquire_2_not_on_stack:SKIP
#175/34 kasan/load_acquire_2_on_stack:SKIP
#175/35 kasan/load_acquire_4_not_on_stack:SKIP
#175/36 kasan/load_acquire_4_on_stack:SKIP
#175/37 kasan/load_acquire_8_not_on_stack:SKIP
#175/38 kasan/load_acquire_8_on_stack:SKIP
#175/39 kasan/store_release_1_not_on_stack:SKIP
#175/40 kasan/store_release_1_on_stack:SKIP
#175/41 kasan/store_release_2_not_on_stack:SKIP
#175/42 kasan/store_release_2_on_stack:SKIP
#175/43 kasan/store_release_4_not_on_stack:SKIP
#175/44 kasan/store_release_4_on_stack:SKIP
#175/45 kasan/store_release_8_not_on_stack:SKIP
#175/46 kasan/store_release_8_on_stack:SKIP
#175/47 kasan/ldx_patched_not_on_stack:OK
#175/48 kasan/ldx_patched_on_stack:OK
#175/49 kasan/verifier_paths_stack_and_non_stack:OK
#175/50 kasan/ldx_oob_1_not_on_stack:OK
#175/51 kasan/ldx_oob_2_not_on_stack:OK
#175/52 kasan/ldx_oob_4_not_on_stack:OK
#175/53 kasan/ldx_oob_8_not_on_stack:OK
#175/54 kasan/ldx_self_alias_on_stack:OK
#175/55 kasan/st_blinded:SKIP
#175 kasan:OK (SKIP: 25/55)
Summary: 1/30 PASSED, 25 SKIPPED, 0/0 FAILED
Signed-off-by: Alexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin.com>
Link: https://lore.kernel.org/r/20260903-kasan-v9-8-2407fe99255a@bootlin.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'tools/testing/selftests/bpf/test_kmods')
| -rw-r--r-- | tools/testing/selftests/bpf/test_kmods/bpf_testmod.c | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c index 2380b6cbdead..f798bbbb4d13 100644 --- a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c +++ b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c @@ -75,6 +75,16 @@ union bpf_testmod_union_arg_2 { struct bpf_testmod_struct_arg_2 arg; }; +struct bpf_testmod_oob { + __u8 data; + union { + __u8 redzone_1; + __u16 redzone_2; + __u32 redzone_4; + __u64 redzone_8; + }; +}; + __bpf_hook_start(); noinline int @@ -336,6 +346,47 @@ __bpf_kfunc void bpf_kfunc_put_default_trusted_ptr_test(struct prog_test_member */ } +#ifdef CONFIG_BPF_JIT_KASAN + +extern void kasan_poison(const void *addr, size_t size, u8 value, bool init); + +#define KASAN_SLAB_FREE 0xFB + +__bpf_kfunc void bpf_kfunc_kasan_poison(void *mem, u32 mem__sz) +{ + kasan_poison(mem, mem__sz, KASAN_SLAB_FREE, false); +} + +__bpf_kfunc void bpf_kfunc_kasan_unpoison(void *mem, u32 mem__sz) +{ + kasan_poison(mem, mem__sz, 0x00, false); +} +#else +__bpf_kfunc void bpf_kfunc_kasan_poison(void *mem, u32 mem__sz) { } +__bpf_kfunc void bpf_kfunc_kasan_unpoison(void *mem, u32 mem__sz) { } +#endif + +__bpf_kfunc struct bpf_testmod_oob *bpf_testmod_oob_alloc(void) +{ + struct bpf_testmod_oob *p; + + /* + * Only allocate size of data (and so, voluntarily use kmalloc + * instead of kmalloc_obj), not the rest of the structure, so + * that programs under test trying to access the rest of the + * structure trigger OoB accesses + */ + p = kmalloc(sizeof(p->data), GFP_ATOMIC); + if (!p) + return NULL; + return p; +} + +__bpf_kfunc void bpf_testmod_oob_free(struct bpf_testmod_oob *oob) +{ + kfree(oob); +} + __bpf_kfunc struct bpf_testmod_ctx * bpf_testmod_ctx_create(int *err) { @@ -869,6 +920,10 @@ BTF_ID_FLAGS(func, bpf_testmod_ops3_call_test_arena_stack) BTF_ID_FLAGS(func, bpf_testmod_ops3_call_test_arena_multislot) BTF_ID_FLAGS(func, bpf_kfunc_get_default_trusted_ptr_test); BTF_ID_FLAGS(func, bpf_kfunc_put_default_trusted_ptr_test); +BTF_ID_FLAGS(func, bpf_kfunc_kasan_poison) +BTF_ID_FLAGS(func, bpf_kfunc_kasan_unpoison) +BTF_ID_FLAGS(func, bpf_testmod_oob_alloc, KF_ACQUIRE | KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_testmod_oob_free, KF_RELEASE) BTF_KFUNCS_END(bpf_testmod_common_kfunc_ids) BTF_ID_LIST(bpf_testmod_dtor_ids) |
