1 // SPDX-License-Identifier: LGPL-2.1 OR BSD-2-Clause
2 /* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
3 #pragma once
4
5 #include <errno.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <sys/mman.h>
9
10 #include <bpf/libbpf.h>
11 #include <bpf/bpf.h>
12
libarena_run_prog(int prog_fd)13 static inline int libarena_run_prog(int prog_fd)
14 {
15 LIBBPF_OPTS(bpf_test_run_opts, opts);
16 int ret;
17
18 ret = bpf_prog_test_run_opts(prog_fd, &opts);
19 if (ret)
20 return ret;
21
22 return opts.retval;
23 }
24
libarena_is_test_prog(const char * name)25 static inline bool libarena_is_test_prog(const char *name)
26 {
27 return strstr(name, "test_") == name;
28 }
29
libarena_is_asan_test_prog(const char * name)30 static inline bool libarena_is_asan_test_prog(const char *name)
31 {
32 return strstr(name, "asan_test") == name;
33 }
34
libarena_is_parallel_test_prog(const char * name)35 static inline bool libarena_is_parallel_test_prog(const char *name)
36 {
37 return strstr(name, "parallel_test") == name;
38 }
39
40
libarena_run_prog_args(int prog_fd,void * args,size_t argsize)41 static inline int libarena_run_prog_args(int prog_fd, void *args, size_t argsize)
42 {
43 LIBBPF_OPTS(bpf_test_run_opts, opts);
44 int ret;
45
46 opts.ctx_in = args;
47 opts.ctx_size_in = argsize;
48
49 ret = bpf_prog_test_run_opts(prog_fd, &opts);
50
51 return ret ?: opts.retval;
52 }
53
libarena_get_arena_base(int arena_get_info_fd,void ** arena_base)54 static inline int libarena_get_arena_base(int arena_get_info_fd,
55 void **arena_base)
56 {
57 LIBBPF_OPTS(bpf_test_run_opts, opts);
58 struct arena_get_info_args args = { .arena_base = NULL };
59 int ret;
60
61 opts.ctx_in = &args;
62 opts.ctx_size_in = sizeof(args);
63
64 ret = bpf_prog_test_run_opts(arena_get_info_fd, &opts);
65 if (ret)
66 return ret;
67 if (opts.retval)
68 return opts.retval;
69
70 *arena_base = args.arena_base;
71 return 0;
72 }
73
libarena_get_globals_pages(int arena_get_globals_fd,size_t arena_all_pages,u64 * globals_pages)74 static inline int libarena_get_globals_pages(int arena_get_globals_fd,
75 size_t arena_all_pages,
76 u64 *globals_pages)
77 {
78 size_t pgsize = sysconf(_SC_PAGESIZE);
79 void *arena_base;
80 ssize_t i;
81 u8 *vec;
82 int ret;
83
84 ret = libarena_get_arena_base(arena_get_globals_fd, &arena_base);
85 if (ret)
86 return ret;
87
88 if (!arena_base)
89 return -EINVAL;
90
91 vec = calloc(arena_all_pages, sizeof(*vec));
92 if (!vec)
93 return -ENOMEM;
94
95 if (mincore(arena_base, arena_all_pages * pgsize, vec) < 0) {
96 ret = -errno;
97 free(vec);
98 return ret;
99 }
100
101 *globals_pages = 0;
102 for (i = arena_all_pages - 1; i >= 0; i--) {
103 if (!(vec[i] & 0x1))
104 break;
105 *globals_pages += 1;
106 }
107
108 free(vec);
109 return 0;
110 }
111
libarena_asan_init(int arena_asan_init_fd,int asan_init_fd,size_t arena_all_pages)112 static inline int libarena_asan_init(int arena_asan_init_fd,
113 int asan_init_fd,
114 size_t arena_all_pages)
115 {
116 LIBBPF_OPTS(bpf_test_run_opts, opts);
117 struct asan_init_args args;
118 u64 globals_pages = 0;
119 int ret;
120
121 ret = libarena_get_globals_pages(arena_asan_init_fd,
122 arena_all_pages, &globals_pages);
123 if (ret)
124 return ret;
125
126 args = (struct asan_init_args){
127 .arena_all_pages = arena_all_pages,
128 .arena_globals_pages = globals_pages,
129 };
130
131 opts.ctx_in = &args;
132 opts.ctx_size_in = sizeof(args);
133
134 ret = bpf_prog_test_run_opts(asan_init_fd, &opts);
135 if (ret)
136 return ret;
137 return opts.retval;
138 }
139