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