xref: /linux/tools/testing/selftests/bpf/progs/arena_kfunc.c (revision 5a8cd539ac19f7a68e68e1d25ef9ca2ff55b8500)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
3 
4 #define BPF_NO_KFUNC_PROTOTYPES
5 #include <vmlinux.h>
6 #include <bpf/bpf_helpers.h>
7 #include "bpf_misc.h"
8 #include "bpf_experimental.h"
9 #include <bpf_arena_common.h>
10 #include "../test_kmods/bpf_testmod_kfunc.h"
11 
12 struct {
13 	__uint(type, BPF_MAP_TYPE_ARENA);
14 	__uint(map_flags, BPF_F_MMAPABLE);
15 	/* page 0 hosts the arena global, page 1 is for allocations */
16 	__uint(max_entries, 2);
17 } arena SEC(".maps");
18 
19 /*
20  * Occupies page 0 so no allocation lands at arena offset 0, which the
21  * nullable tests below must be able to tell apart from NULL.
22  */
23 u64 __arena arena_pad;
24 
25 /* volatile to force the scalar reloads below */
26 volatile u64 stash;
27 
28 SEC("syscall")
29 __arch_x86_64
30 __arch_arm64
31 __success __retval(0)
arena_arg_forms(void * ctx)32 int arena_arg_forms(void *ctx)
33 {
34 #if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
35 	u64 __arena *val;
36 	u64 ret;
37 
38 	val = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
39 	if (!val)
40 		return 1;
41 
42 	/* PTR_TO_ARENA argument */
43 	*val = 41;
44 	ret = bpf_kfunc_arena_arg_test((u64 *)val);
45 	if (ret != 41 || *val != 42)
46 		return 2;
47 
48 	/* the low 32 bits as a scalar */
49 	stash = (u32)(u64)val;
50 	ret = bpf_kfunc_arena_arg_test((u64 *)stash);
51 	if (ret != 42 || *val != 43)
52 		return 3;
53 
54 	/* the full user address as a scalar */
55 	stash = (u64)val;
56 	bpf_addr_space_cast(stash, 1, 0);
57 	ret = bpf_kfunc_arena_arg_test((u64 *)stash);
58 	if (ret != 43 || *val != 44)
59 		return 4;
60 
61 	bpf_arena_free_pages(&arena, (void __arena *)val, 1);
62 #endif
63 	return 0;
64 }
65 
66 /*
67  * Pin the rebase semantics using the capture kfuncs, which return the raw
68  * argument value: __arena rebases unconditionally, so zero low 32 bits
69  * arrive as the arena kernel base, while __arena__nullable turns them into
70  * NULL.
71  */
72 SEC("syscall")
73 __arch_x86_64
74 __arch_arm64
75 __success __retval(0)
arena_arg_rebase(void * ctx)76 int arena_arg_rebase(void *ctx)
77 {
78 #if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
79 	u64 __arena *val;
80 	u64 base, off;
81 
82 	val = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
83 	if (!val)
84 		return 1;
85 
86 	base = bpf_kfunc_arena_cap_test(NULL);
87 	if (!base)
88 		return 2;
89 
90 	/* only the low 32 bits contribute */
91 	stash = 0xbadc0ffe00000000;
92 	if (bpf_kfunc_arena_cap_test((u64 *)stash) != base)
93 		return 3;
94 
95 	off = (u32)(u64)val;
96 	if (bpf_kfunc_arena_cap_test((u64 *)val) != base + off)
97 		return 4;
98 
99 	if (bpf_kfunc_arena_cap_nullable_test(NULL) != 0)
100 		return 5;
101 
102 	stash = 0xbadc0ffe00000000;
103 	if (bpf_kfunc_arena_cap_nullable_test((u64 *)stash) != 0)
104 		return 6;
105 
106 	if (bpf_kfunc_arena_cap_nullable_test((u64 *)val) != base + off)
107 		return 7;
108 
109 	bpf_arena_free_pages(&arena, (void __arena *)val, 1);
110 #endif
111 	return 0;
112 }
113 
114 SEC("syscall")
115 __arch_x86_64
116 __arch_arm64
117 __success __retval(0)
arena_args5(void * ctx)118 int arena_args5(void *ctx)
119 {
120 #if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
121 	u64 __arena *val;
122 
123 	val = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
124 	if (!val)
125 		return 1;
126 
127 	val[0] = 1;
128 	val[1] = 2;
129 	val[2] = 4;
130 	val[3] = 8;
131 	val[4] = 16;
132 
133 	if (bpf_kfunc_arena_args5_test((u64 *)&val[0], (u64 *)&val[1],
134 				       (u64 *)&val[2], (u64 *)&val[3],
135 				       (u64 *)&val[4]) != 31)
136 		return 2;
137 	if (bpf_kfunc_arena_args5_test((u64 *)&val[0], (u64 *)&val[1],
138 				       (u64 *)&val[2], (u64 *)&val[3], NULL) != 15)
139 		return 3;
140 
141 	bpf_arena_free_pages(&arena, (void __arena *)val, 1);
142 #endif
143 	return 0;
144 }
145 
146 SEC("syscall")
147 __arch_x86_64
148 __arch_arm64
149 __success __retval(0)
arena_arg_mixed(void * ctx)150 int arena_arg_mixed(void *ctx)
151 {
152 #if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
153 	u64 __arena *val;
154 
155 	val = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
156 	if (!val)
157 		return 1;
158 
159 	val[0] = 7;
160 	val[1] = 5;
161 
162 	if (bpf_kfunc_arena_mixed_test((u64 *)&val[0], NULL) != 7)
163 		return 2;
164 
165 	if (bpf_kfunc_arena_mixed_test((u64 *)&val[0], (u64 *)&val[1]) != 12)
166 		return 3;
167 
168 	bpf_arena_free_pages(&arena, (void __arena *)val, 1);
169 #endif
170 	return 0;
171 }
172 
173 /* kernel-side faults on unpopulated pages recover via the scratch page */
174 SEC("syscall")
175 __arch_x86_64
176 __arch_arm64
177 __success __retval(0)
arena_arg_unpopulated(void * ctx)178 int arena_arg_unpopulated(void *ctx)
179 {
180 #if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
181 	u64 __arena *val;
182 
183 	val = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
184 	if (!val)
185 		return 1;
186 
187 	stash = (u64)val + PAGE_SIZE;
188 	bpf_kfunc_arena_arg_test((u64 *)stash);
189 
190 	bpf_arena_free_pages(&arena, (void __arena *)val, 1);
191 #endif
192 	return 0;
193 }
194 
195 SEC("syscall")
196 __arch_x86_64
197 __arch_arm64
198 __failure __msg("arena pointer requires a program with an associated arena")
arena_arg_no_arena(void * ctx)199 int arena_arg_no_arena(void *ctx)
200 {
201 	bpf_kfunc_arena_arg_test((u64 *)1);
202 	return 0;
203 }
204 
205 SEC("syscall")
206 __arch_x86_64
207 __arch_arm64
208 __failure __msg("is not a pointer to arena or scalar")
arena_arg_bad_reg(void * ctx)209 int arena_arg_bad_reg(void *ctx)
210 {
211 	u64 buf = 0;
212 
213 	/* use the arena so the program passes the arena presence check */
214 	bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
215 	bpf_kfunc_arena_arg_test(&buf);
216 	return 0;
217 }
218 
219 #if defined(__BPF_FEATURE_ADDR_SPACE_CAST) && \
220 	defined(__BPF_FEATURE_STACK_ARGUMENT)
221 SEC("syscall")
222 __arch_x86_64
223 __arch_arm64
224 __failure __msg("arena pointer cannot be a stack argument")
arena_arg_stack(void * ctx)225 int arena_arg_stack(void *ctx)
226 {
227 	bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
228 	bpf_kfunc_arena_stack_arg_test(1, 2, 3, 4, 5, (u64 *)1);
229 	return 0;
230 }
231 #else
232 SEC("syscall")
233 __arch_x86_64
234 __arch_arm64
235 __description("arena_arg_stack: not supported, dummy test")
236 __success
arena_arg_stack(void * ctx)237 int arena_arg_stack(void *ctx)
238 {
239 	return 0;
240 }
241 #endif
242 
243 char _license[] SEC("license") = "GPL";
244