Loading...
Note: File does not exist in v5.9.
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
10char _license[] SEC("license") = "GPL";
11
12struct test_info {
13 int x;
14 struct bpf_dynptr ptr;
15};
16
17struct {
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
24struct {
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
31struct {
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
38struct sample {
39 int pid;
40 long value;
41 char comm[16];
42};
43
44struct {
45 __uint(type, BPF_MAP_TYPE_RINGBUF);
46 __uint(max_entries, 4096);
47} ringbuf SEC(".maps");
48
49int err, val;
50
51static int get_map_val_dynptr(struct bpf_dynptr *ptr)
52{
53 __u32 key = 0, *map_val;
54
55 bpf_map_update_elem(&array_map3, &key, &val, 0);
56
57 map_val = bpf_map_lookup_elem(&array_map3, &key);
58 if (!map_val)
59 return -ENOENT;
60
61 bpf_dynptr_from_mem(map_val, sizeof(*map_val), 0, ptr);
62
63 return 0;
64}
65
66/* Every bpf_ringbuf_reserve_dynptr call must have a corresponding
67 * bpf_ringbuf_submit/discard_dynptr call
68 */
69SEC("?raw_tp")
70__failure __msg("Unreleased reference id=1")
71int ringbuf_missing_release1(void *ctx)
72{
73 struct bpf_dynptr ptr;
74
75 bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr);
76
77 /* missing a call to bpf_ringbuf_discard/submit_dynptr */
78
79 return 0;
80}
81
82SEC("?raw_tp")
83__failure __msg("Unreleased reference id=2")
84int ringbuf_missing_release2(void *ctx)
85{
86 struct bpf_dynptr ptr1, ptr2;
87 struct sample *sample;
88
89 bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr1);
90 bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr2);
91
92 sample = bpf_dynptr_data(&ptr1, 0, sizeof(*sample));
93 if (!sample) {
94 bpf_ringbuf_discard_dynptr(&ptr1, 0);
95 bpf_ringbuf_discard_dynptr(&ptr2, 0);
96 return 0;
97 }
98
99 bpf_ringbuf_submit_dynptr(&ptr1, 0);
100
101 /* missing a call to bpf_ringbuf_discard/submit_dynptr on ptr2 */
102
103 return 0;
104}
105
106static int missing_release_callback_fn(__u32 index, void *data)
107{
108 struct bpf_dynptr ptr;
109
110 bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr);
111
112 /* missing a call to bpf_ringbuf_discard/submit_dynptr */
113
114 return 0;
115}
116
117/* Any dynptr initialized within a callback must have bpf_dynptr_put called */
118SEC("?raw_tp")
119__failure __msg("Unreleased reference id")
120int ringbuf_missing_release_callback(void *ctx)
121{
122 bpf_loop(10, missing_release_callback_fn, NULL, 0);
123 return 0;
124}
125
126/* Can't call bpf_ringbuf_submit/discard_dynptr on a non-initialized dynptr */
127SEC("?raw_tp")
128__failure __msg("arg 1 is an unacquired reference")
129int ringbuf_release_uninit_dynptr(void *ctx)
130{
131 struct bpf_dynptr ptr;
132
133 /* this should fail */
134 bpf_ringbuf_submit_dynptr(&ptr, 0);
135
136 return 0;
137}
138
139/* A dynptr can't be used after it has been invalidated */
140SEC("?raw_tp")
141__failure __msg("Expected an initialized dynptr as arg #3")
142int use_after_invalid(void *ctx)
143{
144 struct bpf_dynptr ptr;
145 char read_data[64];
146
147 bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(read_data), 0, &ptr);
148
149 bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
150
151 bpf_ringbuf_submit_dynptr(&ptr, 0);
152
153 /* this should fail */
154 bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
155
156 return 0;
157}
158
159/* Can't call non-dynptr ringbuf APIs on a dynptr ringbuf sample */
160SEC("?raw_tp")
161__failure __msg("type=mem expected=ringbuf_mem")
162int ringbuf_invalid_api(void *ctx)
163{
164 struct bpf_dynptr ptr;
165 struct sample *sample;
166
167 bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr);
168 sample = bpf_dynptr_data(&ptr, 0, sizeof(*sample));
169 if (!sample)
170 goto done;
171
172 sample->pid = 123;
173
174 /* invalid API use. need to use dynptr API to submit/discard */
175 bpf_ringbuf_submit(sample, 0);
176
177done:
178 bpf_ringbuf_discard_dynptr(&ptr, 0);
179 return 0;
180}
181
182/* Can't add a dynptr to a map */
183SEC("?raw_tp")
184__failure __msg("invalid indirect read from stack")
185int add_dynptr_to_map1(void *ctx)
186{
187 struct bpf_dynptr ptr;
188 int key = 0;
189
190 bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr);
191
192 /* this should fail */
193 bpf_map_update_elem(&array_map1, &key, &ptr, 0);
194
195 bpf_ringbuf_submit_dynptr(&ptr, 0);
196
197 return 0;
198}
199
200/* Can't add a struct with an embedded dynptr to a map */
201SEC("?raw_tp")
202__failure __msg("invalid indirect read from stack")
203int add_dynptr_to_map2(void *ctx)
204{
205 struct test_info x;
206 int key = 0;
207
208 bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &x.ptr);
209
210 /* this should fail */
211 bpf_map_update_elem(&array_map2, &key, &x, 0);
212
213 bpf_ringbuf_submit_dynptr(&x.ptr, 0);
214
215 return 0;
216}
217
218/* A data slice can't be accessed out of bounds */
219SEC("?raw_tp")
220__failure __msg("value is outside of the allowed memory range")
221int data_slice_out_of_bounds_ringbuf(void *ctx)
222{
223 struct bpf_dynptr ptr;
224 void *data;
225
226 bpf_ringbuf_reserve_dynptr(&ringbuf, 8, 0, &ptr);
227
228 data = bpf_dynptr_data(&ptr, 0, 8);
229 if (!data)
230 goto done;
231
232 /* can't index out of bounds of the data slice */
233 val = *((char *)data + 8);
234
235done:
236 bpf_ringbuf_submit_dynptr(&ptr, 0);
237 return 0;
238}
239
240SEC("?raw_tp")
241__failure __msg("value is outside of the allowed memory range")
242int data_slice_out_of_bounds_map_value(void *ctx)
243{
244 __u32 key = 0, map_val;
245 struct bpf_dynptr ptr;
246 void *data;
247
248 get_map_val_dynptr(&ptr);
249
250 data = bpf_dynptr_data(&ptr, 0, sizeof(map_val));
251 if (!data)
252 return 0;
253
254 /* can't index out of bounds of the data slice */
255 val = *((char *)data + (sizeof(map_val) + 1));
256
257 return 0;
258}
259
260/* A data slice can't be used after it has been released */
261SEC("?raw_tp")
262__failure __msg("invalid mem access 'scalar'")
263int data_slice_use_after_release1(void *ctx)
264{
265 struct bpf_dynptr ptr;
266 struct sample *sample;
267
268 bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr);
269 sample = bpf_dynptr_data(&ptr, 0, sizeof(*sample));
270 if (!sample)
271 goto done;
272
273 sample->pid = 123;
274
275 bpf_ringbuf_submit_dynptr(&ptr, 0);
276
277 /* this should fail */
278 val = sample->pid;
279
280 return 0;
281
282done:
283 bpf_ringbuf_discard_dynptr(&ptr, 0);
284 return 0;
285}
286
287/* A data slice can't be used after it has been released.
288 *
289 * This tests the case where the data slice tracks a dynptr (ptr2)
290 * that is at a non-zero offset from the frame pointer (ptr1 is at fp,
291 * ptr2 is at fp - 16).
292 */
293SEC("?raw_tp")
294__failure __msg("invalid mem access 'scalar'")
295int data_slice_use_after_release2(void *ctx)
296{
297 struct bpf_dynptr ptr1, ptr2;
298 struct sample *sample;
299
300 bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr1);
301 bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr2);
302
303 sample = bpf_dynptr_data(&ptr2, 0, sizeof(*sample));
304 if (!sample)
305 goto done;
306
307 sample->pid = 23;
308
309 bpf_ringbuf_submit_dynptr(&ptr2, 0);
310
311 /* this should fail */
312 sample->pid = 23;
313
314 bpf_ringbuf_submit_dynptr(&ptr1, 0);
315
316 return 0;
317
318done:
319 bpf_ringbuf_discard_dynptr(&ptr2, 0);
320 bpf_ringbuf_discard_dynptr(&ptr1, 0);
321 return 0;
322}
323
324/* A data slice must be first checked for NULL */
325SEC("?raw_tp")
326__failure __msg("invalid mem access 'mem_or_null'")
327int data_slice_missing_null_check1(void *ctx)
328{
329 struct bpf_dynptr ptr;
330 void *data;
331
332 bpf_ringbuf_reserve_dynptr(&ringbuf, 8, 0, &ptr);
333
334 data = bpf_dynptr_data(&ptr, 0, 8);
335
336 /* missing if (!data) check */
337
338 /* this should fail */
339 *(__u8 *)data = 3;
340
341 bpf_ringbuf_submit_dynptr(&ptr, 0);
342 return 0;
343}
344
345/* A data slice can't be dereferenced if it wasn't checked for null */
346SEC("?raw_tp")
347__failure __msg("invalid mem access 'mem_or_null'")
348int data_slice_missing_null_check2(void *ctx)
349{
350 struct bpf_dynptr ptr;
351 __u64 *data1, *data2;
352
353 bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &ptr);
354
355 data1 = bpf_dynptr_data(&ptr, 0, 8);
356 data2 = bpf_dynptr_data(&ptr, 0, 8);
357 if (data1)
358 /* this should fail */
359 *data2 = 3;
360
361done:
362 bpf_ringbuf_discard_dynptr(&ptr, 0);
363 return 0;
364}
365
366/* Can't pass in a dynptr as an arg to a helper function that doesn't take in a
367 * dynptr argument
368 */
369SEC("?raw_tp")
370__failure __msg("invalid indirect read from stack")
371int invalid_helper1(void *ctx)
372{
373 struct bpf_dynptr ptr;
374
375 get_map_val_dynptr(&ptr);
376
377 /* this should fail */
378 bpf_strncmp((const char *)&ptr, sizeof(ptr), "hello!");
379
380 return 0;
381}
382
383/* A dynptr can't be passed into a helper function at a non-zero offset */
384SEC("?raw_tp")
385__failure __msg("Expected an initialized dynptr as arg #3")
386int invalid_helper2(void *ctx)
387{
388 struct bpf_dynptr ptr;
389 char read_data[64];
390
391 get_map_val_dynptr(&ptr);
392
393 /* this should fail */
394 bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 8, 0, 0);
395
396 return 0;
397}
398
399/* A bpf_dynptr is invalidated if it's been written into */
400SEC("?raw_tp")
401__failure __msg("Expected an initialized dynptr as arg #1")
402int invalid_write1(void *ctx)
403{
404 struct bpf_dynptr ptr;
405 void *data;
406 __u8 x = 0;
407
408 get_map_val_dynptr(&ptr);
409
410 memcpy(&ptr, &x, sizeof(x));
411
412 /* this should fail */
413 data = bpf_dynptr_data(&ptr, 0, 1);
414
415 return 0;
416}
417
418/*
419 * A bpf_dynptr can't be used as a dynptr if it has been written into at a fixed
420 * offset
421 */
422SEC("?raw_tp")
423__failure __msg("Expected an initialized dynptr as arg #3")
424int invalid_write2(void *ctx)
425{
426 struct bpf_dynptr ptr;
427 char read_data[64];
428 __u8 x = 0;
429
430 bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr);
431
432 memcpy((void *)&ptr + 8, &x, sizeof(x));
433
434 /* this should fail */
435 bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
436
437 bpf_ringbuf_submit_dynptr(&ptr, 0);
438
439 return 0;
440}
441
442/*
443 * A bpf_dynptr can't be used as a dynptr if it has been written into at a
444 * non-const offset
445 */
446SEC("?raw_tp")
447__failure __msg("Expected an initialized dynptr as arg #1")
448int invalid_write3(void *ctx)
449{
450 struct bpf_dynptr ptr;
451 char stack_buf[16];
452 unsigned long len;
453 __u8 x = 0;
454
455 bpf_ringbuf_reserve_dynptr(&ringbuf, 8, 0, &ptr);
456
457 memcpy(stack_buf, &val, sizeof(val));
458 len = stack_buf[0] & 0xf;
459
460 memcpy((void *)&ptr + len, &x, sizeof(x));
461
462 /* this should fail */
463 bpf_ringbuf_submit_dynptr(&ptr, 0);
464
465 return 0;
466}
467
468static int invalid_write4_callback(__u32 index, void *data)
469{
470 *(__u32 *)data = 123;
471
472 return 0;
473}
474
475/* If the dynptr is written into in a callback function, it should
476 * be invalidated as a dynptr
477 */
478SEC("?raw_tp")
479__failure __msg("arg 1 is an unacquired reference")
480int invalid_write4(void *ctx)
481{
482 struct bpf_dynptr ptr;
483
484 bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr);
485
486 bpf_loop(10, invalid_write4_callback, &ptr, 0);
487
488 /* this should fail */
489 bpf_ringbuf_submit_dynptr(&ptr, 0);
490
491 return 0;
492}
493
494/* A globally-defined bpf_dynptr can't be used (it must reside as a stack frame) */
495struct bpf_dynptr global_dynptr;
496
497SEC("?raw_tp")
498__failure __msg("type=map_value expected=fp")
499int global(void *ctx)
500{
501 /* this should fail */
502 bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &global_dynptr);
503
504 bpf_ringbuf_discard_dynptr(&global_dynptr, 0);
505
506 return 0;
507}
508
509/* A direct read should fail */
510SEC("?raw_tp")
511__failure __msg("invalid read from stack")
512int invalid_read1(void *ctx)
513{
514 struct bpf_dynptr ptr;
515
516 bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr);
517
518 /* this should fail */
519 val = *(int *)&ptr;
520
521 bpf_ringbuf_discard_dynptr(&ptr, 0);
522
523 return 0;
524}
525
526/* A direct read at an offset should fail */
527SEC("?raw_tp")
528__failure __msg("cannot pass in dynptr at an offset")
529int invalid_read2(void *ctx)
530{
531 struct bpf_dynptr ptr;
532 char read_data[64];
533
534 get_map_val_dynptr(&ptr);
535
536 /* this should fail */
537 bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 1, 0, 0);
538
539 return 0;
540}
541
542/* A direct read at an offset into the lower stack slot should fail */
543SEC("?raw_tp")
544__failure __msg("invalid read from stack")
545int invalid_read3(void *ctx)
546{
547 struct bpf_dynptr ptr1, ptr2;
548
549 bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &ptr1);
550 bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &ptr2);
551
552 /* this should fail */
553 memcpy(&val, (void *)&ptr1 + 8, sizeof(val));
554
555 bpf_ringbuf_discard_dynptr(&ptr1, 0);
556 bpf_ringbuf_discard_dynptr(&ptr2, 0);
557
558 return 0;
559}
560
561static int invalid_read4_callback(__u32 index, void *data)
562{
563 /* this should fail */
564 val = *(__u32 *)data;
565
566 return 0;
567}
568
569/* A direct read within a callback function should fail */
570SEC("?raw_tp")
571__failure __msg("invalid read from stack")
572int invalid_read4(void *ctx)
573{
574 struct bpf_dynptr ptr;
575
576 bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr);
577
578 bpf_loop(10, invalid_read4_callback, &ptr, 0);
579
580 bpf_ringbuf_submit_dynptr(&ptr, 0);
581
582 return 0;
583}
584
585/* Initializing a dynptr on an offset should fail */
586SEC("?raw_tp")
587__failure __msg("invalid write to stack")
588int invalid_offset(void *ctx)
589{
590 struct bpf_dynptr ptr;
591
592 /* this should fail */
593 bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr + 1);
594
595 bpf_ringbuf_discard_dynptr(&ptr, 0);
596
597 return 0;
598}
599
600/* Can't release a dynptr twice */
601SEC("?raw_tp")
602__failure __msg("arg 1 is an unacquired reference")
603int release_twice(void *ctx)
604{
605 struct bpf_dynptr ptr;
606
607 bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &ptr);
608
609 bpf_ringbuf_discard_dynptr(&ptr, 0);
610
611 /* this second release should fail */
612 bpf_ringbuf_discard_dynptr(&ptr, 0);
613
614 return 0;
615}
616
617static int release_twice_callback_fn(__u32 index, void *data)
618{
619 /* this should fail */
620 bpf_ringbuf_discard_dynptr(data, 0);
621
622 return 0;
623}
624
625/* Test that releasing a dynptr twice, where one of the releases happens
626 * within a calback function, fails
627 */
628SEC("?raw_tp")
629__failure __msg("arg 1 is an unacquired reference")
630int release_twice_callback(void *ctx)
631{
632 struct bpf_dynptr ptr;
633
634 bpf_ringbuf_reserve_dynptr(&ringbuf, 32, 0, &ptr);
635
636 bpf_ringbuf_discard_dynptr(&ptr, 0);
637
638 bpf_loop(10, release_twice_callback_fn, &ptr, 0);
639
640 return 0;
641}
642
643/* Reject unsupported local mem types for dynptr_from_mem API */
644SEC("?raw_tp")
645__failure __msg("Unsupported reg type fp for bpf_dynptr_from_mem data")
646int dynptr_from_mem_invalid_api(void *ctx)
647{
648 struct bpf_dynptr ptr;
649 int x = 0;
650
651 /* this should fail */
652 bpf_dynptr_from_mem(&x, sizeof(x), 0, &ptr);
653
654 return 0;
655}