summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/bpf/libarena/include
diff options
context:
space:
mode:
authorEmil Tsalapatis <emil@etsalapatis.com>2026-04-26 15:03:34 -0400
committerAlexei Starovoitov <ast@kernel.org>2026-04-26 18:12:22 -0700
commit9ab78691eb5fd0d3ad0a1994d4103223678eb78b (patch)
treeead6c1bb4cc6e1d07d1a046a3bff23cce691dd98 /tools/testing/selftests/bpf/libarena/include
parent8c1e1c33fe5ad867bc0b6ba121911d70e7881d88 (diff)
downloadlinux-next-9ab78691eb5fd0d3ad0a1994d4103223678eb78b.tar.gz
linux-next-9ab78691eb5fd0d3ad0a1994d4103223678eb78b.zip
selftests/bpf: Add arena ASAN runtime to libarena
Add an address sanitizer (ASAN) runtime to the arena library. The ASAN runtime implements the functions injected into BPF binaries by LLVM sanitization when ASAN is enabled during compilation. The runtime also includes functions called explicitly by memory allocation code to mark memory as poisoned/unpoisoned to ASAN. This code is a no-op when sanitization is turned off. Signed-off-by: Emil Tsalapatis <emil@etsalapatis.com> Link: https://lore.kernel.org/r/20260426190338.4615-5-emil@etsalapatis.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'tools/testing/selftests/bpf/libarena/include')
-rw-r--r--tools/testing/selftests/bpf/libarena/include/libarena/asan.h103
-rw-r--r--tools/testing/selftests/bpf/libarena/include/libarena/common.h1
2 files changed, 104 insertions, 0 deletions
diff --git a/tools/testing/selftests/bpf/libarena/include/libarena/asan.h b/tools/testing/selftests/bpf/libarena/include/libarena/asan.h
new file mode 100644
index 000000000000..eb9fc69d9eb0
--- /dev/null
+++ b/tools/testing/selftests/bpf/libarena/include/libarena/asan.h
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: LGPL-2.1 OR BSD-2-Clause
+/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
+#pragma once
+
+struct asan_init_args {
+ u64 arena_all_pages;
+ u64 arena_globals_pages;
+};
+
+int asan_init(struct asan_init_args *args);
+
+extern volatile u64 __asan_shadow_memory_dynamic_address;
+extern volatile u32 asan_reported;
+extern volatile bool asan_inited;
+extern volatile bool asan_report_once;
+
+#ifdef __BPF__
+
+#define ASAN_SHADOW_SHIFT 3
+#define ASAN_SHADOW_SCALE (1ULL << ASAN_SHADOW_SHIFT)
+#define ASAN_GRANULE_MASK ((1ULL << ASAN_SHADOW_SHIFT) - 1)
+#define ASAN_GRANULE(addr) ((s8)((u32)(u64)((addr)) & ASAN_GRANULE_MASK))
+
+#define __noasan __attribute__((no_sanitize("address")))
+
+#ifdef BPF_ARENA_ASAN
+
+typedef s8 __arena s8a;
+
+static inline
+s8a *mem_to_shadow(void __arena __arg_arena *addr)
+{
+ return (s8a *)(((u32)(u64)addr >> ASAN_SHADOW_SHIFT) +
+ __asan_shadow_memory_dynamic_address);
+}
+
+__weak __noasan
+bool asan_ready(void)
+{
+ return __asan_shadow_memory_dynamic_address;
+}
+
+int asan_poison(void __arena *addr, s8 val, size_t size);
+int asan_unpoison(void __arena *addr, size_t size);
+bool asan_shadow_set(void __arena *addr);
+
+/*
+ * Dummy calls to ensure the ASAN runtime's BTF information is present
+ * in every object file when compiling the runtime and local BPF code
+ * separately. The runtime calls are injected into the LLVM IR file
+ */
+#define DECLARE_ASAN_LOAD_STORE_SIZE(size) \
+ void __asan_store##size(intptr_t addr); \
+ void __asan_store##size##_noabort(intptr_t addr); \
+ void __asan_load##size(intptr_t addr); \
+ void __asan_load##size##_noabort(intptr_t addr); \
+ void __asan_report_store##size(intptr_t addr); \
+ void __asan_report_store##size##_noabort(intptr_t addr); \
+ void __asan_report_load##size(intptr_t addr); \
+ void __asan_report_load##size##_noabort(intptr_t addr);
+
+DECLARE_ASAN_LOAD_STORE_SIZE(1);
+DECLARE_ASAN_LOAD_STORE_SIZE(2);
+DECLARE_ASAN_LOAD_STORE_SIZE(4);
+DECLARE_ASAN_LOAD_STORE_SIZE(8);
+
+void __asan_storeN(intptr_t addr, ssize_t size);
+void __asan_storeN_noabort(intptr_t addr, ssize_t size);
+void __asan_loadN(intptr_t addr, ssize_t size);
+void __asan_loadN_noabort(intptr_t addr, ssize_t size);
+
+/*
+ * Force LLVM to emit BTF information for the stubs,
+ * because the ASAN pass in LLVM by itself doesn't.
+ */
+#define ASAN_LOAD_STORE_SIZE(size) \
+ __asan_store##size, \
+ __asan_store##size##_noabort, \
+ __asan_load##size, \
+ __asan_load##size##_noabort, \
+ __asan_report_store##size, \
+ __asan_report_store##size##_noabort, \
+ __asan_report_load##size, \
+ __asan_report_load##size##_noabort
+
+__attribute__((used))
+static void (*__asan_btf_anchors[])(intptr_t) = {
+ ASAN_LOAD_STORE_SIZE(1),
+ ASAN_LOAD_STORE_SIZE(2),
+ ASAN_LOAD_STORE_SIZE(4),
+ ASAN_LOAD_STORE_SIZE(8),
+};
+
+#else /* BPF_ARENA_ASAN */
+
+static inline int asan_poison(void __arena *addr, s8 val, size_t size) { return 0; }
+static inline int asan_unpoison(void __arena *addr, size_t size) { return 0; }
+static inline bool asan_shadow_set(void __arena *addr) { return 0; }
+__weak bool asan_ready(void) { return true; }
+
+#endif /* BPF_ARENA_ASAN */
+
+#endif /* __BPF__ */
diff --git a/tools/testing/selftests/bpf/libarena/include/libarena/common.h b/tools/testing/selftests/bpf/libarena/include/libarena/common.h
index d088f3e75798..21eb18bf4533 100644
--- a/tools/testing/selftests/bpf/libarena/include/libarena/common.h
+++ b/tools/testing/selftests/bpf/libarena/include/libarena/common.h
@@ -44,6 +44,7 @@ struct {
* the opaque volatile variable 0 instead of the constant 0.
*/
extern const volatile u32 zero;
+extern volatile u64 asan_violated;
int arena_fls(__u64 word);