1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2022 Facebook */
7 #include <bpf/bpf_helpers.h>
10 char _license[] SEC("license") = "GPL";
14 struct bpf_dynptr ptr;
18 __uint(type, BPF_MAP_TYPE_ARRAY);
19 __uint(max_entries, 1);
21 __type(value, struct bpf_dynptr);
22 } array_map1 SEC(".maps");
25 __uint(type, BPF_MAP_TYPE_ARRAY);
26 __uint(max_entries, 1);
28 __type(value, struct test_info);
29 } array_map2 SEC(".maps");
32 __uint(type, BPF_MAP_TYPE_ARRAY);
33 __uint(max_entries, 1);
36 } array_map3 SEC(".maps");
45 __uint(type, BPF_MAP_TYPE_RINGBUF);
46 } ringbuf SEC(".maps");
50 static int get_map_val_dynptr(struct bpf_dynptr *ptr)
52 __u32 key = 0, *map_val;
54 bpf_map_update_elem(&array_map3, &key, &val, 0);
56 map_val = bpf_map_lookup_elem(&array_map3, &key);
60 bpf_dynptr_from_mem(map_val, sizeof(*map_val), 0, ptr);
65 /* Every bpf_ringbuf_reserve_dynptr call must have a corresponding
66 * bpf_ringbuf_submit/discard_dynptr call
68 SEC("?raw_tp/sys_nanosleep")
69 int ringbuf_missing_release1(void *ctx)
71 struct bpf_dynptr ptr;
73 bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr);
75 /* missing a call to bpf_ringbuf_discard/submit_dynptr */
80 SEC("?raw_tp/sys_nanosleep")
81 int ringbuf_missing_release2(void *ctx)
83 struct bpf_dynptr ptr1, ptr2;
84 struct sample *sample;
86 bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr1);
87 bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr2);
89 sample = bpf_dynptr_data(&ptr1, 0, sizeof(*sample));
91 bpf_ringbuf_discard_dynptr(&ptr1, 0);
92 bpf_ringbuf_discard_dynptr(&ptr2, 0);
96 bpf_ringbuf_submit_dynptr(&ptr1, 0);
98 /* missing a call to bpf_ringbuf_discard/submit_dynptr on ptr2 */
103 static int missing_release_callback_fn(__u32 index, void *data)
105 struct bpf_dynptr ptr;
107 bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr);
109 /* missing a call to bpf_ringbuf_discard/submit_dynptr */
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)
118 bpf_loop(10, missing_release_callback_fn, NULL, 0);
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)
126 struct bpf_dynptr ptr;
128 /* this should fail */
129 bpf_ringbuf_submit_dynptr(&ptr, 0);
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)
138 struct bpf_dynptr ptr;
141 bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(read_data), 0, &ptr);
143 bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
145 bpf_ringbuf_submit_dynptr(&ptr, 0);
147 /* this should fail */
148 bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
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)
157 struct bpf_dynptr ptr;
158 struct sample *sample;
160 bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr);
161 sample = bpf_dynptr_data(&ptr, 0, sizeof(*sample));
167 /* invalid API use. need to use dynptr API to submit/discard */
168 bpf_ringbuf_submit(sample, 0);
171 bpf_ringbuf_discard_dynptr(&ptr, 0);
175 /* Can't add a dynptr to a map */
176 SEC("?raw_tp/sys_nanosleep")
177 int add_dynptr_to_map1(void *ctx)
179 struct bpf_dynptr ptr;
182 bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr);
184 /* this should fail */
185 bpf_map_update_elem(&array_map1, &key, &ptr, 0);
187 bpf_ringbuf_submit_dynptr(&ptr, 0);
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)
199 bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &x.ptr);
201 /* this should fail */
202 bpf_map_update_elem(&array_map2, &key, &x, 0);
204 bpf_ringbuf_submit_dynptr(&x.ptr, 0);
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)
213 struct bpf_dynptr ptr;
216 bpf_ringbuf_reserve_dynptr(&ringbuf, 8, 0, &ptr);
218 data = bpf_dynptr_data(&ptr, 0, 8);
222 /* can't index out of bounds of the data slice */
223 val = *((char *)data + 8);
226 bpf_ringbuf_submit_dynptr(&ptr, 0);
230 SEC("?raw_tp/sys_nanosleep")
231 int data_slice_out_of_bounds_map_value(void *ctx)
233 __u32 key = 0, map_val;
234 struct bpf_dynptr ptr;
237 get_map_val_dynptr(&ptr);
239 data = bpf_dynptr_data(&ptr, 0, sizeof(map_val));
243 /* can't index out of bounds of the data slice */
244 val = *((char *)data + (sizeof(map_val) + 1));
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)
253 struct bpf_dynptr ptr;
254 struct sample *sample;
256 bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr);
257 sample = bpf_dynptr_data(&ptr, 0, sizeof(*sample));
263 bpf_ringbuf_submit_dynptr(&ptr, 0);
265 /* this should fail */
271 bpf_ringbuf_discard_dynptr(&ptr, 0);
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)
279 struct bpf_dynptr ptr;
282 bpf_ringbuf_reserve_dynptr(&ringbuf, 8, 0, &ptr);
284 data = bpf_dynptr_data(&ptr, 0, 8);
286 /* missing if (!data) check */
288 /* this should fail */
291 bpf_ringbuf_submit_dynptr(&ptr, 0);
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)
299 struct bpf_dynptr ptr;
300 __u64 *data1, *data2;
302 bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &ptr);
304 data1 = bpf_dynptr_data(&ptr, 0, 8);
305 data2 = bpf_dynptr_data(&ptr, 0, 8);
307 /* this should fail */
311 bpf_ringbuf_discard_dynptr(&ptr, 0);
315 /* Can't pass in a dynptr as an arg to a helper function that doesn't take in a
318 SEC("?raw_tp/sys_nanosleep")
319 int invalid_helper1(void *ctx)
321 struct bpf_dynptr ptr;
323 get_map_val_dynptr(&ptr);
325 /* this should fail */
326 bpf_strncmp((const char *)&ptr, sizeof(ptr), "hello!");
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)
335 struct bpf_dynptr ptr;
338 get_map_val_dynptr(&ptr);
340 /* this should fail */
341 bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 8, 0, 0);
346 /* A bpf_dynptr is invalidated if it's been written into */
347 SEC("?raw_tp/sys_nanosleep")
348 int invalid_write1(void *ctx)
350 struct bpf_dynptr ptr;
354 get_map_val_dynptr(&ptr);
356 memcpy(&ptr, &x, sizeof(x));
358 /* this should fail */
359 data = bpf_dynptr_data(&ptr, 0, 1);
365 * A bpf_dynptr can't be used as a dynptr if it has been written into at a fixed
368 SEC("?raw_tp/sys_nanosleep")
369 int invalid_write2(void *ctx)
371 struct bpf_dynptr ptr;
375 bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr);
377 memcpy((void *)&ptr + 8, &x, sizeof(x));
379 /* this should fail */
380 bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
382 bpf_ringbuf_submit_dynptr(&ptr, 0);
388 * A bpf_dynptr can't be used as a dynptr if it has been written into at a
391 SEC("?raw_tp/sys_nanosleep")
392 int invalid_write3(void *ctx)
394 struct bpf_dynptr ptr;
399 bpf_ringbuf_reserve_dynptr(&ringbuf, 8, 0, &ptr);
401 memcpy(stack_buf, &val, sizeof(val));
402 len = stack_buf[0] & 0xf;
404 memcpy((void *)&ptr + len, &x, sizeof(x));
406 /* this should fail */
407 bpf_ringbuf_submit_dynptr(&ptr, 0);
412 static int invalid_write4_callback(__u32 index, void *data)
414 *(__u32 *)data = 123;
419 /* If the dynptr is written into in a callback function, it should
420 * be invalidated as a dynptr
422 SEC("?raw_tp/sys_nanosleep")
423 int invalid_write4(void *ctx)
425 struct bpf_dynptr ptr;
427 bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr);
429 bpf_loop(10, invalid_write4_callback, &ptr, 0);
431 /* this should fail */
432 bpf_ringbuf_submit_dynptr(&ptr, 0);
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)
442 /* this should fail */
443 bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &global_dynptr);
445 bpf_ringbuf_discard_dynptr(&global_dynptr, 0);
450 /* A direct read should fail */
451 SEC("?raw_tp/sys_nanosleep")
452 int invalid_read1(void *ctx)
454 struct bpf_dynptr ptr;
456 bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr);
458 /* this should fail */
461 bpf_ringbuf_discard_dynptr(&ptr, 0);
466 /* A direct read at an offset should fail */
467 SEC("?raw_tp/sys_nanosleep")
468 int invalid_read2(void *ctx)
470 struct bpf_dynptr ptr;
473 get_map_val_dynptr(&ptr);
475 /* this should fail */
476 bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 1, 0, 0);
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)
485 struct bpf_dynptr ptr1, ptr2;
487 bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &ptr1);
488 bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &ptr2);
490 /* this should fail */
491 memcpy(&val, (void *)&ptr1 + 8, sizeof(val));
493 bpf_ringbuf_discard_dynptr(&ptr1, 0);
494 bpf_ringbuf_discard_dynptr(&ptr2, 0);
499 static int invalid_read4_callback(__u32 index, void *data)
501 /* this should fail */
502 val = *(__u32 *)data;
507 /* A direct read within a callback function should fail */
508 SEC("?raw_tp/sys_nanosleep")
509 int invalid_read4(void *ctx)
511 struct bpf_dynptr ptr;
513 bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr);
515 bpf_loop(10, invalid_read4_callback, &ptr, 0);
517 bpf_ringbuf_submit_dynptr(&ptr, 0);
522 /* Initializing a dynptr on an offset should fail */
523 SEC("?raw_tp/sys_nanosleep")
524 int invalid_offset(void *ctx)
526 struct bpf_dynptr ptr;
528 /* this should fail */
529 bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr + 1);
531 bpf_ringbuf_discard_dynptr(&ptr, 0);
536 /* Can't release a dynptr twice */
537 SEC("?raw_tp/sys_nanosleep")
538 int release_twice(void *ctx)
540 struct bpf_dynptr ptr;
542 bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &ptr);
544 bpf_ringbuf_discard_dynptr(&ptr, 0);
546 /* this second release should fail */
547 bpf_ringbuf_discard_dynptr(&ptr, 0);
552 static int release_twice_callback_fn(__u32 index, void *data)
554 /* this should fail */
555 bpf_ringbuf_discard_dynptr(data, 0);
560 /* Test that releasing a dynptr twice, where one of the releases happens
561 * within a calback function, fails
563 SEC("?raw_tp/sys_nanosleep")
564 int release_twice_callback(void *ctx)
566 struct bpf_dynptr ptr;
568 bpf_ringbuf_reserve_dynptr(&ringbuf, 32, 0, &ptr);
570 bpf_ringbuf_discard_dynptr(&ptr, 0);
572 bpf_loop(10, release_twice_callback_fn, &ptr, 0);
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)
581 struct bpf_dynptr ptr;
584 /* this should fail */
585 bpf_dynptr_from_mem(&x, sizeof(x), 0, &ptr);