summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/bpf/test_kmods
diff options
context:
space:
mode:
authorAlexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin.com>2026-09-03 15:51:37 +0200
committerAlexei Starovoitov <ast@kernel.org>2026-09-04 09:54:19 -0700
commit2cbbb035977a79b78952404d3e2c3c6dfe318259 (patch)
treeaa6c44661508e0f64e89fbc3ddc913330f3fb60f /tools/testing/selftests/bpf/test_kmods
parent9123a4d4c4f3321efbb40569b81985d9654abe25 (diff)
downloadlinux-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.c55
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)