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
get_map_val_dynptr(struct bpf_dynptr * ptr)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")
ringbuf_missing_release1(void * ctx)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")
ringbuf_missing_release2(void * ctx)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
missing_release_callback_fn(__u32 index,void * data)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")
ringbuf_missing_release_callback(void * ctx)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")
ringbuf_release_uninit_dynptr(void * ctx)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")
use_after_invalid(void * ctx)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")
ringbuf_invalid_api(void * ctx)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")
add_dynptr_to_map1(void * ctx)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")
add_dynptr_to_map2(void * ctx)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")
data_slice_out_of_bounds_ringbuf(void * ctx)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")
data_slice_out_of_bounds_map_value(void * ctx)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")
data_slice_use_after_release1(void * ctx)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")
data_slice_use_after_release2(void * ctx)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")
data_slice_missing_null_check1(void * ctx)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")
data_slice_missing_null_check2(void * ctx)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")
invalid_helper1(void * ctx)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")
invalid_helper2(void * ctx)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")
invalid_write1(void * ctx)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")
invalid_write2(void * ctx)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")
invalid_write3(void * ctx)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
invalid_write4_callback(__u32 index,void * data)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")
invalid_write4(void * ctx)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")
global(void * ctx)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")
invalid_read1(void * ctx)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")
invalid_read2(void * ctx)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")
invalid_read3(void * ctx)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
invalid_read4_callback(__u32 index,void * data)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")
invalid_read4(void * ctx)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")
invalid_offset(void * ctx)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")
release_twice(void * ctx)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
release_twice_callback_fn(__u32 index,void * data)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")
release_twice_callback(void * ctx)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")
dynptr_from_mem_invalid_api(void * ctx)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