xref: /linux/tools/testing/selftests/bpf/progs/verifier_global_subprogs.c (revision 9e56ff53b4115875667760445b028357848b4748)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
3 
4 #include <vmlinux.h>
5 #include <bpf/bpf_helpers.h>
6 #include <bpf/bpf_tracing.h>
7 #include "bpf_misc.h"
8 #include "xdp_metadata.h"
9 #include "bpf_kfuncs.h"
10 
11 int arr[1];
12 int unkn_idx;
13 const volatile bool call_dead_subprog = false;
14 
15 __noinline long global_bad(void)
16 {
17 	return arr[unkn_idx]; /* BOOM */
18 }
19 
20 __noinline long global_good(void)
21 {
22 	return arr[0];
23 }
24 
25 __noinline long global_calls_bad(void)
26 {
27 	return global_good() + global_bad() /* does BOOM indirectly */;
28 }
29 
30 __noinline long global_calls_good_only(void)
31 {
32 	return global_good();
33 }
34 
35 __noinline long global_dead(void)
36 {
37 	return arr[0] * 2;
38 }
39 
40 SEC("?raw_tp")
41 __success __log_level(2)
42 /* main prog is validated completely first */
43 __msg("('global_calls_good_only') is global and assumed valid.")
44 /* eventually global_good() is transitively validated as well */
45 __msg("Validating global_good() func")
46 __msg("('global_good') is safe for any args that match its prototype")
47 int chained_global_func_calls_success(void)
48 {
49 	int sum = 0;
50 
51 	if (call_dead_subprog)
52 		sum += global_dead();
53 	return global_calls_good_only() + sum;
54 }
55 
56 SEC("?raw_tp")
57 __failure __log_level(2)
58 /* main prog validated successfully first */
59 __msg("('global_calls_bad') is global and assumed valid.")
60 /* eventually we validate global_bad() and fail */
61 __msg("Validating global_bad() func")
62 __msg("math between map_value pointer and register") /* BOOM */
63 int chained_global_func_calls_bad(void)
64 {
65 	return global_calls_bad();
66 }
67 
68 /* do out of bounds access forcing verifier to fail verification if this
69  * global func is called
70  */
71 __noinline int global_unsupp(const int *mem)
72 {
73 	if (!mem)
74 		return 0;
75 	return mem[100]; /* BOOM */
76 }
77 
78 const volatile bool skip_unsupp_global = true;
79 
80 SEC("?raw_tp")
81 __success
82 int guarded_unsupp_global_called(void)
83 {
84 	if (!skip_unsupp_global)
85 		return global_unsupp(NULL);
86 	return 0;
87 }
88 
89 SEC("?raw_tp")
90 __failure __log_level(2)
91 __msg("Func#1 ('global_unsupp') is global and assumed valid.")
92 __msg("Validating global_unsupp() func#1...")
93 __msg("value is outside of the allowed memory range")
94 int unguarded_unsupp_global_called(void)
95 {
96 	int x = 0;
97 
98 	return global_unsupp(&x);
99 }
100 
101 long stack[128];
102 
103 __weak int subprog_nullable_ptr_bad(int *p)
104 {
105 	return (*p) * 2; /* bad, missing null check */
106 }
107 
108 SEC("?raw_tp")
109 __failure __log_level(2)
110 __msg("invalid mem access 'mem_or_null'")
111 int arg_tag_nullable_ptr_fail(void *ctx)
112 {
113 	int x = 42;
114 
115 	return subprog_nullable_ptr_bad(&x);
116 }
117 
118 __noinline __weak int subprog_nonnull_ptr_good(int *p1 __arg_nonnull, int *p2 __arg_nonnull)
119 {
120 	return (*p1) * (*p2); /* good, no need for NULL checks */
121 }
122 
123 int x = 47;
124 
125 SEC("?raw_tp")
126 __success __log_level(2)
127 int arg_tag_nonnull_ptr_good(void *ctx)
128 {
129 	int y = 74;
130 
131 	return subprog_nonnull_ptr_good(&x, &y);
132 }
133 
134 /* this global subprog can be now called from many types of entry progs, each
135  * with different context type
136  */
137 __weak int subprog_ctx_tag(void *ctx __arg_ctx)
138 {
139 	return bpf_get_stack(ctx, stack, sizeof(stack), 0);
140 }
141 
142 __weak int raw_tp_canonical(struct bpf_raw_tracepoint_args *ctx __arg_ctx)
143 {
144 	return 0;
145 }
146 
147 __weak int raw_tp_u64_array(u64 *ctx __arg_ctx)
148 {
149 	return 0;
150 }
151 
152 SEC("?raw_tp")
153 __success __log_level(2)
154 int arg_tag_ctx_raw_tp(void *ctx)
155 {
156 	return subprog_ctx_tag(ctx) + raw_tp_canonical(ctx) + raw_tp_u64_array(ctx);
157 }
158 
159 SEC("?raw_tp.w")
160 __success __log_level(2)
161 int arg_tag_ctx_raw_tp_writable(void *ctx)
162 {
163 	return subprog_ctx_tag(ctx) + raw_tp_canonical(ctx) + raw_tp_u64_array(ctx);
164 }
165 
166 SEC("?tp_btf/sys_enter")
167 __success __log_level(2)
168 int arg_tag_ctx_raw_tp_btf(void *ctx)
169 {
170 	return subprog_ctx_tag(ctx) + raw_tp_canonical(ctx) + raw_tp_u64_array(ctx);
171 }
172 
173 struct whatever { };
174 
175 __weak int tp_whatever(struct whatever *ctx __arg_ctx)
176 {
177 	return 0;
178 }
179 
180 SEC("?tp")
181 __success __log_level(2)
182 int arg_tag_ctx_tp(void *ctx)
183 {
184 	return subprog_ctx_tag(ctx) + tp_whatever(ctx);
185 }
186 
187 __weak int kprobe_subprog_pt_regs(struct pt_regs *ctx __arg_ctx)
188 {
189 	return 0;
190 }
191 
192 __weak int kprobe_subprog_typedef(bpf_user_pt_regs_t *ctx __arg_ctx)
193 {
194 	return 0;
195 }
196 
197 SEC("?kprobe")
198 __success __log_level(2)
199 int arg_tag_ctx_kprobe(void *ctx)
200 {
201 	return subprog_ctx_tag(ctx) +
202 	       kprobe_subprog_pt_regs(ctx) +
203 	       kprobe_subprog_typedef(ctx);
204 }
205 
206 __weak int perf_subprog_regs(
207 #if defined(bpf_target_riscv)
208 	struct user_regs_struct *ctx __arg_ctx
209 #elif defined(bpf_target_s390)
210 	/* user_pt_regs typedef is anonymous struct, so only `void *` works */
211 	void *ctx __arg_ctx
212 #elif defined(bpf_target_loongarch) || defined(bpf_target_arm64) || defined(bpf_target_powerpc)
213 	struct user_pt_regs *ctx __arg_ctx
214 #else
215 	struct pt_regs *ctx __arg_ctx
216 #endif
217 )
218 {
219 	return 0;
220 }
221 
222 __weak int perf_subprog_typedef(bpf_user_pt_regs_t *ctx __arg_ctx)
223 {
224 	return 0;
225 }
226 
227 __weak int perf_subprog_canonical(struct bpf_perf_event_data *ctx __arg_ctx)
228 {
229 	return 0;
230 }
231 
232 SEC("?perf_event")
233 __success __log_level(2)
234 int arg_tag_ctx_perf(void *ctx)
235 {
236 	return subprog_ctx_tag(ctx) +
237 	       perf_subprog_regs(ctx) +
238 	       perf_subprog_typedef(ctx) +
239 	       perf_subprog_canonical(ctx);
240 }
241 
242 __weak int iter_subprog_void(void *ctx __arg_ctx)
243 {
244 	return 0;
245 }
246 
247 __weak int iter_subprog_typed(struct bpf_iter__task *ctx __arg_ctx)
248 {
249 	return 0;
250 }
251 
252 SEC("?iter/task")
253 __success __log_level(2)
254 int arg_tag_ctx_iter_task(struct bpf_iter__task *ctx)
255 {
256 	return (iter_subprog_void(ctx) + iter_subprog_typed(ctx)) & 1;
257 }
258 
259 __weak int tracing_subprog_void(void *ctx __arg_ctx)
260 {
261 	return 0;
262 }
263 
264 __weak int tracing_subprog_u64(u64 *ctx __arg_ctx)
265 {
266 	return 0;
267 }
268 
269 int acc;
270 
271 SEC("?fentry/" SYS_PREFIX "sys_nanosleep")
272 __success __log_level(2)
273 int BPF_PROG(arg_tag_ctx_fentry)
274 {
275 	acc += tracing_subprog_void(ctx) + tracing_subprog_u64(ctx);
276 	return 0;
277 }
278 
279 SEC("?fexit/" SYS_PREFIX "sys_nanosleep")
280 __success __log_level(2)
281 int BPF_PROG(arg_tag_ctx_fexit)
282 {
283 	acc += tracing_subprog_void(ctx) + tracing_subprog_u64(ctx);
284 	return 0;
285 }
286 
287 SEC("?fmod_ret/" SYS_PREFIX "sys_nanosleep")
288 __success __log_level(2)
289 int BPF_PROG(arg_tag_ctx_fmod_ret)
290 {
291 	return tracing_subprog_void(ctx) + tracing_subprog_u64(ctx);
292 }
293 
294 SEC("?lsm/bpf")
295 __success __log_level(2)
296 int BPF_PROG(arg_tag_ctx_lsm)
297 {
298 	return tracing_subprog_void(ctx) + tracing_subprog_u64(ctx);
299 }
300 
301 SEC("?struct_ops/test_1")
302 __success __log_level(2)
303 int BPF_PROG(arg_tag_ctx_struct_ops)
304 {
305 	return tracing_subprog_void(ctx) + tracing_subprog_u64(ctx);
306 }
307 
308 SEC(".struct_ops")
309 struct bpf_dummy_ops dummy_1 = {
310 	.test_1 = (void *)arg_tag_ctx_struct_ops,
311 };
312 
313 SEC("?syscall")
314 __success __log_level(2)
315 int arg_tag_ctx_syscall(void *ctx)
316 {
317 	return tracing_subprog_void(ctx) + tracing_subprog_u64(ctx) + tp_whatever(ctx);
318 }
319 
320 __weak int subprog_dynptr(struct bpf_dynptr *dptr)
321 {
322 	long *d, t, buf[1] = {};
323 
324 	d = bpf_dynptr_data(dptr, 0, sizeof(long));
325 	if (!d)
326 		return 0;
327 
328 	t = *d + 1;
329 
330 	d = bpf_dynptr_slice(dptr, 0, &buf, sizeof(long));
331 	if (!d)
332 		return t;
333 
334 	t = *d + 2;
335 
336 	return t;
337 }
338 
339 SEC("?xdp")
340 __success __log_level(2)
341 int arg_tag_dynptr(struct xdp_md *ctx)
342 {
343 	struct bpf_dynptr dptr;
344 
345 	bpf_dynptr_from_xdp(ctx, 0, &dptr);
346 
347 	return subprog_dynptr(&dptr);
348 }
349 
350 char _license[] SEC("license") = "GPL";
351