Loading...
1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2022 Facebook */
3
4#include <string.h>
5#include <stdbool.h>
6#include <linux/bpf.h>
7#include <bpf/bpf_helpers.h>
8#include <bpf/bpf_tracing.h>
9#include "bpf_misc.h"
10#include "bpf_kfuncs.h"
11#include "errno.h"
12
13char _license[] SEC("license") = "GPL";
14
15int pid, err, val;
16
17struct sample {
18 int pid;
19 int seq;
20 long value;
21 char comm[16];
22};
23
24struct {
25 __uint(type, BPF_MAP_TYPE_RINGBUF);
26 __uint(max_entries, 4096);
27} ringbuf SEC(".maps");
28
29struct {
30 __uint(type, BPF_MAP_TYPE_ARRAY);
31 __uint(max_entries, 1);
32 __type(key, __u32);
33 __type(value, __u32);
34} array_map SEC(".maps");
35
36SEC("?tp/syscalls/sys_enter_nanosleep")
37int test_read_write(void *ctx)
38{
39 char write_data[64] = "hello there, world!!";
40 char read_data[64] = {};
41 struct bpf_dynptr ptr;
42 int i;
43
44 if (bpf_get_current_pid_tgid() >> 32 != pid)
45 return 0;
46
47 bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(write_data), 0, &ptr);
48
49 /* Write data into the dynptr */
50 err = bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0);
51
52 /* Read the data that was written into the dynptr */
53 err = err ?: bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
54
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]) {
58 err = 1;
59 break;
60 }
61 }
62
63 bpf_ringbuf_discard_dynptr(&ptr, 0);
64 return 0;
65}
66
67SEC("?tp/syscalls/sys_enter_nanosleep")
68int test_dynptr_data(void *ctx)
69{
70 __u32 key = 0, val = 235, *map_val;
71 struct bpf_dynptr ptr;
72 __u32 map_val_size;
73 void *data;
74
75 map_val_size = sizeof(*map_val);
76
77 if (bpf_get_current_pid_tgid() >> 32 != pid)
78 return 0;
79
80 bpf_map_update_elem(&array_map, &key, &val, 0);
81
82 map_val = bpf_map_lookup_elem(&array_map, &key);
83 if (!map_val) {
84 err = 1;
85 return 0;
86 }
87
88 bpf_dynptr_from_mem(map_val, map_val_size, 0, &ptr);
89
90 /* Try getting a data slice that is out of range */
91 data = bpf_dynptr_data(&ptr, map_val_size + 1, 1);
92 if (data) {
93 err = 2;
94 return 0;
95 }
96
97 /* Try getting more bytes than available */
98 data = bpf_dynptr_data(&ptr, 0, map_val_size + 1);
99 if (data) {
100 err = 3;
101 return 0;
102 }
103
104 data = bpf_dynptr_data(&ptr, 0, sizeof(__u32));
105 if (!data) {
106 err = 4;
107 return 0;
108 }
109
110 *(__u32 *)data = 999;
111
112 err = bpf_probe_read_kernel(&val, sizeof(val), data);
113 if (err)
114 return 0;
115
116 if (val != *(int *)data)
117 err = 5;
118
119 return 0;
120}
121
122static int ringbuf_callback(__u32 index, void *data)
123{
124 struct sample *sample;
125
126 struct bpf_dynptr *ptr = (struct bpf_dynptr *)data;
127
128 sample = bpf_dynptr_data(ptr, 0, sizeof(*sample));
129 if (!sample)
130 err = 2;
131 else
132 sample->pid += index;
133
134 return 0;
135}
136
137SEC("?tp/syscalls/sys_enter_nanosleep")
138int test_ringbuf(void *ctx)
139{
140 struct bpf_dynptr ptr;
141 struct sample *sample;
142
143 if (bpf_get_current_pid_tgid() >> 32 != pid)
144 return 0;
145
146 val = 100;
147
148 /* check that you can reserve a dynamic size reservation */
149 err = bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr);
150
151 sample = err ? NULL : bpf_dynptr_data(&ptr, 0, sizeof(*sample));
152 if (!sample) {
153 err = 1;
154 goto done;
155 }
156
157 sample->pid = 10;
158
159 /* Can pass dynptr to callback functions */
160 bpf_loop(10, ringbuf_callback, &ptr, 0);
161
162 if (sample->pid != 55)
163 err = 2;
164
165done:
166 bpf_ringbuf_discard_dynptr(&ptr, 0);
167 return 0;
168}
169
170SEC("?cgroup_skb/egress")
171int test_skb_readonly(struct __sk_buff *skb)
172{
173 __u8 write_data[2] = {1, 2};
174 struct bpf_dynptr ptr;
175 int ret;
176
177 if (bpf_dynptr_from_skb(skb, 0, &ptr)) {
178 err = 1;
179 return 1;
180 }
181
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) {
185 err = 2;
186 return 1;
187 }
188
189 return 1;
190}
191
192SEC("?cgroup_skb/egress")
193int test_dynptr_skb_data(struct __sk_buff *skb)
194{
195 struct bpf_dynptr ptr;
196 __u64 *data;
197
198 if (bpf_dynptr_from_skb(skb, 0, &ptr)) {
199 err = 1;
200 return 1;
201 }
202
203 /* This should return NULL. Must use bpf_dynptr_slice API */
204 data = bpf_dynptr_data(&ptr, 0, 1);
205 if (data) {
206 err = 2;
207 return 1;
208 }
209
210 return 1;
211}
212
213SEC("tp/syscalls/sys_enter_nanosleep")
214int test_adjust(void *ctx)
215{
216 struct bpf_dynptr ptr;
217 __u32 bytes = 64;
218 __u32 off = 10;
219 __u32 trim = 15;
220
221 if (bpf_get_current_pid_tgid() >> 32 != pid)
222 return 0;
223
224 err = bpf_ringbuf_reserve_dynptr(&ringbuf, bytes, 0, &ptr);
225 if (err) {
226 err = 1;
227 goto done;
228 }
229
230 if (bpf_dynptr_size(&ptr) != bytes) {
231 err = 2;
232 goto done;
233 }
234
235 /* Advance the dynptr by off */
236 err = bpf_dynptr_adjust(&ptr, off, bpf_dynptr_size(&ptr));
237 if (err) {
238 err = 3;
239 goto done;
240 }
241
242 if (bpf_dynptr_size(&ptr) != bytes - off) {
243 err = 4;
244 goto done;
245 }
246
247 /* Trim the dynptr */
248 err = bpf_dynptr_adjust(&ptr, off, 15);
249 if (err) {
250 err = 5;
251 goto done;
252 }
253
254 /* Check that the size was adjusted correctly */
255 if (bpf_dynptr_size(&ptr) != trim - off) {
256 err = 6;
257 goto done;
258 }
259
260done:
261 bpf_ringbuf_discard_dynptr(&ptr, 0);
262 return 0;
263}
264
265SEC("tp/syscalls/sys_enter_nanosleep")
266int test_adjust_err(void *ctx)
267{
268 char write_data[45] = "hello there, world!!";
269 struct bpf_dynptr ptr;
270 __u32 size = 64;
271 __u32 off = 20;
272
273 if (bpf_get_current_pid_tgid() >> 32 != pid)
274 return 0;
275
276 if (bpf_ringbuf_reserve_dynptr(&ringbuf, size, 0, &ptr)) {
277 err = 1;
278 goto done;
279 }
280
281 /* Check that start can't be greater than end */
282 if (bpf_dynptr_adjust(&ptr, 5, 1) != -EINVAL) {
283 err = 2;
284 goto done;
285 }
286
287 /* Check that start can't be greater than size */
288 if (bpf_dynptr_adjust(&ptr, size + 1, size + 1) != -ERANGE) {
289 err = 3;
290 goto done;
291 }
292
293 /* Check that end can't be greater than size */
294 if (bpf_dynptr_adjust(&ptr, 0, size + 1) != -ERANGE) {
295 err = 4;
296 goto done;
297 }
298
299 if (bpf_dynptr_adjust(&ptr, off, size)) {
300 err = 5;
301 goto done;
302 }
303
304 /* Check that you can't write more bytes than available into the dynptr
305 * after you've adjusted it
306 */
307 if (bpf_dynptr_write(&ptr, 0, &write_data, sizeof(write_data), 0) != -E2BIG) {
308 err = 6;
309 goto done;
310 }
311
312 /* Check that even after adjusting, submitting/discarding
313 * a ringbuf dynptr works
314 */
315 bpf_ringbuf_submit_dynptr(&ptr, 0);
316 return 0;
317
318done:
319 bpf_ringbuf_discard_dynptr(&ptr, 0);
320 return 0;
321}
322
323SEC("tp/syscalls/sys_enter_nanosleep")
324int test_zero_size_dynptr(void *ctx)
325{
326 char write_data = 'x', read_data;
327 struct bpf_dynptr ptr;
328 __u32 size = 64;
329
330 if (bpf_get_current_pid_tgid() >> 32 != pid)
331 return 0;
332
333 if (bpf_ringbuf_reserve_dynptr(&ringbuf, size, 0, &ptr)) {
334 err = 1;
335 goto done;
336 }
337
338 /* After this, the dynptr has a size of 0 */
339 if (bpf_dynptr_adjust(&ptr, size, size)) {
340 err = 2;
341 goto done;
342 }
343
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) {
346 err = 3;
347 goto done;
348 }
349
350 if (bpf_dynptr_write(&ptr, 0, &write_data, sizeof(write_data), 0) != -E2BIG) {
351 err = 4;
352 goto done;
353 }
354
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)) {
357 err = 5;
358 goto done;
359 }
360
361 if (bpf_dynptr_write(&ptr, 0, &write_data, 0, 0)) {
362 err = 6;
363 goto done;
364 }
365
366 err = 0;
367
368done:
369 bpf_ringbuf_discard_dynptr(&ptr, 0);
370 return 0;
371}
372
373SEC("tp/syscalls/sys_enter_nanosleep")
374int test_dynptr_is_null(void *ctx)
375{
376 struct bpf_dynptr ptr1;
377 struct bpf_dynptr ptr2;
378 __u64 size = 4;
379
380 if (bpf_get_current_pid_tgid() >> 32 != pid)
381 return 0;
382
383 /* Pass in invalid flags, get back an invalid dynptr */
384 if (bpf_ringbuf_reserve_dynptr(&ringbuf, size, 123, &ptr1) != -EINVAL) {
385 err = 1;
386 goto exit_early;
387 }
388
389 /* Test that the invalid dynptr is null */
390 if (!bpf_dynptr_is_null(&ptr1)) {
391 err = 2;
392 goto exit_early;
393 }
394
395 /* Get a valid dynptr */
396 if (bpf_ringbuf_reserve_dynptr(&ringbuf, size, 0, &ptr2)) {
397 err = 3;
398 goto exit;
399 }
400
401 /* Test that the valid dynptr is not null */
402 if (bpf_dynptr_is_null(&ptr2)) {
403 err = 4;
404 goto exit;
405 }
406
407exit:
408 bpf_ringbuf_discard_dynptr(&ptr2, 0);
409exit_early:
410 bpf_ringbuf_discard_dynptr(&ptr1, 0);
411 return 0;
412}
413
414SEC("cgroup_skb/egress")
415int test_dynptr_is_rdonly(struct __sk_buff *skb)
416{
417 struct bpf_dynptr ptr1;
418 struct bpf_dynptr ptr2;
419 struct bpf_dynptr ptr3;
420
421 /* Pass in invalid flags, get back an invalid dynptr */
422 if (bpf_dynptr_from_skb(skb, 123, &ptr1) != -EINVAL) {
423 err = 1;
424 return 0;
425 }
426
427 /* Test that an invalid dynptr is_rdonly returns false */
428 if (bpf_dynptr_is_rdonly(&ptr1)) {
429 err = 2;
430 return 0;
431 }
432
433 /* Get a read-only dynptr */
434 if (bpf_dynptr_from_skb(skb, 0, &ptr2)) {
435 err = 3;
436 return 0;
437 }
438
439 /* Test that the dynptr is read-only */
440 if (!bpf_dynptr_is_rdonly(&ptr2)) {
441 err = 4;
442 return 0;
443 }
444
445 /* Get a read-writeable dynptr */
446 if (bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr3)) {
447 err = 5;
448 goto done;
449 }
450
451 /* Test that the dynptr is read-only */
452 if (bpf_dynptr_is_rdonly(&ptr3)) {
453 err = 6;
454 goto done;
455 }
456
457done:
458 bpf_ringbuf_discard_dynptr(&ptr3, 0);
459 return 0;
460}
461
462SEC("cgroup_skb/egress")
463int test_dynptr_clone(struct __sk_buff *skb)
464{
465 struct bpf_dynptr ptr1;
466 struct bpf_dynptr ptr2;
467 __u32 off = 2, size;
468
469 /* Get a dynptr */
470 if (bpf_dynptr_from_skb(skb, 0, &ptr1)) {
471 err = 1;
472 return 0;
473 }
474
475 if (bpf_dynptr_adjust(&ptr1, off, bpf_dynptr_size(&ptr1))) {
476 err = 2;
477 return 0;
478 }
479
480 /* Clone the dynptr */
481 if (bpf_dynptr_clone(&ptr1, &ptr2)) {
482 err = 3;
483 return 0;
484 }
485
486 size = bpf_dynptr_size(&ptr1);
487
488 /* Check that the clone has the same size and rd-only */
489 if (bpf_dynptr_size(&ptr2) != size) {
490 err = 4;
491 return 0;
492 }
493
494 if (bpf_dynptr_is_rdonly(&ptr2) != bpf_dynptr_is_rdonly(&ptr1)) {
495 err = 5;
496 return 0;
497 }
498
499 /* Advance and trim the original dynptr */
500 bpf_dynptr_adjust(&ptr1, 5, 5);
501
502 /* Check that only original dynptr was affected, and the clone wasn't */
503 if (bpf_dynptr_size(&ptr2) != size) {
504 err = 6;
505 return 0;
506 }
507
508 return 0;
509}
510
511SEC("?cgroup_skb/egress")
512int test_dynptr_skb_no_buff(struct __sk_buff *skb)
513{
514 struct bpf_dynptr ptr;
515 __u64 *data;
516
517 if (bpf_dynptr_from_skb(skb, 0, &ptr)) {
518 err = 1;
519 return 1;
520 }
521
522 /* This may return NULL. SKB may require a buffer */
523 data = bpf_dynptr_slice(&ptr, 0, NULL, 1);
524
525 return !!data;
526}
527
528SEC("?cgroup_skb/egress")
529int test_dynptr_skb_strcmp(struct __sk_buff *skb)
530{
531 struct bpf_dynptr ptr;
532 char *data;
533
534 if (bpf_dynptr_from_skb(skb, 0, &ptr)) {
535 err = 1;
536 return 1;
537 }
538
539 /* This may return NULL. SKB may require a buffer */
540 data = bpf_dynptr_slice(&ptr, 0, NULL, 10);
541 if (data) {
542 bpf_strncmp(data, 10, "foo");
543 return 1;
544 }
545
546 return 1;
547}
548
549SEC("tp_btf/kfree_skb")
550int BPF_PROG(test_dynptr_skb_tp_btf, void *skb, void *location)
551{
552 __u8 write_data[2] = {1, 2};
553 struct bpf_dynptr ptr;
554 int ret;
555
556 if (bpf_dynptr_from_skb(skb, 0, &ptr)) {
557 err = 1;
558 return 1;
559 }
560
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) {
564 err = 2;
565 return 1;
566 }
567
568 return 1;
569}
1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2022 Facebook */
3
4#include <string.h>
5#include <stdbool.h>
6#include <linux/bpf.h>
7#include <bpf/bpf_helpers.h>
8#include "bpf_misc.h"
9#include "bpf_kfuncs.h"
10#include "errno.h"
11
12char _license[] SEC("license") = "GPL";
13
14int pid, err, val;
15
16struct sample {
17 int pid;
18 int seq;
19 long value;
20 char comm[16];
21};
22
23struct {
24 __uint(type, BPF_MAP_TYPE_RINGBUF);
25 __uint(max_entries, 4096);
26} ringbuf SEC(".maps");
27
28struct {
29 __uint(type, BPF_MAP_TYPE_ARRAY);
30 __uint(max_entries, 1);
31 __type(key, __u32);
32 __type(value, __u32);
33} array_map SEC(".maps");
34
35SEC("?tp/syscalls/sys_enter_nanosleep")
36int test_read_write(void *ctx)
37{
38 char write_data[64] = "hello there, world!!";
39 char read_data[64] = {};
40 struct bpf_dynptr ptr;
41 int i;
42
43 if (bpf_get_current_pid_tgid() >> 32 != pid)
44 return 0;
45
46 bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(write_data), 0, &ptr);
47
48 /* Write data into the dynptr */
49 err = bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0);
50
51 /* Read the data that was written into the dynptr */
52 err = err ?: bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
53
54 /* Ensure the data we read matches the data we wrote */
55 for (i = 0; i < sizeof(read_data); i++) {
56 if (read_data[i] != write_data[i]) {
57 err = 1;
58 break;
59 }
60 }
61
62 bpf_ringbuf_discard_dynptr(&ptr, 0);
63 return 0;
64}
65
66SEC("?tp/syscalls/sys_enter_nanosleep")
67int test_dynptr_data(void *ctx)
68{
69 __u32 key = 0, val = 235, *map_val;
70 struct bpf_dynptr ptr;
71 __u32 map_val_size;
72 void *data;
73
74 map_val_size = sizeof(*map_val);
75
76 if (bpf_get_current_pid_tgid() >> 32 != pid)
77 return 0;
78
79 bpf_map_update_elem(&array_map, &key, &val, 0);
80
81 map_val = bpf_map_lookup_elem(&array_map, &key);
82 if (!map_val) {
83 err = 1;
84 return 0;
85 }
86
87 bpf_dynptr_from_mem(map_val, map_val_size, 0, &ptr);
88
89 /* Try getting a data slice that is out of range */
90 data = bpf_dynptr_data(&ptr, map_val_size + 1, 1);
91 if (data) {
92 err = 2;
93 return 0;
94 }
95
96 /* Try getting more bytes than available */
97 data = bpf_dynptr_data(&ptr, 0, map_val_size + 1);
98 if (data) {
99 err = 3;
100 return 0;
101 }
102
103 data = bpf_dynptr_data(&ptr, 0, sizeof(__u32));
104 if (!data) {
105 err = 4;
106 return 0;
107 }
108
109 *(__u32 *)data = 999;
110
111 err = bpf_probe_read_kernel(&val, sizeof(val), data);
112 if (err)
113 return 0;
114
115 if (val != *(int *)data)
116 err = 5;
117
118 return 0;
119}
120
121static int ringbuf_callback(__u32 index, void *data)
122{
123 struct sample *sample;
124
125 struct bpf_dynptr *ptr = (struct bpf_dynptr *)data;
126
127 sample = bpf_dynptr_data(ptr, 0, sizeof(*sample));
128 if (!sample)
129 err = 2;
130 else
131 sample->pid += index;
132
133 return 0;
134}
135
136SEC("?tp/syscalls/sys_enter_nanosleep")
137int test_ringbuf(void *ctx)
138{
139 struct bpf_dynptr ptr;
140 struct sample *sample;
141
142 if (bpf_get_current_pid_tgid() >> 32 != pid)
143 return 0;
144
145 val = 100;
146
147 /* check that you can reserve a dynamic size reservation */
148 err = bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr);
149
150 sample = err ? NULL : bpf_dynptr_data(&ptr, 0, sizeof(*sample));
151 if (!sample) {
152 err = 1;
153 goto done;
154 }
155
156 sample->pid = 10;
157
158 /* Can pass dynptr to callback functions */
159 bpf_loop(10, ringbuf_callback, &ptr, 0);
160
161 if (sample->pid != 55)
162 err = 2;
163
164done:
165 bpf_ringbuf_discard_dynptr(&ptr, 0);
166 return 0;
167}
168
169SEC("?cgroup_skb/egress")
170int test_skb_readonly(struct __sk_buff *skb)
171{
172 __u8 write_data[2] = {1, 2};
173 struct bpf_dynptr ptr;
174 int ret;
175
176 if (bpf_dynptr_from_skb(skb, 0, &ptr)) {
177 err = 1;
178 return 1;
179 }
180
181 /* since cgroup skbs are read only, writes should fail */
182 ret = bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0);
183 if (ret != -EINVAL) {
184 err = 2;
185 return 1;
186 }
187
188 return 1;
189}
190
191SEC("?cgroup_skb/egress")
192int test_dynptr_skb_data(struct __sk_buff *skb)
193{
194 struct bpf_dynptr ptr;
195 __u64 *data;
196
197 if (bpf_dynptr_from_skb(skb, 0, &ptr)) {
198 err = 1;
199 return 1;
200 }
201
202 /* This should return NULL. Must use bpf_dynptr_slice API */
203 data = bpf_dynptr_data(&ptr, 0, 1);
204 if (data) {
205 err = 2;
206 return 1;
207 }
208
209 return 1;
210}
211
212SEC("tp/syscalls/sys_enter_nanosleep")
213int test_adjust(void *ctx)
214{
215 struct bpf_dynptr ptr;
216 __u32 bytes = 64;
217 __u32 off = 10;
218 __u32 trim = 15;
219
220 if (bpf_get_current_pid_tgid() >> 32 != pid)
221 return 0;
222
223 err = bpf_ringbuf_reserve_dynptr(&ringbuf, bytes, 0, &ptr);
224 if (err) {
225 err = 1;
226 goto done;
227 }
228
229 if (bpf_dynptr_size(&ptr) != bytes) {
230 err = 2;
231 goto done;
232 }
233
234 /* Advance the dynptr by off */
235 err = bpf_dynptr_adjust(&ptr, off, bpf_dynptr_size(&ptr));
236 if (err) {
237 err = 3;
238 goto done;
239 }
240
241 if (bpf_dynptr_size(&ptr) != bytes - off) {
242 err = 4;
243 goto done;
244 }
245
246 /* Trim the dynptr */
247 err = bpf_dynptr_adjust(&ptr, off, 15);
248 if (err) {
249 err = 5;
250 goto done;
251 }
252
253 /* Check that the size was adjusted correctly */
254 if (bpf_dynptr_size(&ptr) != trim - off) {
255 err = 6;
256 goto done;
257 }
258
259done:
260 bpf_ringbuf_discard_dynptr(&ptr, 0);
261 return 0;
262}
263
264SEC("tp/syscalls/sys_enter_nanosleep")
265int test_adjust_err(void *ctx)
266{
267 char write_data[45] = "hello there, world!!";
268 struct bpf_dynptr ptr;
269 __u32 size = 64;
270 __u32 off = 20;
271
272 if (bpf_get_current_pid_tgid() >> 32 != pid)
273 return 0;
274
275 if (bpf_ringbuf_reserve_dynptr(&ringbuf, size, 0, &ptr)) {
276 err = 1;
277 goto done;
278 }
279
280 /* Check that start can't be greater than end */
281 if (bpf_dynptr_adjust(&ptr, 5, 1) != -EINVAL) {
282 err = 2;
283 goto done;
284 }
285
286 /* Check that start can't be greater than size */
287 if (bpf_dynptr_adjust(&ptr, size + 1, size + 1) != -ERANGE) {
288 err = 3;
289 goto done;
290 }
291
292 /* Check that end can't be greater than size */
293 if (bpf_dynptr_adjust(&ptr, 0, size + 1) != -ERANGE) {
294 err = 4;
295 goto done;
296 }
297
298 if (bpf_dynptr_adjust(&ptr, off, size)) {
299 err = 5;
300 goto done;
301 }
302
303 /* Check that you can't write more bytes than available into the dynptr
304 * after you've adjusted it
305 */
306 if (bpf_dynptr_write(&ptr, 0, &write_data, sizeof(write_data), 0) != -E2BIG) {
307 err = 6;
308 goto done;
309 }
310
311 /* Check that even after adjusting, submitting/discarding
312 * a ringbuf dynptr works
313 */
314 bpf_ringbuf_submit_dynptr(&ptr, 0);
315 return 0;
316
317done:
318 bpf_ringbuf_discard_dynptr(&ptr, 0);
319 return 0;
320}
321
322SEC("tp/syscalls/sys_enter_nanosleep")
323int test_zero_size_dynptr(void *ctx)
324{
325 char write_data = 'x', read_data;
326 struct bpf_dynptr ptr;
327 __u32 size = 64;
328
329 if (bpf_get_current_pid_tgid() >> 32 != pid)
330 return 0;
331
332 if (bpf_ringbuf_reserve_dynptr(&ringbuf, size, 0, &ptr)) {
333 err = 1;
334 goto done;
335 }
336
337 /* After this, the dynptr has a size of 0 */
338 if (bpf_dynptr_adjust(&ptr, size, size)) {
339 err = 2;
340 goto done;
341 }
342
343 /* Test that reading + writing non-zero bytes is not ok */
344 if (bpf_dynptr_read(&read_data, sizeof(read_data), &ptr, 0, 0) != -E2BIG) {
345 err = 3;
346 goto done;
347 }
348
349 if (bpf_dynptr_write(&ptr, 0, &write_data, sizeof(write_data), 0) != -E2BIG) {
350 err = 4;
351 goto done;
352 }
353
354 /* Test that reading + writing 0 bytes from a 0-size dynptr is ok */
355 if (bpf_dynptr_read(&read_data, 0, &ptr, 0, 0)) {
356 err = 5;
357 goto done;
358 }
359
360 if (bpf_dynptr_write(&ptr, 0, &write_data, 0, 0)) {
361 err = 6;
362 goto done;
363 }
364
365 err = 0;
366
367done:
368 bpf_ringbuf_discard_dynptr(&ptr, 0);
369 return 0;
370}
371
372SEC("tp/syscalls/sys_enter_nanosleep")
373int test_dynptr_is_null(void *ctx)
374{
375 struct bpf_dynptr ptr1;
376 struct bpf_dynptr ptr2;
377 __u64 size = 4;
378
379 if (bpf_get_current_pid_tgid() >> 32 != pid)
380 return 0;
381
382 /* Pass in invalid flags, get back an invalid dynptr */
383 if (bpf_ringbuf_reserve_dynptr(&ringbuf, size, 123, &ptr1) != -EINVAL) {
384 err = 1;
385 goto exit_early;
386 }
387
388 /* Test that the invalid dynptr is null */
389 if (!bpf_dynptr_is_null(&ptr1)) {
390 err = 2;
391 goto exit_early;
392 }
393
394 /* Get a valid dynptr */
395 if (bpf_ringbuf_reserve_dynptr(&ringbuf, size, 0, &ptr2)) {
396 err = 3;
397 goto exit;
398 }
399
400 /* Test that the valid dynptr is not null */
401 if (bpf_dynptr_is_null(&ptr2)) {
402 err = 4;
403 goto exit;
404 }
405
406exit:
407 bpf_ringbuf_discard_dynptr(&ptr2, 0);
408exit_early:
409 bpf_ringbuf_discard_dynptr(&ptr1, 0);
410 return 0;
411}
412
413SEC("cgroup_skb/egress")
414int test_dynptr_is_rdonly(struct __sk_buff *skb)
415{
416 struct bpf_dynptr ptr1;
417 struct bpf_dynptr ptr2;
418 struct bpf_dynptr ptr3;
419
420 /* Pass in invalid flags, get back an invalid dynptr */
421 if (bpf_dynptr_from_skb(skb, 123, &ptr1) != -EINVAL) {
422 err = 1;
423 return 0;
424 }
425
426 /* Test that an invalid dynptr is_rdonly returns false */
427 if (bpf_dynptr_is_rdonly(&ptr1)) {
428 err = 2;
429 return 0;
430 }
431
432 /* Get a read-only dynptr */
433 if (bpf_dynptr_from_skb(skb, 0, &ptr2)) {
434 err = 3;
435 return 0;
436 }
437
438 /* Test that the dynptr is read-only */
439 if (!bpf_dynptr_is_rdonly(&ptr2)) {
440 err = 4;
441 return 0;
442 }
443
444 /* Get a read-writeable dynptr */
445 if (bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr3)) {
446 err = 5;
447 goto done;
448 }
449
450 /* Test that the dynptr is read-only */
451 if (bpf_dynptr_is_rdonly(&ptr3)) {
452 err = 6;
453 goto done;
454 }
455
456done:
457 bpf_ringbuf_discard_dynptr(&ptr3, 0);
458 return 0;
459}
460
461SEC("cgroup_skb/egress")
462int test_dynptr_clone(struct __sk_buff *skb)
463{
464 struct bpf_dynptr ptr1;
465 struct bpf_dynptr ptr2;
466 __u32 off = 2, size;
467
468 /* Get a dynptr */
469 if (bpf_dynptr_from_skb(skb, 0, &ptr1)) {
470 err = 1;
471 return 0;
472 }
473
474 if (bpf_dynptr_adjust(&ptr1, off, bpf_dynptr_size(&ptr1))) {
475 err = 2;
476 return 0;
477 }
478
479 /* Clone the dynptr */
480 if (bpf_dynptr_clone(&ptr1, &ptr2)) {
481 err = 3;
482 return 0;
483 }
484
485 size = bpf_dynptr_size(&ptr1);
486
487 /* Check that the clone has the same size and rd-only */
488 if (bpf_dynptr_size(&ptr2) != size) {
489 err = 4;
490 return 0;
491 }
492
493 if (bpf_dynptr_is_rdonly(&ptr2) != bpf_dynptr_is_rdonly(&ptr1)) {
494 err = 5;
495 return 0;
496 }
497
498 /* Advance and trim the original dynptr */
499 bpf_dynptr_adjust(&ptr1, 5, 5);
500
501 /* Check that only original dynptr was affected, and the clone wasn't */
502 if (bpf_dynptr_size(&ptr2) != size) {
503 err = 6;
504 return 0;
505 }
506
507 return 0;
508}
509
510SEC("?cgroup_skb/egress")
511int test_dynptr_skb_no_buff(struct __sk_buff *skb)
512{
513 struct bpf_dynptr ptr;
514 __u64 *data;
515
516 if (bpf_dynptr_from_skb(skb, 0, &ptr)) {
517 err = 1;
518 return 1;
519 }
520
521 /* This may return NULL. SKB may require a buffer */
522 data = bpf_dynptr_slice(&ptr, 0, NULL, 1);
523
524 return !!data;
525}
526
527SEC("?cgroup_skb/egress")
528int test_dynptr_skb_strcmp(struct __sk_buff *skb)
529{
530 struct bpf_dynptr ptr;
531 char *data;
532
533 if (bpf_dynptr_from_skb(skb, 0, &ptr)) {
534 err = 1;
535 return 1;
536 }
537
538 /* This may return NULL. SKB may require a buffer */
539 data = bpf_dynptr_slice(&ptr, 0, NULL, 10);
540 if (data) {
541 bpf_strncmp(data, 10, "foo");
542 return 1;
543 }
544
545 return 1;
546}