1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2022 Facebook */
3 
4 #include <errno.h>
5 #include <string.h>
6 #include <linux/bpf.h>
7 #include <bpf/bpf_helpers.h>
8 #include "bpf_misc.h"
9 
10 char _license[] SEC("license") = "GPL";
11 
12 struct test_info {
13 	int x;
14 	struct bpf_dynptr ptr;
15 };
16 
17 struct {
18 	__uint(type, BPF_MAP_TYPE_ARRAY);
19 	__uint(max_entries, 1);
20 	__type(key, __u32);
21 	__type(value, struct bpf_dynptr);
22 } array_map1 SEC(".maps");
23 
24 struct {
25 	__uint(type, BPF_MAP_TYPE_ARRAY);
26 	__uint(max_entries, 1);
27 	__type(key, __u32);
28 	__type(value, struct test_info);
29 } array_map2 SEC(".maps");
30 
31 struct {
32 	__uint(type, BPF_MAP_TYPE_ARRAY);
33 	__uint(max_entries, 1);
34 	__type(key, __u32);
35 	__type(value, __u32);
36 } array_map3 SEC(".maps");
37 
38 struct sample {
39 	int pid;
40 	long value;
41 	char comm[16];
42 };
43 
44 struct {
45 	__uint(type, BPF_MAP_TYPE_RINGBUF);
46 } ringbuf SEC(".maps");
47 
48 int err, val;
49 
50 static int get_map_val_dynptr(struct bpf_dynptr *ptr)
51 {
52 	__u32 key = 0, *map_val;
53 
54 	bpf_map_update_elem(&array_map3, &key, &val, 0);
55 
56 	map_val = bpf_map_lookup_elem(&array_map3, &key);
57 	if (!map_val)
58 		return -ENOENT;
59 
60 	bpf_dynptr_from_mem(map_val, sizeof(*map_val), 0, ptr);
61 
62 	return 0;
63 }
64 
65 /* Every bpf_ringbuf_reserve_dynptr call must have a corresponding
66  * bpf_ringbuf_submit/discard_dynptr call
67  */
68 SEC("?raw_tp/sys_nanosleep")
69 int ringbuf_missing_release1(void *ctx)
70 {
71 	struct bpf_dynptr ptr;
72 
73 	bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr);
74 
75 	/* missing a call to bpf_ringbuf_discard/submit_dynptr */
76 
77 	return 0;
78 }
79 
80 SEC("?raw_tp/sys_nanosleep")
81 int ringbuf_missing_release2(void *ctx)
82 {
83 	struct bpf_dynptr ptr1, ptr2;
84 	struct sample *sample;
85 
86 	bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr1);
87 	bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr2);
88 
89 	sample = bpf_dynptr_data(&ptr1, 0, sizeof(*sample));
90 	if (!sample) {
91 		bpf_ringbuf_discard_dynptr(&ptr1, 0);
92 		bpf_ringbuf_discard_dynptr(&ptr2, 0);
93 		return 0;
94 	}
95 
96 	bpf_ringbuf_submit_dynptr(&ptr1, 0);
97 
98 	/* missing a call to bpf_ringbuf_discard/submit_dynptr on ptr2 */
99 
100 	return 0;
101 }
102 
103 static int missing_release_callback_fn(__u32 index, void *data)
104 {
105 	struct bpf_dynptr ptr;
106 
107 	bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr);
108 
109 	/* missing a call to bpf_ringbuf_discard/submit_dynptr */
110 
111 	return 0;
112 }
113 
114 /* Any dynptr initialized within a callback must have bpf_dynptr_put called */
115 SEC("?raw_tp/sys_nanosleep")
116 int ringbuf_missing_release_callback(void *ctx)
117 {
118 	bpf_loop(10, missing_release_callback_fn, NULL, 0);
119 	return 0;
120 }
121 
122 /* Can't call bpf_ringbuf_submit/discard_dynptr on a non-initialized dynptr */
123 SEC("?raw_tp/sys_nanosleep")
124 int ringbuf_release_uninit_dynptr(void *ctx)
125 {
126 	struct bpf_dynptr ptr;
127 
128 	/* this should fail */
129 	bpf_ringbuf_submit_dynptr(&ptr, 0);
130 
131 	return 0;
132 }
133 
134 /* A dynptr can't be used after it has been invalidated */
135 SEC("?raw_tp/sys_nanosleep")
136 int use_after_invalid(void *ctx)
137 {
138 	struct bpf_dynptr ptr;
139 	char read_data[64];
140 
141 	bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(read_data), 0, &ptr);
142 
143 	bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0);
144 
145 	bpf_ringbuf_submit_dynptr(&ptr, 0);
146 
147 	/* this should fail */
148 	bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0);
149 
150 	return 0;
151 }
152 
153 /* Can't call non-dynptr ringbuf APIs on a dynptr ringbuf sample */
154 SEC("?raw_tp/sys_nanosleep")
155 int ringbuf_invalid_api(void *ctx)
156 {
157 	struct bpf_dynptr ptr;
158 	struct sample *sample;
159 
160 	bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr);
161 	sample = bpf_dynptr_data(&ptr, 0, sizeof(*sample));
162 	if (!sample)
163 		goto done;
164 
165 	sample->pid = 123;
166 
167 	/* invalid API use. need to use dynptr API to submit/discard */
168 	bpf_ringbuf_submit(sample, 0);
169 
170 done:
171 	bpf_ringbuf_discard_dynptr(&ptr, 0);
172 	return 0;
173 }
174 
175 /* Can't add a dynptr to a map */
176 SEC("?raw_tp/sys_nanosleep")
177 int add_dynptr_to_map1(void *ctx)
178 {
179 	struct bpf_dynptr ptr;
180 	int key = 0;
181 
182 	bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr);
183 
184 	/* this should fail */
185 	bpf_map_update_elem(&array_map1, &key, &ptr, 0);
186 
187 	bpf_ringbuf_submit_dynptr(&ptr, 0);
188 
189 	return 0;
190 }
191 
192 /* Can't add a struct with an embedded dynptr to a map */
193 SEC("?raw_tp/sys_nanosleep")
194 int add_dynptr_to_map2(void *ctx)
195 {
196 	struct test_info x;
197 	int key = 0;
198 
199 	bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &x.ptr);
200 
201 	/* this should fail */
202 	bpf_map_update_elem(&array_map2, &key, &x, 0);
203 
204 	bpf_ringbuf_submit_dynptr(&x.ptr, 0);
205 
206 	return 0;
207 }
208 
209 /* A data slice can't be accessed out of bounds */
210 SEC("?raw_tp/sys_nanosleep")
211 int data_slice_out_of_bounds_ringbuf(void *ctx)
212 {
213 	struct bpf_dynptr ptr;
214 	void *data;
215 
216 	bpf_ringbuf_reserve_dynptr(&ringbuf, 8, 0, &ptr);
217 
218 	data  = bpf_dynptr_data(&ptr, 0, 8);
219 	if (!data)
220 		goto done;
221 
222 	/* can't index out of bounds of the data slice */
223 	val = *((char *)data + 8);
224 
225 done:
226 	bpf_ringbuf_submit_dynptr(&ptr, 0);
227 	return 0;
228 }
229 
230 SEC("?raw_tp/sys_nanosleep")
231 int data_slice_out_of_bounds_map_value(void *ctx)
232 {
233 	__u32 key = 0, map_val;
234 	struct bpf_dynptr ptr;
235 	void *data;
236 
237 	get_map_val_dynptr(&ptr);
238 
239 	data  = bpf_dynptr_data(&ptr, 0, sizeof(map_val));
240 	if (!data)
241 		return 0;
242 
243 	/* can't index out of bounds of the data slice */
244 	val = *((char *)data + (sizeof(map_val) + 1));
245 
246 	return 0;
247 }
248 
249 /* A data slice can't be used after it has been released */
250 SEC("?raw_tp/sys_nanosleep")
251 int data_slice_use_after_release(void *ctx)
252 {
253 	struct bpf_dynptr ptr;
254 	struct sample *sample;
255 
256 	bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr);
257 	sample = bpf_dynptr_data(&ptr, 0, sizeof(*sample));
258 	if (!sample)
259 		goto done;
260 
261 	sample->pid = 123;
262 
263 	bpf_ringbuf_submit_dynptr(&ptr, 0);
264 
265 	/* this should fail */
266 	val = sample->pid;
267 
268 	return 0;
269 
270 done:
271 	bpf_ringbuf_discard_dynptr(&ptr, 0);
272 	return 0;
273 }
274 
275 /* A data slice must be first checked for NULL */
276 SEC("?raw_tp/sys_nanosleep")
277 int data_slice_missing_null_check1(void *ctx)
278 {
279 	struct bpf_dynptr ptr;
280 	void *data;
281 
282 	bpf_ringbuf_reserve_dynptr(&ringbuf, 8, 0, &ptr);
283 
284 	data  = bpf_dynptr_data(&ptr, 0, 8);
285 
286 	/* missing if (!data) check */
287 
288 	/* this should fail */
289 	*(__u8 *)data = 3;
290 
291 	bpf_ringbuf_submit_dynptr(&ptr, 0);
292 	return 0;
293 }
294 
295 /* A data slice can't be dereferenced if it wasn't checked for null */
296 SEC("?raw_tp/sys_nanosleep")
297 int data_slice_missing_null_check2(void *ctx)
298 {
299 	struct bpf_dynptr ptr;
300 	__u64 *data1, *data2;
301 
302 	bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &ptr);
303 
304 	data1 = bpf_dynptr_data(&ptr, 0, 8);
305 	data2 = bpf_dynptr_data(&ptr, 0, 8);
306 	if (data1)
307 		/* this should fail */
308 		*data2 = 3;
309 
310 done:
311 	bpf_ringbuf_discard_dynptr(&ptr, 0);
312 	return 0;
313 }
314 
315 /* Can't pass in a dynptr as an arg to a helper function that doesn't take in a
316  * dynptr argument
317  */
318 SEC("?raw_tp/sys_nanosleep")
319 int invalid_helper1(void *ctx)
320 {
321 	struct bpf_dynptr ptr;
322 
323 	get_map_val_dynptr(&ptr);
324 
325 	/* this should fail */
326 	bpf_strncmp((const char *)&ptr, sizeof(ptr), "hello!");
327 
328 	return 0;
329 }
330 
331 /* A dynptr can't be passed into a helper function at a non-zero offset */
332 SEC("?raw_tp/sys_nanosleep")
333 int invalid_helper2(void *ctx)
334 {
335 	struct bpf_dynptr ptr;
336 	char read_data[64];
337 
338 	get_map_val_dynptr(&ptr);
339 
340 	/* this should fail */
341 	bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 8, 0);
342 
343 	return 0;
344 }
345 
346 /* A bpf_dynptr is invalidated if it's been written into */
347 SEC("?raw_tp/sys_nanosleep")
348 int invalid_write1(void *ctx)
349 {
350 	struct bpf_dynptr ptr;
351 	void *data;
352 	__u8 x = 0;
353 
354 	get_map_val_dynptr(&ptr);
355 
356 	memcpy(&ptr, &x, sizeof(x));
357 
358 	/* this should fail */
359 	data = bpf_dynptr_data(&ptr, 0, 1);
360 
361 	return 0;
362 }
363 
364 /*
365  * A bpf_dynptr can't be used as a dynptr if it has been written into at a fixed
366  * offset
367  */
368 SEC("?raw_tp/sys_nanosleep")
369 int invalid_write2(void *ctx)
370 {
371 	struct bpf_dynptr ptr;
372 	char read_data[64];
373 	__u8 x = 0;
374 
375 	bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr);
376 
377 	memcpy((void *)&ptr + 8, &x, sizeof(x));
378 
379 	/* this should fail */
380 	bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0);
381 
382 	bpf_ringbuf_submit_dynptr(&ptr, 0);
383 
384 	return 0;
385 }
386 
387 /*
388  * A bpf_dynptr can't be used as a dynptr if it has been written into at a
389  * non-const offset
390  */
391 SEC("?raw_tp/sys_nanosleep")
392 int invalid_write3(void *ctx)
393 {
394 	struct bpf_dynptr ptr;
395 	char stack_buf[16];
396 	unsigned long len;
397 	__u8 x = 0;
398 
399 	bpf_ringbuf_reserve_dynptr(&ringbuf, 8, 0, &ptr);
400 
401 	memcpy(stack_buf, &val, sizeof(val));
402 	len = stack_buf[0] & 0xf;
403 
404 	memcpy((void *)&ptr + len, &x, sizeof(x));
405 
406 	/* this should fail */
407 	bpf_ringbuf_submit_dynptr(&ptr, 0);
408 
409 	return 0;
410 }
411 
412 static int invalid_write4_callback(__u32 index, void *data)
413 {
414 	*(__u32 *)data = 123;
415 
416 	return 0;
417 }
418 
419 /* If the dynptr is written into in a callback function, it should
420  * be invalidated as a dynptr
421  */
422 SEC("?raw_tp/sys_nanosleep")
423 int invalid_write4(void *ctx)
424 {
425 	struct bpf_dynptr ptr;
426 
427 	bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr);
428 
429 	bpf_loop(10, invalid_write4_callback, &ptr, 0);
430 
431 	/* this should fail */
432 	bpf_ringbuf_submit_dynptr(&ptr, 0);
433 
434 	return 0;
435 }
436 
437 /* A globally-defined bpf_dynptr can't be used (it must reside as a stack frame) */
438 struct bpf_dynptr global_dynptr;
439 SEC("?raw_tp/sys_nanosleep")
440 int global(void *ctx)
441 {
442 	/* this should fail */
443 	bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &global_dynptr);
444 
445 	bpf_ringbuf_discard_dynptr(&global_dynptr, 0);
446 
447 	return 0;
448 }
449 
450 /* A direct read should fail */
451 SEC("?raw_tp/sys_nanosleep")
452 int invalid_read1(void *ctx)
453 {
454 	struct bpf_dynptr ptr;
455 
456 	bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr);
457 
458 	/* this should fail */
459 	val = *(int *)&ptr;
460 
461 	bpf_ringbuf_discard_dynptr(&ptr, 0);
462 
463 	return 0;
464 }
465 
466 /* A direct read at an offset should fail */
467 SEC("?raw_tp/sys_nanosleep")
468 int invalid_read2(void *ctx)
469 {
470 	struct bpf_dynptr ptr;
471 	char read_data[64];
472 
473 	get_map_val_dynptr(&ptr);
474 
475 	/* this should fail */
476 	bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 1, 0);
477 
478 	return 0;
479 }
480 
481 /* A direct read at an offset into the lower stack slot should fail */
482 SEC("?raw_tp/sys_nanosleep")
483 int invalid_read3(void *ctx)
484 {
485 	struct bpf_dynptr ptr1, ptr2;
486 
487 	bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &ptr1);
488 	bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &ptr2);
489 
490 	/* this should fail */
491 	memcpy(&val, (void *)&ptr1 + 8, sizeof(val));
492 
493 	bpf_ringbuf_discard_dynptr(&ptr1, 0);
494 	bpf_ringbuf_discard_dynptr(&ptr2, 0);
495 
496 	return 0;
497 }
498 
499 static int invalid_read4_callback(__u32 index, void *data)
500 {
501 	/* this should fail */
502 	val = *(__u32 *)data;
503 
504 	return 0;
505 }
506 
507 /* A direct read within a callback function should fail */
508 SEC("?raw_tp/sys_nanosleep")
509 int invalid_read4(void *ctx)
510 {
511 	struct bpf_dynptr ptr;
512 
513 	bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr);
514 
515 	bpf_loop(10, invalid_read4_callback, &ptr, 0);
516 
517 	bpf_ringbuf_submit_dynptr(&ptr, 0);
518 
519 	return 0;
520 }
521 
522 /* Initializing a dynptr on an offset should fail */
523 SEC("?raw_tp/sys_nanosleep")
524 int invalid_offset(void *ctx)
525 {
526 	struct bpf_dynptr ptr;
527 
528 	/* this should fail */
529 	bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr + 1);
530 
531 	bpf_ringbuf_discard_dynptr(&ptr, 0);
532 
533 	return 0;
534 }
535 
536 /* Can't release a dynptr twice */
537 SEC("?raw_tp/sys_nanosleep")
538 int release_twice(void *ctx)
539 {
540 	struct bpf_dynptr ptr;
541 
542 	bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &ptr);
543 
544 	bpf_ringbuf_discard_dynptr(&ptr, 0);
545 
546 	/* this second release should fail */
547 	bpf_ringbuf_discard_dynptr(&ptr, 0);
548 
549 	return 0;
550 }
551 
552 static int release_twice_callback_fn(__u32 index, void *data)
553 {
554 	/* this should fail */
555 	bpf_ringbuf_discard_dynptr(data, 0);
556 
557 	return 0;
558 }
559 
560 /* Test that releasing a dynptr twice, where one of the releases happens
561  * within a calback function, fails
562  */
563 SEC("?raw_tp/sys_nanosleep")
564 int release_twice_callback(void *ctx)
565 {
566 	struct bpf_dynptr ptr;
567 
568 	bpf_ringbuf_reserve_dynptr(&ringbuf, 32, 0, &ptr);
569 
570 	bpf_ringbuf_discard_dynptr(&ptr, 0);
571 
572 	bpf_loop(10, release_twice_callback_fn, &ptr, 0);
573 
574 	return 0;
575 }
576 
577 /* Reject unsupported local mem types for dynptr_from_mem API */
578 SEC("?raw_tp/sys_nanosleep")
579 int dynptr_from_mem_invalid_api(void *ctx)
580 {
581 	struct bpf_dynptr ptr;
582 	int x = 0;
583 
584 	/* this should fail */
585 	bpf_dynptr_from_mem(&x, sizeof(x), 0, &ptr);
586 
587 	return 0;
588 }
589