1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2022 Facebook */
7 #include <bpf/bpf_helpers.h>
8 #include <bpf/bpf_tracing.h>
10 #include "bpf_kfuncs.h"
13 char _license[] SEC("license") = "GPL";
25 __uint(type, BPF_MAP_TYPE_RINGBUF);
26 __uint(max_entries, 4096);
27 } ringbuf SEC(".maps");
30 __uint(type, BPF_MAP_TYPE_ARRAY);
31 __uint(max_entries, 1);
34 } array_map SEC(".maps");
36 SEC("?tp/syscalls/sys_enter_nanosleep")
37 int test_read_write(void *ctx)
39 char write_data[64] = "hello there, world!!";
40 char read_data[64] = {};
41 struct bpf_dynptr ptr;
44 if (bpf_get_current_pid_tgid() >> 32 != pid)
47 bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(write_data), 0, &ptr);
49 /* Write data into the dynptr */
50 err = bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0);
52 /* Read the data that was written into the dynptr */
53 err = err ?: bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
55 /* Ensure the data we read matches the data we wrote */
56 for (i = 0; i < sizeof(read_data); i++) {
57 if (read_data[i] != write_data[i]) {
63 bpf_ringbuf_discard_dynptr(&ptr, 0);
67 SEC("?tp/syscalls/sys_enter_nanosleep")
68 int test_dynptr_data(void *ctx)
70 __u32 key = 0, val = 235, *map_val;
71 struct bpf_dynptr ptr;
75 map_val_size = sizeof(*map_val);
77 if (bpf_get_current_pid_tgid() >> 32 != pid)
80 bpf_map_update_elem(&array_map, &key, &val, 0);
82 map_val = bpf_map_lookup_elem(&array_map, &key);
88 bpf_dynptr_from_mem(map_val, map_val_size, 0, &ptr);
90 /* Try getting a data slice that is out of range */
91 data = bpf_dynptr_data(&ptr, map_val_size + 1, 1);
97 /* Try getting more bytes than available */
98 data = bpf_dynptr_data(&ptr, 0, map_val_size + 1);
104 data = bpf_dynptr_data(&ptr, 0, sizeof(__u32));
110 *(__u32 *)data = 999;
112 err = bpf_probe_read_kernel(&val, sizeof(val), data);
116 if (val != *(int *)data)
122 static int ringbuf_callback(__u32 index, void *data)
124 struct sample *sample;
126 struct bpf_dynptr *ptr = (struct bpf_dynptr *)data;
128 sample = bpf_dynptr_data(ptr, 0, sizeof(*sample));
132 sample->pid += index;
137 SEC("?tp/syscalls/sys_enter_nanosleep")
138 int test_ringbuf(void *ctx)
140 struct bpf_dynptr ptr;
141 struct sample *sample;
143 if (bpf_get_current_pid_tgid() >> 32 != pid)
148 /* check that you can reserve a dynamic size reservation */
149 err = bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr);
151 sample = err ? NULL : bpf_dynptr_data(&ptr, 0, sizeof(*sample));
159 /* Can pass dynptr to callback functions */
160 bpf_loop(10, ringbuf_callback, &ptr, 0);
162 if (sample->pid != 55)
166 bpf_ringbuf_discard_dynptr(&ptr, 0);
170 SEC("?cgroup_skb/egress")
171 int test_skb_readonly(struct __sk_buff *skb)
173 __u8 write_data[2] = {1, 2};
174 struct bpf_dynptr ptr;
177 if (bpf_dynptr_from_skb(skb, 0, &ptr)) {
182 /* since cgroup skbs are read only, writes should fail */
183 ret = bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0);
184 if (ret != -EINVAL) {
192 SEC("?cgroup_skb/egress")
193 int test_dynptr_skb_data(struct __sk_buff *skb)
195 struct bpf_dynptr ptr;
198 if (bpf_dynptr_from_skb(skb, 0, &ptr)) {
203 /* This should return NULL. Must use bpf_dynptr_slice API */
204 data = bpf_dynptr_data(&ptr, 0, 1);
213 SEC("tp/syscalls/sys_enter_nanosleep")
214 int test_adjust(void *ctx)
216 struct bpf_dynptr ptr;
221 if (bpf_get_current_pid_tgid() >> 32 != pid)
224 err = bpf_ringbuf_reserve_dynptr(&ringbuf, bytes, 0, &ptr);
230 if (bpf_dynptr_size(&ptr) != bytes) {
235 /* Advance the dynptr by off */
236 err = bpf_dynptr_adjust(&ptr, off, bpf_dynptr_size(&ptr));
242 if (bpf_dynptr_size(&ptr) != bytes - off) {
247 /* Trim the dynptr */
248 err = bpf_dynptr_adjust(&ptr, off, 15);
254 /* Check that the size was adjusted correctly */
255 if (bpf_dynptr_size(&ptr) != trim - off) {
261 bpf_ringbuf_discard_dynptr(&ptr, 0);
265 SEC("tp/syscalls/sys_enter_nanosleep")
266 int test_adjust_err(void *ctx)
268 char write_data[45] = "hello there, world!!";
269 struct bpf_dynptr ptr;
273 if (bpf_get_current_pid_tgid() >> 32 != pid)
276 if (bpf_ringbuf_reserve_dynptr(&ringbuf, size, 0, &ptr)) {
281 /* Check that start can't be greater than end */
282 if (bpf_dynptr_adjust(&ptr, 5, 1) != -EINVAL) {
287 /* Check that start can't be greater than size */
288 if (bpf_dynptr_adjust(&ptr, size + 1, size + 1) != -ERANGE) {
293 /* Check that end can't be greater than size */
294 if (bpf_dynptr_adjust(&ptr, 0, size + 1) != -ERANGE) {
299 if (bpf_dynptr_adjust(&ptr, off, size)) {
304 /* Check that you can't write more bytes than available into the dynptr
305 * after you've adjusted it
307 if (bpf_dynptr_write(&ptr, 0, &write_data, sizeof(write_data), 0) != -E2BIG) {
312 /* Check that even after adjusting, submitting/discarding
313 * a ringbuf dynptr works
315 bpf_ringbuf_submit_dynptr(&ptr, 0);
319 bpf_ringbuf_discard_dynptr(&ptr, 0);
323 SEC("tp/syscalls/sys_enter_nanosleep")
324 int test_zero_size_dynptr(void *ctx)
326 char write_data = 'x', read_data;
327 struct bpf_dynptr ptr;
330 if (bpf_get_current_pid_tgid() >> 32 != pid)
333 if (bpf_ringbuf_reserve_dynptr(&ringbuf, size, 0, &ptr)) {
338 /* After this, the dynptr has a size of 0 */
339 if (bpf_dynptr_adjust(&ptr, size, size)) {
344 /* Test that reading + writing non-zero bytes is not ok */
345 if (bpf_dynptr_read(&read_data, sizeof(read_data), &ptr, 0, 0) != -E2BIG) {
350 if (bpf_dynptr_write(&ptr, 0, &write_data, sizeof(write_data), 0) != -E2BIG) {
355 /* Test that reading + writing 0 bytes from a 0-size dynptr is ok */
356 if (bpf_dynptr_read(&read_data, 0, &ptr, 0, 0)) {
361 if (bpf_dynptr_write(&ptr, 0, &write_data, 0, 0)) {
369 bpf_ringbuf_discard_dynptr(&ptr, 0);
373 SEC("tp/syscalls/sys_enter_nanosleep")
374 int test_dynptr_is_null(void *ctx)
376 struct bpf_dynptr ptr1;
377 struct bpf_dynptr ptr2;
380 if (bpf_get_current_pid_tgid() >> 32 != pid)
383 /* Pass in invalid flags, get back an invalid dynptr */
384 if (bpf_ringbuf_reserve_dynptr(&ringbuf, size, 123, &ptr1) != -EINVAL) {
389 /* Test that the invalid dynptr is null */
390 if (!bpf_dynptr_is_null(&ptr1)) {
395 /* Get a valid dynptr */
396 if (bpf_ringbuf_reserve_dynptr(&ringbuf, size, 0, &ptr2)) {
401 /* Test that the valid dynptr is not null */
402 if (bpf_dynptr_is_null(&ptr2)) {
408 bpf_ringbuf_discard_dynptr(&ptr2, 0);
410 bpf_ringbuf_discard_dynptr(&ptr1, 0);
414 SEC("cgroup_skb/egress")
415 int test_dynptr_is_rdonly(struct __sk_buff *skb)
417 struct bpf_dynptr ptr1;
418 struct bpf_dynptr ptr2;
419 struct bpf_dynptr ptr3;
421 /* Pass in invalid flags, get back an invalid dynptr */
422 if (bpf_dynptr_from_skb(skb, 123, &ptr1) != -EINVAL) {
427 /* Test that an invalid dynptr is_rdonly returns false */
428 if (bpf_dynptr_is_rdonly(&ptr1)) {
433 /* Get a read-only dynptr */
434 if (bpf_dynptr_from_skb(skb, 0, &ptr2)) {
439 /* Test that the dynptr is read-only */
440 if (!bpf_dynptr_is_rdonly(&ptr2)) {
445 /* Get a read-writeable dynptr */
446 if (bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr3)) {
451 /* Test that the dynptr is read-only */
452 if (bpf_dynptr_is_rdonly(&ptr3)) {
458 bpf_ringbuf_discard_dynptr(&ptr3, 0);
462 SEC("cgroup_skb/egress")
463 int test_dynptr_clone(struct __sk_buff *skb)
465 struct bpf_dynptr ptr1;
466 struct bpf_dynptr ptr2;
470 if (bpf_dynptr_from_skb(skb, 0, &ptr1)) {
475 if (bpf_dynptr_adjust(&ptr1, off, bpf_dynptr_size(&ptr1))) {
480 /* Clone the dynptr */
481 if (bpf_dynptr_clone(&ptr1, &ptr2)) {
486 size = bpf_dynptr_size(&ptr1);
488 /* Check that the clone has the same size and rd-only */
489 if (bpf_dynptr_size(&ptr2) != size) {
494 if (bpf_dynptr_is_rdonly(&ptr2) != bpf_dynptr_is_rdonly(&ptr1)) {
499 /* Advance and trim the original dynptr */
500 bpf_dynptr_adjust(&ptr1, 5, 5);
502 /* Check that only original dynptr was affected, and the clone wasn't */
503 if (bpf_dynptr_size(&ptr2) != size) {
511 SEC("?cgroup_skb/egress")
512 int test_dynptr_skb_no_buff(struct __sk_buff *skb)
514 struct bpf_dynptr ptr;
517 if (bpf_dynptr_from_skb(skb, 0, &ptr)) {
522 /* This may return NULL. SKB may require a buffer */
523 data = bpf_dynptr_slice(&ptr, 0, NULL, 1);
528 SEC("?cgroup_skb/egress")
529 int test_dynptr_skb_strcmp(struct __sk_buff *skb)
531 struct bpf_dynptr ptr;
534 if (bpf_dynptr_from_skb(skb, 0, &ptr)) {
539 /* This may return NULL. SKB may require a buffer */
540 data = bpf_dynptr_slice(&ptr, 0, NULL, 10);
542 bpf_strncmp(data, 10, "foo");
549 SEC("tp_btf/kfree_skb")
550 int BPF_PROG(test_dynptr_skb_tp_btf, void *skb, void *location)
552 __u8 write_data[2] = {1, 2};
553 struct bpf_dynptr ptr;
556 if (bpf_dynptr_from_skb(skb, 0, &ptr)) {
561 /* since tp_btf skbs are read only, writes should fail */
562 ret = bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0);
563 if (ret != -EINVAL) {