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")
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")
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")
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")
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")
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, 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, 0);
149 
150 	return 0;
151 }
152 
153 /* Can't call non-dynptr ringbuf APIs on a dynptr ringbuf sample */
154 SEC("?raw_tp")
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")
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")
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")
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")
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")
251 int data_slice_use_after_release1(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 can't be used after it has been released.
276  *
277  * This tests the case where the data slice tracks a dynptr (ptr2)
278  * that is at a non-zero offset from the frame pointer (ptr1 is at fp,
279  * ptr2 is at fp - 16).
280  */
281 SEC("?raw_tp")
282 int data_slice_use_after_release2(void *ctx)
283 {
284 	struct bpf_dynptr ptr1, ptr2;
285 	struct sample *sample;
286 
287 	bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr1);
288 	bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr2);
289 
290 	sample = bpf_dynptr_data(&ptr2, 0, sizeof(*sample));
291 	if (!sample)
292 		goto done;
293 
294 	sample->pid = 23;
295 
296 	bpf_ringbuf_submit_dynptr(&ptr2, 0);
297 
298 	/* this should fail */
299 	sample->pid = 23;
300 
301 	bpf_ringbuf_submit_dynptr(&ptr1, 0);
302 
303 	return 0;
304 
305 done:
306 	bpf_ringbuf_discard_dynptr(&ptr2, 0);
307 	bpf_ringbuf_discard_dynptr(&ptr1, 0);
308 	return 0;
309 }
310 
311 /* A data slice must be first checked for NULL */
312 SEC("?raw_tp")
313 int data_slice_missing_null_check1(void *ctx)
314 {
315 	struct bpf_dynptr ptr;
316 	void *data;
317 
318 	bpf_ringbuf_reserve_dynptr(&ringbuf, 8, 0, &ptr);
319 
320 	data  = bpf_dynptr_data(&ptr, 0, 8);
321 
322 	/* missing if (!data) check */
323 
324 	/* this should fail */
325 	*(__u8 *)data = 3;
326 
327 	bpf_ringbuf_submit_dynptr(&ptr, 0);
328 	return 0;
329 }
330 
331 /* A data slice can't be dereferenced if it wasn't checked for null */
332 SEC("?raw_tp")
333 int data_slice_missing_null_check2(void *ctx)
334 {
335 	struct bpf_dynptr ptr;
336 	__u64 *data1, *data2;
337 
338 	bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &ptr);
339 
340 	data1 = bpf_dynptr_data(&ptr, 0, 8);
341 	data2 = bpf_dynptr_data(&ptr, 0, 8);
342 	if (data1)
343 		/* this should fail */
344 		*data2 = 3;
345 
346 done:
347 	bpf_ringbuf_discard_dynptr(&ptr, 0);
348 	return 0;
349 }
350 
351 /* Can't pass in a dynptr as an arg to a helper function that doesn't take in a
352  * dynptr argument
353  */
354 SEC("?raw_tp")
355 int invalid_helper1(void *ctx)
356 {
357 	struct bpf_dynptr ptr;
358 
359 	get_map_val_dynptr(&ptr);
360 
361 	/* this should fail */
362 	bpf_strncmp((const char *)&ptr, sizeof(ptr), "hello!");
363 
364 	return 0;
365 }
366 
367 /* A dynptr can't be passed into a helper function at a non-zero offset */
368 SEC("?raw_tp")
369 int invalid_helper2(void *ctx)
370 {
371 	struct bpf_dynptr ptr;
372 	char read_data[64];
373 
374 	get_map_val_dynptr(&ptr);
375 
376 	/* this should fail */
377 	bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 8, 0, 0);
378 
379 	return 0;
380 }
381 
382 /* A bpf_dynptr is invalidated if it's been written into */
383 SEC("?raw_tp")
384 int invalid_write1(void *ctx)
385 {
386 	struct bpf_dynptr ptr;
387 	void *data;
388 	__u8 x = 0;
389 
390 	get_map_val_dynptr(&ptr);
391 
392 	memcpy(&ptr, &x, sizeof(x));
393 
394 	/* this should fail */
395 	data = bpf_dynptr_data(&ptr, 0, 1);
396 
397 	return 0;
398 }
399 
400 /*
401  * A bpf_dynptr can't be used as a dynptr if it has been written into at a fixed
402  * offset
403  */
404 SEC("?raw_tp")
405 int invalid_write2(void *ctx)
406 {
407 	struct bpf_dynptr ptr;
408 	char read_data[64];
409 	__u8 x = 0;
410 
411 	bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr);
412 
413 	memcpy((void *)&ptr + 8, &x, sizeof(x));
414 
415 	/* this should fail */
416 	bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
417 
418 	bpf_ringbuf_submit_dynptr(&ptr, 0);
419 
420 	return 0;
421 }
422 
423 /*
424  * A bpf_dynptr can't be used as a dynptr if it has been written into at a
425  * non-const offset
426  */
427 SEC("?raw_tp")
428 int invalid_write3(void *ctx)
429 {
430 	struct bpf_dynptr ptr;
431 	char stack_buf[16];
432 	unsigned long len;
433 	__u8 x = 0;
434 
435 	bpf_ringbuf_reserve_dynptr(&ringbuf, 8, 0, &ptr);
436 
437 	memcpy(stack_buf, &val, sizeof(val));
438 	len = stack_buf[0] & 0xf;
439 
440 	memcpy((void *)&ptr + len, &x, sizeof(x));
441 
442 	/* this should fail */
443 	bpf_ringbuf_submit_dynptr(&ptr, 0);
444 
445 	return 0;
446 }
447 
448 static int invalid_write4_callback(__u32 index, void *data)
449 {
450 	*(__u32 *)data = 123;
451 
452 	return 0;
453 }
454 
455 /* If the dynptr is written into in a callback function, it should
456  * be invalidated as a dynptr
457  */
458 SEC("?raw_tp")
459 int invalid_write4(void *ctx)
460 {
461 	struct bpf_dynptr ptr;
462 
463 	bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr);
464 
465 	bpf_loop(10, invalid_write4_callback, &ptr, 0);
466 
467 	/* this should fail */
468 	bpf_ringbuf_submit_dynptr(&ptr, 0);
469 
470 	return 0;
471 }
472 
473 /* A globally-defined bpf_dynptr can't be used (it must reside as a stack frame) */
474 struct bpf_dynptr global_dynptr;
475 SEC("?raw_tp")
476 int global(void *ctx)
477 {
478 	/* this should fail */
479 	bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &global_dynptr);
480 
481 	bpf_ringbuf_discard_dynptr(&global_dynptr, 0);
482 
483 	return 0;
484 }
485 
486 /* A direct read should fail */
487 SEC("?raw_tp")
488 int invalid_read1(void *ctx)
489 {
490 	struct bpf_dynptr ptr;
491 
492 	bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr);
493 
494 	/* this should fail */
495 	val = *(int *)&ptr;
496 
497 	bpf_ringbuf_discard_dynptr(&ptr, 0);
498 
499 	return 0;
500 }
501 
502 /* A direct read at an offset should fail */
503 SEC("?raw_tp")
504 int invalid_read2(void *ctx)
505 {
506 	struct bpf_dynptr ptr;
507 	char read_data[64];
508 
509 	get_map_val_dynptr(&ptr);
510 
511 	/* this should fail */
512 	bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 1, 0, 0);
513 
514 	return 0;
515 }
516 
517 /* A direct read at an offset into the lower stack slot should fail */
518 SEC("?raw_tp")
519 int invalid_read3(void *ctx)
520 {
521 	struct bpf_dynptr ptr1, ptr2;
522 
523 	bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &ptr1);
524 	bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &ptr2);
525 
526 	/* this should fail */
527 	memcpy(&val, (void *)&ptr1 + 8, sizeof(val));
528 
529 	bpf_ringbuf_discard_dynptr(&ptr1, 0);
530 	bpf_ringbuf_discard_dynptr(&ptr2, 0);
531 
532 	return 0;
533 }
534 
535 static int invalid_read4_callback(__u32 index, void *data)
536 {
537 	/* this should fail */
538 	val = *(__u32 *)data;
539 
540 	return 0;
541 }
542 
543 /* A direct read within a callback function should fail */
544 SEC("?raw_tp")
545 int invalid_read4(void *ctx)
546 {
547 	struct bpf_dynptr ptr;
548 
549 	bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr);
550 
551 	bpf_loop(10, invalid_read4_callback, &ptr, 0);
552 
553 	bpf_ringbuf_submit_dynptr(&ptr, 0);
554 
555 	return 0;
556 }
557 
558 /* Initializing a dynptr on an offset should fail */
559 SEC("?raw_tp")
560 int invalid_offset(void *ctx)
561 {
562 	struct bpf_dynptr ptr;
563 
564 	/* this should fail */
565 	bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr + 1);
566 
567 	bpf_ringbuf_discard_dynptr(&ptr, 0);
568 
569 	return 0;
570 }
571 
572 /* Can't release a dynptr twice */
573 SEC("?raw_tp")
574 int release_twice(void *ctx)
575 {
576 	struct bpf_dynptr ptr;
577 
578 	bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &ptr);
579 
580 	bpf_ringbuf_discard_dynptr(&ptr, 0);
581 
582 	/* this second release should fail */
583 	bpf_ringbuf_discard_dynptr(&ptr, 0);
584 
585 	return 0;
586 }
587 
588 static int release_twice_callback_fn(__u32 index, void *data)
589 {
590 	/* this should fail */
591 	bpf_ringbuf_discard_dynptr(data, 0);
592 
593 	return 0;
594 }
595 
596 /* Test that releasing a dynptr twice, where one of the releases happens
597  * within a calback function, fails
598  */
599 SEC("?raw_tp")
600 int release_twice_callback(void *ctx)
601 {
602 	struct bpf_dynptr ptr;
603 
604 	bpf_ringbuf_reserve_dynptr(&ringbuf, 32, 0, &ptr);
605 
606 	bpf_ringbuf_discard_dynptr(&ptr, 0);
607 
608 	bpf_loop(10, release_twice_callback_fn, &ptr, 0);
609 
610 	return 0;
611 }
612 
613 /* Reject unsupported local mem types for dynptr_from_mem API */
614 SEC("?raw_tp")
615 int dynptr_from_mem_invalid_api(void *ctx)
616 {
617 	struct bpf_dynptr ptr;
618 	int x = 0;
619 
620 	/* this should fail */
621 	bpf_dynptr_from_mem(&x, sizeof(x), 0, &ptr);
622 
623 	return 0;
624 }
625