]> Git Repo - linux.git/blob - tools/testing/selftests/bpf/progs/dynptr_success.c
Linux 6.14-rc3
[linux.git] / tools / testing / selftests / bpf / progs / dynptr_success.c
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
13 char _license[] SEC("license") = "GPL";
14
15 int pid, err, val;
16
17 struct sample {
18         int pid;
19         int seq;
20         long value;
21         char comm[16];
22 };
23
24 struct {
25         __uint(type, BPF_MAP_TYPE_RINGBUF);
26         __uint(max_entries, 4096);
27 } ringbuf SEC(".maps");
28
29 struct {
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
36 SEC("?tp/syscalls/sys_enter_nanosleep")
37 int 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
67 SEC("?tp/syscalls/sys_enter_nanosleep")
68 int 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
122 static 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
137 SEC("?tp/syscalls/sys_enter_nanosleep")
138 int 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
165 done:
166         bpf_ringbuf_discard_dynptr(&ptr, 0);
167         return 0;
168 }
169
170 SEC("?cgroup_skb/egress")
171 int 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
192 SEC("?cgroup_skb/egress")
193 int 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
213 SEC("tp/syscalls/sys_enter_nanosleep")
214 int 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
260 done:
261         bpf_ringbuf_discard_dynptr(&ptr, 0);
262         return 0;
263 }
264
265 SEC("tp/syscalls/sys_enter_nanosleep")
266 int 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
318 done:
319         bpf_ringbuf_discard_dynptr(&ptr, 0);
320         return 0;
321 }
322
323 SEC("tp/syscalls/sys_enter_nanosleep")
324 int 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
368 done:
369         bpf_ringbuf_discard_dynptr(&ptr, 0);
370         return 0;
371 }
372
373 SEC("tp/syscalls/sys_enter_nanosleep")
374 int 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
407 exit:
408         bpf_ringbuf_discard_dynptr(&ptr2, 0);
409 exit_early:
410         bpf_ringbuf_discard_dynptr(&ptr1, 0);
411         return 0;
412 }
413
414 SEC("cgroup_skb/egress")
415 int 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
457 done:
458         bpf_ringbuf_discard_dynptr(&ptr3, 0);
459         return 0;
460 }
461
462 SEC("cgroup_skb/egress")
463 int 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
511 SEC("?cgroup_skb/egress")
512 int 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
528 SEC("?cgroup_skb/egress")
529 int 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
549 SEC("tp_btf/kfree_skb")
550 int 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 }
This page took 0.055619 seconds and 4 git commands to generate.