]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
selftests/bpf: Add UAF tests for arena atomics
authorIlya Leoshkevich <iii@linux.ibm.com>
Mon, 1 Jul 2024 23:40:29 +0000 (01:40 +0200)
committerDaniel Borkmann <daniel@iogearbox.net>
Tue, 2 Jul 2024 16:31:52 +0000 (18:31 +0200)
Check that __sync_*() functions don't cause kernel panics when handling
freed arena pages.

x86_64 does not support some arena atomics yet, and aarch64 may or may
not support them, based on the availability of LSE atomics at run time.
Do not enable this test for these architectures for simplicity.

Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/20240701234304.14336-12-iii@linux.ibm.com
tools/testing/selftests/bpf/prog_tests/arena_atomics.c
tools/testing/selftests/bpf/progs/arena_atomics.c

index 0807a48a58eec5788dc0dcf102978d2b574fa486..26e7c06c6cb4d0aaabb5e16a6dd670a0b88d332a 100644 (file)
@@ -146,6 +146,22 @@ static void test_xchg(struct arena_atomics *skel)
        ASSERT_EQ(skel->arena->xchg32_result, 1, "xchg32_result");
 }
 
+static void test_uaf(struct arena_atomics *skel)
+{
+       LIBBPF_OPTS(bpf_test_run_opts, topts);
+       int err, prog_fd;
+
+       /* No need to attach it, just run it directly */
+       prog_fd = bpf_program__fd(skel->progs.uaf);
+       err = bpf_prog_test_run_opts(prog_fd, &topts);
+       if (!ASSERT_OK(err, "test_run_opts err"))
+               return;
+       if (!ASSERT_OK(topts.retval, "test_run_opts retval"))
+               return;
+
+       ASSERT_EQ(skel->arena->uaf_recovery_fails, 0, "uaf_recovery_fails");
+}
+
 void test_arena_atomics(void)
 {
        struct arena_atomics *skel;
@@ -180,6 +196,8 @@ void test_arena_atomics(void)
                test_cmpxchg(skel);
        if (test__start_subtest("xchg"))
                test_xchg(skel);
+       if (test__start_subtest("uaf"))
+               test_uaf(skel);
 
 cleanup:
        arena_atomics__destroy(skel);
index 77a4dfa9cdf9d15856c6c740644f91600512a994..bb0acd79d28a7185917a8bfdf7ff5c582c6211c0 100644 (file)
@@ -169,3 +169,79 @@ int xchg(const void *ctx)
 
        return 0;
 }
+
+__u64 __arena_global uaf_sink;
+volatile __u64 __arena_global uaf_recovery_fails;
+
+SEC("syscall")
+int uaf(const void *ctx)
+{
+       if (pid != (bpf_get_current_pid_tgid() >> 32))
+               return 0;
+#if defined(ENABLE_ATOMICS_TESTS) && !defined(__TARGET_ARCH_arm64) && \
+    !defined(__TARGET_ARCH_x86)
+       __u32 __arena *page32;
+       __u64 __arena *page64;
+       void __arena *page;
+
+       page = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
+       bpf_arena_free_pages(&arena, page, 1);
+       uaf_recovery_fails = 24;
+
+       page32 = (__u32 __arena *)page;
+       uaf_sink += __sync_fetch_and_add(page32, 1);
+       uaf_recovery_fails -= 1;
+       __sync_add_and_fetch(page32, 1);
+       uaf_recovery_fails -= 1;
+       uaf_sink += __sync_fetch_and_sub(page32, 1);
+       uaf_recovery_fails -= 1;
+       __sync_sub_and_fetch(page32, 1);
+       uaf_recovery_fails -= 1;
+       uaf_sink += __sync_fetch_and_and(page32, 1);
+       uaf_recovery_fails -= 1;
+       __sync_and_and_fetch(page32, 1);
+       uaf_recovery_fails -= 1;
+       uaf_sink += __sync_fetch_and_or(page32, 1);
+       uaf_recovery_fails -= 1;
+       __sync_or_and_fetch(page32, 1);
+       uaf_recovery_fails -= 1;
+       uaf_sink += __sync_fetch_and_xor(page32, 1);
+       uaf_recovery_fails -= 1;
+       __sync_xor_and_fetch(page32, 1);
+       uaf_recovery_fails -= 1;
+       uaf_sink += __sync_val_compare_and_swap(page32, 0, 1);
+       uaf_recovery_fails -= 1;
+       uaf_sink += __sync_lock_test_and_set(page32, 1);
+       uaf_recovery_fails -= 1;
+
+       page64 = (__u64 __arena *)page;
+       uaf_sink += __sync_fetch_and_add(page64, 1);
+       uaf_recovery_fails -= 1;
+       __sync_add_and_fetch(page64, 1);
+       uaf_recovery_fails -= 1;
+       uaf_sink += __sync_fetch_and_sub(page64, 1);
+       uaf_recovery_fails -= 1;
+       __sync_sub_and_fetch(page64, 1);
+       uaf_recovery_fails -= 1;
+       uaf_sink += __sync_fetch_and_and(page64, 1);
+       uaf_recovery_fails -= 1;
+       __sync_and_and_fetch(page64, 1);
+       uaf_recovery_fails -= 1;
+       uaf_sink += __sync_fetch_and_or(page64, 1);
+       uaf_recovery_fails -= 1;
+       __sync_or_and_fetch(page64, 1);
+       uaf_recovery_fails -= 1;
+       uaf_sink += __sync_fetch_and_xor(page64, 1);
+       uaf_recovery_fails -= 1;
+       __sync_xor_and_fetch(page64, 1);
+       uaf_recovery_fails -= 1;
+       uaf_sink += __sync_val_compare_and_swap(page64, 0, 1);
+       uaf_recovery_fails -= 1;
+       uaf_sink += __sync_lock_test_and_set(page64, 1);
+       uaf_recovery_fails -= 1;
+#endif
+
+       return 0;
+}
+
+char _license[] SEC("license") = "GPL";