xref: /linux/tools/testing/selftests/bpf/libarena/include/libarena/userspace.h (revision 5a8cd539ac19f7a68e68e1d25ef9ca2ff55b8500)
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