1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright (c) 2022 Facebook */ |
3 | |
4 | #include <errno.h> |
5 | #include <string.h> |
6 | #include <stdbool.h> |
7 | #include <linux/bpf.h> |
8 | #include <bpf/bpf_helpers.h> |
9 | #include <linux/if_ether.h> |
10 | #include "bpf_misc.h" |
11 | #include "bpf_kfuncs.h" |
12 | |
13 | char _license[] SEC("license" ) = "GPL" ; |
14 | |
15 | struct test_info { |
16 | int x; |
17 | struct bpf_dynptr ptr; |
18 | }; |
19 | |
20 | struct { |
21 | __uint(type, BPF_MAP_TYPE_ARRAY); |
22 | __uint(max_entries, 1); |
23 | __type(key, __u32); |
24 | __type(value, struct bpf_dynptr); |
25 | } array_map1 SEC(".maps" ); |
26 | |
27 | struct { |
28 | __uint(type, BPF_MAP_TYPE_ARRAY); |
29 | __uint(max_entries, 1); |
30 | __type(key, __u32); |
31 | __type(value, struct test_info); |
32 | } array_map2 SEC(".maps" ); |
33 | |
34 | struct { |
35 | __uint(type, BPF_MAP_TYPE_ARRAY); |
36 | __uint(max_entries, 1); |
37 | __type(key, __u32); |
38 | __type(value, __u32); |
39 | } array_map3 SEC(".maps" ); |
40 | |
41 | struct { |
42 | __uint(type, BPF_MAP_TYPE_ARRAY); |
43 | __uint(max_entries, 1); |
44 | __type(key, __u32); |
45 | __type(value, __u64); |
46 | } array_map4 SEC(".maps" ); |
47 | |
48 | struct sample { |
49 | int pid; |
50 | long value; |
51 | char comm[16]; |
52 | }; |
53 | |
54 | struct { |
55 | __uint(type, BPF_MAP_TYPE_RINGBUF); |
56 | __uint(max_entries, 4096); |
57 | } ringbuf SEC(".maps" ); |
58 | |
59 | int err, val; |
60 | |
61 | static int get_map_val_dynptr(struct bpf_dynptr *ptr) |
62 | { |
63 | __u32 key = 0, *map_val; |
64 | |
65 | bpf_map_update_elem(&array_map3, &key, &val, 0); |
66 | |
67 | map_val = bpf_map_lookup_elem(&array_map3, &key); |
68 | if (!map_val) |
69 | return -ENOENT; |
70 | |
71 | bpf_dynptr_from_mem(map_val, sizeof(*map_val), 0, ptr); |
72 | |
73 | return 0; |
74 | } |
75 | |
76 | /* Every bpf_ringbuf_reserve_dynptr call must have a corresponding |
77 | * bpf_ringbuf_submit/discard_dynptr call |
78 | */ |
79 | SEC("?raw_tp" ) |
80 | __failure __msg("Unreleased reference id=2" ) |
81 | int ringbuf_missing_release1(void *ctx) |
82 | { |
83 | struct bpf_dynptr ptr; |
84 | |
85 | bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); |
86 | |
87 | /* missing a call to bpf_ringbuf_discard/submit_dynptr */ |
88 | |
89 | return 0; |
90 | } |
91 | |
92 | SEC("?raw_tp" ) |
93 | __failure __msg("Unreleased reference id=4" ) |
94 | int ringbuf_missing_release2(void *ctx) |
95 | { |
96 | struct bpf_dynptr ptr1, ptr2; |
97 | struct sample *sample; |
98 | |
99 | bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr1); |
100 | bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr2); |
101 | |
102 | sample = bpf_dynptr_data(&ptr1, 0, sizeof(*sample)); |
103 | if (!sample) { |
104 | bpf_ringbuf_discard_dynptr(&ptr1, 0); |
105 | bpf_ringbuf_discard_dynptr(&ptr2, 0); |
106 | return 0; |
107 | } |
108 | |
109 | bpf_ringbuf_submit_dynptr(&ptr1, 0); |
110 | |
111 | /* missing a call to bpf_ringbuf_discard/submit_dynptr on ptr2 */ |
112 | |
113 | return 0; |
114 | } |
115 | |
116 | static int missing_release_callback_fn(__u32 index, void *data) |
117 | { |
118 | struct bpf_dynptr ptr; |
119 | |
120 | bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); |
121 | |
122 | /* missing a call to bpf_ringbuf_discard/submit_dynptr */ |
123 | |
124 | return 0; |
125 | } |
126 | |
127 | /* Any dynptr initialized within a callback must have bpf_dynptr_put called */ |
128 | SEC("?raw_tp" ) |
129 | __failure __msg("Unreleased reference id" ) |
130 | int ringbuf_missing_release_callback(void *ctx) |
131 | { |
132 | bpf_loop(10, missing_release_callback_fn, NULL, 0); |
133 | return 0; |
134 | } |
135 | |
136 | /* Can't call bpf_ringbuf_submit/discard_dynptr on a non-initialized dynptr */ |
137 | SEC("?raw_tp" ) |
138 | __failure __msg("arg 1 is an unacquired reference" ) |
139 | int ringbuf_release_uninit_dynptr(void *ctx) |
140 | { |
141 | struct bpf_dynptr ptr; |
142 | |
143 | /* this should fail */ |
144 | bpf_ringbuf_submit_dynptr(&ptr, 0); |
145 | |
146 | return 0; |
147 | } |
148 | |
149 | /* A dynptr can't be used after it has been invalidated */ |
150 | SEC("?raw_tp" ) |
151 | __failure __msg("Expected an initialized dynptr as arg #3" ) |
152 | int use_after_invalid(void *ctx) |
153 | { |
154 | struct bpf_dynptr ptr; |
155 | char read_data[64]; |
156 | |
157 | bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(read_data), 0, &ptr); |
158 | |
159 | bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0); |
160 | |
161 | bpf_ringbuf_submit_dynptr(&ptr, 0); |
162 | |
163 | /* this should fail */ |
164 | bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0); |
165 | |
166 | return 0; |
167 | } |
168 | |
169 | /* Can't call non-dynptr ringbuf APIs on a dynptr ringbuf sample */ |
170 | SEC("?raw_tp" ) |
171 | __failure __msg("type=mem expected=ringbuf_mem" ) |
172 | int ringbuf_invalid_api(void *ctx) |
173 | { |
174 | struct bpf_dynptr ptr; |
175 | struct sample *sample; |
176 | |
177 | bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr); |
178 | sample = bpf_dynptr_data(&ptr, 0, sizeof(*sample)); |
179 | if (!sample) |
180 | goto done; |
181 | |
182 | sample->pid = 123; |
183 | |
184 | /* invalid API use. need to use dynptr API to submit/discard */ |
185 | bpf_ringbuf_submit(sample, 0); |
186 | |
187 | done: |
188 | bpf_ringbuf_discard_dynptr(&ptr, 0); |
189 | return 0; |
190 | } |
191 | |
192 | /* Can't add a dynptr to a map */ |
193 | SEC("?raw_tp" ) |
194 | __failure __msg("invalid indirect read from stack" ) |
195 | int add_dynptr_to_map1(void *ctx) |
196 | { |
197 | struct bpf_dynptr ptr; |
198 | int key = 0; |
199 | |
200 | bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); |
201 | |
202 | /* this should fail */ |
203 | bpf_map_update_elem(&array_map1, &key, &ptr, 0); |
204 | |
205 | bpf_ringbuf_submit_dynptr(&ptr, 0); |
206 | |
207 | return 0; |
208 | } |
209 | |
210 | /* Can't add a struct with an embedded dynptr to a map */ |
211 | SEC("?raw_tp" ) |
212 | __failure __msg("invalid indirect read from stack" ) |
213 | int add_dynptr_to_map2(void *ctx) |
214 | { |
215 | struct test_info x; |
216 | int key = 0; |
217 | |
218 | bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &x.ptr); |
219 | |
220 | /* this should fail */ |
221 | bpf_map_update_elem(&array_map2, &key, &x, 0); |
222 | |
223 | bpf_ringbuf_submit_dynptr(&x.ptr, 0); |
224 | |
225 | return 0; |
226 | } |
227 | |
228 | /* A data slice can't be accessed out of bounds */ |
229 | SEC("?raw_tp" ) |
230 | __failure __msg("value is outside of the allowed memory range" ) |
231 | int data_slice_out_of_bounds_ringbuf(void *ctx) |
232 | { |
233 | struct bpf_dynptr ptr; |
234 | void *data; |
235 | |
236 | bpf_ringbuf_reserve_dynptr(&ringbuf, 8, 0, &ptr); |
237 | |
238 | data = bpf_dynptr_data(&ptr, 0, 8); |
239 | if (!data) |
240 | goto done; |
241 | |
242 | /* can't index out of bounds of the data slice */ |
243 | val = *((char *)data + 8); |
244 | |
245 | done: |
246 | bpf_ringbuf_submit_dynptr(&ptr, 0); |
247 | return 0; |
248 | } |
249 | |
250 | /* A data slice can't be accessed out of bounds */ |
251 | SEC("?tc" ) |
252 | __failure __msg("value is outside of the allowed memory range" ) |
253 | int data_slice_out_of_bounds_skb(struct __sk_buff *skb) |
254 | { |
255 | struct bpf_dynptr ptr; |
256 | struct ethhdr *hdr; |
257 | char buffer[sizeof(*hdr)] = {}; |
258 | |
259 | bpf_dynptr_from_skb(skb, 0, &ptr); |
260 | |
261 | hdr = bpf_dynptr_slice_rdwr(&ptr, 0, buffer, sizeof(buffer)); |
262 | if (!hdr) |
263 | return SK_DROP; |
264 | |
265 | /* this should fail */ |
266 | *(__u8*)(hdr + 1) = 1; |
267 | |
268 | return SK_PASS; |
269 | } |
270 | |
271 | SEC("?raw_tp" ) |
272 | __failure __msg("value is outside of the allowed memory range" ) |
273 | int data_slice_out_of_bounds_map_value(void *ctx) |
274 | { |
275 | __u32 map_val; |
276 | struct bpf_dynptr ptr; |
277 | void *data; |
278 | |
279 | get_map_val_dynptr(ptr: &ptr); |
280 | |
281 | data = bpf_dynptr_data(&ptr, 0, sizeof(map_val)); |
282 | if (!data) |
283 | return 0; |
284 | |
285 | /* can't index out of bounds of the data slice */ |
286 | val = *((char *)data + (sizeof(map_val) + 1)); |
287 | |
288 | return 0; |
289 | } |
290 | |
291 | /* A data slice can't be used after it has been released */ |
292 | SEC("?raw_tp" ) |
293 | __failure __msg("invalid mem access 'scalar'" ) |
294 | int data_slice_use_after_release1(void *ctx) |
295 | { |
296 | struct bpf_dynptr ptr; |
297 | struct sample *sample; |
298 | |
299 | bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr); |
300 | sample = bpf_dynptr_data(&ptr, 0, sizeof(*sample)); |
301 | if (!sample) |
302 | goto done; |
303 | |
304 | sample->pid = 123; |
305 | |
306 | bpf_ringbuf_submit_dynptr(&ptr, 0); |
307 | |
308 | /* this should fail */ |
309 | val = sample->pid; |
310 | |
311 | return 0; |
312 | |
313 | done: |
314 | bpf_ringbuf_discard_dynptr(&ptr, 0); |
315 | return 0; |
316 | } |
317 | |
318 | /* A data slice can't be used after it has been released. |
319 | * |
320 | * This tests the case where the data slice tracks a dynptr (ptr2) |
321 | * that is at a non-zero offset from the frame pointer (ptr1 is at fp, |
322 | * ptr2 is at fp - 16). |
323 | */ |
324 | SEC("?raw_tp" ) |
325 | __failure __msg("invalid mem access 'scalar'" ) |
326 | int data_slice_use_after_release2(void *ctx) |
327 | { |
328 | struct bpf_dynptr ptr1, ptr2; |
329 | struct sample *sample; |
330 | |
331 | bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr1); |
332 | bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr2); |
333 | |
334 | sample = bpf_dynptr_data(&ptr2, 0, sizeof(*sample)); |
335 | if (!sample) |
336 | goto done; |
337 | |
338 | sample->pid = 23; |
339 | |
340 | bpf_ringbuf_submit_dynptr(&ptr2, 0); |
341 | |
342 | /* this should fail */ |
343 | sample->pid = 23; |
344 | |
345 | bpf_ringbuf_submit_dynptr(&ptr1, 0); |
346 | |
347 | return 0; |
348 | |
349 | done: |
350 | bpf_ringbuf_discard_dynptr(&ptr2, 0); |
351 | bpf_ringbuf_discard_dynptr(&ptr1, 0); |
352 | return 0; |
353 | } |
354 | |
355 | /* A data slice must be first checked for NULL */ |
356 | SEC("?raw_tp" ) |
357 | __failure __msg("invalid mem access 'mem_or_null'" ) |
358 | int data_slice_missing_null_check1(void *ctx) |
359 | { |
360 | struct bpf_dynptr ptr; |
361 | void *data; |
362 | |
363 | bpf_ringbuf_reserve_dynptr(&ringbuf, 8, 0, &ptr); |
364 | |
365 | data = bpf_dynptr_data(&ptr, 0, 8); |
366 | |
367 | /* missing if (!data) check */ |
368 | |
369 | /* this should fail */ |
370 | *(__u8 *)data = 3; |
371 | |
372 | bpf_ringbuf_submit_dynptr(&ptr, 0); |
373 | return 0; |
374 | } |
375 | |
376 | /* A data slice can't be dereferenced if it wasn't checked for null */ |
377 | SEC("?raw_tp" ) |
378 | __failure __msg("invalid mem access 'mem_or_null'" ) |
379 | int data_slice_missing_null_check2(void *ctx) |
380 | { |
381 | struct bpf_dynptr ptr; |
382 | __u64 *data1, *data2; |
383 | |
384 | bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &ptr); |
385 | |
386 | data1 = bpf_dynptr_data(&ptr, 0, 8); |
387 | data2 = bpf_dynptr_data(&ptr, 0, 8); |
388 | if (data1) |
389 | /* this should fail */ |
390 | *data2 = 3; |
391 | |
392 | bpf_ringbuf_discard_dynptr(&ptr, 0); |
393 | return 0; |
394 | } |
395 | |
396 | /* Can't pass in a dynptr as an arg to a helper function that doesn't take in a |
397 | * dynptr argument |
398 | */ |
399 | SEC("?raw_tp" ) |
400 | __failure __msg("invalid indirect read from stack" ) |
401 | int invalid_helper1(void *ctx) |
402 | { |
403 | struct bpf_dynptr ptr; |
404 | |
405 | get_map_val_dynptr(ptr: &ptr); |
406 | |
407 | /* this should fail */ |
408 | bpf_strncmp((const char *)&ptr, sizeof(ptr), "hello!" ); |
409 | |
410 | return 0; |
411 | } |
412 | |
413 | /* A dynptr can't be passed into a helper function at a non-zero offset */ |
414 | SEC("?raw_tp" ) |
415 | __failure __msg("cannot pass in dynptr at an offset=-8" ) |
416 | int invalid_helper2(void *ctx) |
417 | { |
418 | struct bpf_dynptr ptr; |
419 | char read_data[64]; |
420 | |
421 | get_map_val_dynptr(ptr: &ptr); |
422 | |
423 | /* this should fail */ |
424 | bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 8, 0, 0); |
425 | return 0; |
426 | } |
427 | |
428 | /* A bpf_dynptr is invalidated if it's been written into */ |
429 | SEC("?raw_tp" ) |
430 | __failure __msg("Expected an initialized dynptr as arg #1" ) |
431 | int invalid_write1(void *ctx) |
432 | { |
433 | struct bpf_dynptr ptr; |
434 | void *data; |
435 | __u8 x = 0; |
436 | |
437 | get_map_val_dynptr(ptr: &ptr); |
438 | |
439 | memcpy(&ptr, &x, sizeof(x)); |
440 | |
441 | /* this should fail */ |
442 | data = bpf_dynptr_data(&ptr, 0, 1); |
443 | __sink(data); |
444 | |
445 | return 0; |
446 | } |
447 | |
448 | /* |
449 | * A bpf_dynptr can't be used as a dynptr if it has been written into at a fixed |
450 | * offset |
451 | */ |
452 | SEC("?raw_tp" ) |
453 | __failure __msg("cannot overwrite referenced dynptr" ) |
454 | int invalid_write2(void *ctx) |
455 | { |
456 | struct bpf_dynptr ptr; |
457 | char read_data[64]; |
458 | __u8 x = 0; |
459 | |
460 | bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr); |
461 | |
462 | memcpy((void *)&ptr + 8, &x, sizeof(x)); |
463 | |
464 | /* this should fail */ |
465 | bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0); |
466 | |
467 | bpf_ringbuf_submit_dynptr(&ptr, 0); |
468 | |
469 | return 0; |
470 | } |
471 | |
472 | /* |
473 | * A bpf_dynptr can't be used as a dynptr if it has been written into at a |
474 | * non-const offset |
475 | */ |
476 | SEC("?raw_tp" ) |
477 | __failure __msg("cannot overwrite referenced dynptr" ) |
478 | int invalid_write3(void *ctx) |
479 | { |
480 | struct bpf_dynptr ptr; |
481 | char stack_buf[16]; |
482 | unsigned long len; |
483 | __u8 x = 0; |
484 | |
485 | bpf_ringbuf_reserve_dynptr(&ringbuf, 8, 0, &ptr); |
486 | |
487 | memcpy(stack_buf, &val, sizeof(val)); |
488 | len = stack_buf[0] & 0xf; |
489 | |
490 | memcpy((void *)&ptr + len, &x, sizeof(x)); |
491 | |
492 | /* this should fail */ |
493 | bpf_ringbuf_submit_dynptr(&ptr, 0); |
494 | |
495 | return 0; |
496 | } |
497 | |
498 | static int invalid_write4_callback(__u32 index, void *data) |
499 | { |
500 | *(__u32 *)data = 123; |
501 | |
502 | return 0; |
503 | } |
504 | |
505 | /* If the dynptr is written into in a callback function, it should |
506 | * be invalidated as a dynptr |
507 | */ |
508 | SEC("?raw_tp" ) |
509 | __failure __msg("cannot overwrite referenced dynptr" ) |
510 | int invalid_write4(void *ctx) |
511 | { |
512 | struct bpf_dynptr ptr; |
513 | |
514 | bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr); |
515 | |
516 | bpf_loop(10, invalid_write4_callback, &ptr, 0); |
517 | |
518 | /* this should fail */ |
519 | bpf_ringbuf_submit_dynptr(&ptr, 0); |
520 | |
521 | return 0; |
522 | } |
523 | |
524 | /* A globally-defined bpf_dynptr can't be used (it must reside as a stack frame) */ |
525 | struct bpf_dynptr global_dynptr; |
526 | |
527 | SEC("?raw_tp" ) |
528 | __failure __msg("type=map_value expected=fp" ) |
529 | int global(void *ctx) |
530 | { |
531 | /* this should fail */ |
532 | bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &global_dynptr); |
533 | |
534 | bpf_ringbuf_discard_dynptr(&global_dynptr, 0); |
535 | |
536 | return 0; |
537 | } |
538 | |
539 | /* A direct read should fail */ |
540 | SEC("?raw_tp" ) |
541 | __failure __msg("invalid read from stack" ) |
542 | int invalid_read1(void *ctx) |
543 | { |
544 | struct bpf_dynptr ptr; |
545 | |
546 | bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr); |
547 | |
548 | /* this should fail */ |
549 | val = *(int *)&ptr; |
550 | |
551 | bpf_ringbuf_discard_dynptr(&ptr, 0); |
552 | |
553 | return 0; |
554 | } |
555 | |
556 | /* A direct read at an offset should fail */ |
557 | SEC("?raw_tp" ) |
558 | __failure __msg("cannot pass in dynptr at an offset" ) |
559 | int invalid_read2(void *ctx) |
560 | { |
561 | struct bpf_dynptr ptr; |
562 | char read_data[64]; |
563 | |
564 | get_map_val_dynptr(ptr: &ptr); |
565 | |
566 | /* this should fail */ |
567 | bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 1, 0, 0); |
568 | |
569 | return 0; |
570 | } |
571 | |
572 | /* A direct read at an offset into the lower stack slot should fail */ |
573 | SEC("?raw_tp" ) |
574 | __failure __msg("invalid read from stack" ) |
575 | int invalid_read3(void *ctx) |
576 | { |
577 | struct bpf_dynptr ptr1, ptr2; |
578 | |
579 | bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &ptr1); |
580 | bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &ptr2); |
581 | |
582 | /* this should fail */ |
583 | memcpy(&val, (void *)&ptr1 + 8, sizeof(val)); |
584 | |
585 | bpf_ringbuf_discard_dynptr(&ptr1, 0); |
586 | bpf_ringbuf_discard_dynptr(&ptr2, 0); |
587 | |
588 | return 0; |
589 | } |
590 | |
591 | static int invalid_read4_callback(__u32 index, void *data) |
592 | { |
593 | /* this should fail */ |
594 | val = *(__u32 *)data; |
595 | |
596 | return 0; |
597 | } |
598 | |
599 | /* A direct read within a callback function should fail */ |
600 | SEC("?raw_tp" ) |
601 | __failure __msg("invalid read from stack" ) |
602 | int invalid_read4(void *ctx) |
603 | { |
604 | struct bpf_dynptr ptr; |
605 | |
606 | bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr); |
607 | |
608 | bpf_loop(10, invalid_read4_callback, &ptr, 0); |
609 | |
610 | bpf_ringbuf_submit_dynptr(&ptr, 0); |
611 | |
612 | return 0; |
613 | } |
614 | |
615 | /* Initializing a dynptr on an offset should fail */ |
616 | SEC("?raw_tp" ) |
617 | __failure __msg("cannot pass in dynptr at an offset=0" ) |
618 | int invalid_offset(void *ctx) |
619 | { |
620 | struct bpf_dynptr ptr; |
621 | |
622 | /* this should fail */ |
623 | bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr + 1); |
624 | |
625 | bpf_ringbuf_discard_dynptr(&ptr, 0); |
626 | |
627 | return 0; |
628 | } |
629 | |
630 | /* Can't release a dynptr twice */ |
631 | SEC("?raw_tp" ) |
632 | __failure __msg("arg 1 is an unacquired reference" ) |
633 | int release_twice(void *ctx) |
634 | { |
635 | struct bpf_dynptr ptr; |
636 | |
637 | bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &ptr); |
638 | |
639 | bpf_ringbuf_discard_dynptr(&ptr, 0); |
640 | |
641 | /* this second release should fail */ |
642 | bpf_ringbuf_discard_dynptr(&ptr, 0); |
643 | |
644 | return 0; |
645 | } |
646 | |
647 | static int release_twice_callback_fn(__u32 index, void *data) |
648 | { |
649 | /* this should fail */ |
650 | bpf_ringbuf_discard_dynptr(data, 0); |
651 | |
652 | return 0; |
653 | } |
654 | |
655 | /* Test that releasing a dynptr twice, where one of the releases happens |
656 | * within a callback function, fails |
657 | */ |
658 | SEC("?raw_tp" ) |
659 | __failure __msg("arg 1 is an unacquired reference" ) |
660 | int release_twice_callback(void *ctx) |
661 | { |
662 | struct bpf_dynptr ptr; |
663 | |
664 | bpf_ringbuf_reserve_dynptr(&ringbuf, 32, 0, &ptr); |
665 | |
666 | bpf_ringbuf_discard_dynptr(&ptr, 0); |
667 | |
668 | bpf_loop(10, release_twice_callback_fn, &ptr, 0); |
669 | |
670 | return 0; |
671 | } |
672 | |
673 | /* Reject unsupported local mem types for dynptr_from_mem API */ |
674 | SEC("?raw_tp" ) |
675 | __failure __msg("Unsupported reg type fp for bpf_dynptr_from_mem data" ) |
676 | int dynptr_from_mem_invalid_api(void *ctx) |
677 | { |
678 | struct bpf_dynptr ptr; |
679 | int x = 0; |
680 | |
681 | /* this should fail */ |
682 | bpf_dynptr_from_mem(&x, sizeof(x), 0, &ptr); |
683 | |
684 | return 0; |
685 | } |
686 | |
687 | SEC("?tc" ) |
688 | __failure __msg("cannot overwrite referenced dynptr" ) __log_level(2) |
689 | int dynptr_pruning_overwrite(struct __sk_buff *ctx) |
690 | { |
691 | asm volatile ( |
692 | "r9 = 0xeB9F; \ |
693 | r6 = %[ringbuf] ll; \ |
694 | r1 = r6; \ |
695 | r2 = 8; \ |
696 | r3 = 0; \ |
697 | r4 = r10; \ |
698 | r4 += -16; \ |
699 | call %[bpf_ringbuf_reserve_dynptr]; \ |
700 | if r0 == 0 goto pjmp1; \ |
701 | goto pjmp2; \ |
702 | pjmp1: \ |
703 | *(u64 *)(r10 - 16) = r9; \ |
704 | pjmp2: \ |
705 | r1 = r10; \ |
706 | r1 += -16; \ |
707 | r2 = 0; \ |
708 | call %[bpf_ringbuf_discard_dynptr]; " |
709 | : |
710 | : __imm(bpf_ringbuf_reserve_dynptr), |
711 | __imm(bpf_ringbuf_discard_dynptr), |
712 | __imm_addr(ringbuf) |
713 | : __clobber_all |
714 | ); |
715 | return 0; |
716 | } |
717 | |
718 | SEC("?tc" ) |
719 | __success __msg("12: safe" ) __log_level(2) |
720 | int dynptr_pruning_stacksafe(struct __sk_buff *ctx) |
721 | { |
722 | asm volatile ( |
723 | "r9 = 0xeB9F; \ |
724 | r6 = %[ringbuf] ll; \ |
725 | r1 = r6; \ |
726 | r2 = 8; \ |
727 | r3 = 0; \ |
728 | r4 = r10; \ |
729 | r4 += -16; \ |
730 | call %[bpf_ringbuf_reserve_dynptr]; \ |
731 | if r0 == 0 goto stjmp1; \ |
732 | goto stjmp2; \ |
733 | stjmp1: \ |
734 | r9 = r9; \ |
735 | stjmp2: \ |
736 | r1 = r10; \ |
737 | r1 += -16; \ |
738 | r2 = 0; \ |
739 | call %[bpf_ringbuf_discard_dynptr]; " |
740 | : |
741 | : __imm(bpf_ringbuf_reserve_dynptr), |
742 | __imm(bpf_ringbuf_discard_dynptr), |
743 | __imm_addr(ringbuf) |
744 | : __clobber_all |
745 | ); |
746 | return 0; |
747 | } |
748 | |
749 | SEC("?tc" ) |
750 | __failure __msg("cannot overwrite referenced dynptr" ) __log_level(2) |
751 | int dynptr_pruning_type_confusion(struct __sk_buff *ctx) |
752 | { |
753 | asm volatile ( |
754 | "r6 = %[array_map4] ll; \ |
755 | r7 = %[ringbuf] ll; \ |
756 | r1 = r6; \ |
757 | r2 = r10; \ |
758 | r2 += -8; \ |
759 | r9 = 0; \ |
760 | *(u64 *)(r2 + 0) = r9; \ |
761 | r3 = r10; \ |
762 | r3 += -24; \ |
763 | r9 = 0xeB9FeB9F; \ |
764 | *(u64 *)(r10 - 16) = r9; \ |
765 | *(u64 *)(r10 - 24) = r9; \ |
766 | r9 = 0; \ |
767 | r4 = 0; \ |
768 | r8 = r2; \ |
769 | call %[bpf_map_update_elem]; \ |
770 | r1 = r6; \ |
771 | r2 = r8; \ |
772 | call %[bpf_map_lookup_elem]; \ |
773 | if r0 != 0 goto tjmp1; \ |
774 | exit; \ |
775 | tjmp1: \ |
776 | r8 = r0; \ |
777 | r1 = r7; \ |
778 | r2 = 8; \ |
779 | r3 = 0; \ |
780 | r4 = r10; \ |
781 | r4 += -16; \ |
782 | r0 = *(u64 *)(r0 + 0); \ |
783 | call %[bpf_ringbuf_reserve_dynptr]; \ |
784 | if r0 == 0 goto tjmp2; \ |
785 | r8 = r8; \ |
786 | r8 = r8; \ |
787 | r8 = r8; \ |
788 | r8 = r8; \ |
789 | r8 = r8; \ |
790 | r8 = r8; \ |
791 | r8 = r8; \ |
792 | goto tjmp3; \ |
793 | tjmp2: \ |
794 | *(u64 *)(r10 - 8) = r9; \ |
795 | *(u64 *)(r10 - 16) = r9; \ |
796 | r1 = r8; \ |
797 | r1 += 8; \ |
798 | r2 = 0; \ |
799 | r3 = 0; \ |
800 | r4 = r10; \ |
801 | r4 += -16; \ |
802 | call %[bpf_dynptr_from_mem]; \ |
803 | tjmp3: \ |
804 | r1 = r10; \ |
805 | r1 += -16; \ |
806 | r2 = 0; \ |
807 | call %[bpf_ringbuf_discard_dynptr]; " |
808 | : |
809 | : __imm(bpf_map_update_elem), |
810 | __imm(bpf_map_lookup_elem), |
811 | __imm(bpf_ringbuf_reserve_dynptr), |
812 | __imm(bpf_dynptr_from_mem), |
813 | __imm(bpf_ringbuf_discard_dynptr), |
814 | __imm_addr(array_map4), |
815 | __imm_addr(ringbuf) |
816 | : __clobber_all |
817 | ); |
818 | return 0; |
819 | } |
820 | |
821 | SEC("?tc" ) |
822 | __failure __msg("dynptr has to be at a constant offset" ) __log_level(2) |
823 | int dynptr_var_off_overwrite(struct __sk_buff *ctx) |
824 | { |
825 | asm volatile ( |
826 | "r9 = 16; \ |
827 | *(u32 *)(r10 - 4) = r9; \ |
828 | r8 = *(u32 *)(r10 - 4); \ |
829 | if r8 >= 0 goto vjmp1; \ |
830 | r0 = 1; \ |
831 | exit; \ |
832 | vjmp1: \ |
833 | if r8 <= 16 goto vjmp2; \ |
834 | r0 = 1; \ |
835 | exit; \ |
836 | vjmp2: \ |
837 | r8 &= 16; \ |
838 | r1 = %[ringbuf] ll; \ |
839 | r2 = 8; \ |
840 | r3 = 0; \ |
841 | r4 = r10; \ |
842 | r4 += -32; \ |
843 | r4 += r8; \ |
844 | call %[bpf_ringbuf_reserve_dynptr]; \ |
845 | r9 = 0xeB9F; \ |
846 | *(u64 *)(r10 - 16) = r9; \ |
847 | r1 = r10; \ |
848 | r1 += -32; \ |
849 | r1 += r8; \ |
850 | r2 = 0; \ |
851 | call %[bpf_ringbuf_discard_dynptr]; " |
852 | : |
853 | : __imm(bpf_ringbuf_reserve_dynptr), |
854 | __imm(bpf_ringbuf_discard_dynptr), |
855 | __imm_addr(ringbuf) |
856 | : __clobber_all |
857 | ); |
858 | return 0; |
859 | } |
860 | |
861 | SEC("?tc" ) |
862 | __failure __msg("cannot overwrite referenced dynptr" ) __log_level(2) |
863 | int dynptr_partial_slot_invalidate(struct __sk_buff *ctx) |
864 | { |
865 | asm volatile ( |
866 | "r6 = %[ringbuf] ll; \ |
867 | r7 = %[array_map4] ll; \ |
868 | r1 = r7; \ |
869 | r2 = r10; \ |
870 | r2 += -8; \ |
871 | r9 = 0; \ |
872 | *(u64 *)(r2 + 0) = r9; \ |
873 | r3 = r2; \ |
874 | r4 = 0; \ |
875 | r8 = r2; \ |
876 | call %[bpf_map_update_elem]; \ |
877 | r1 = r7; \ |
878 | r2 = r8; \ |
879 | call %[bpf_map_lookup_elem]; \ |
880 | if r0 != 0 goto sjmp1; \ |
881 | exit; \ |
882 | sjmp1: \ |
883 | r7 = r0; \ |
884 | r1 = r6; \ |
885 | r2 = 8; \ |
886 | r3 = 0; \ |
887 | r4 = r10; \ |
888 | r4 += -24; \ |
889 | call %[bpf_ringbuf_reserve_dynptr]; \ |
890 | *(u64 *)(r10 - 16) = r9; \ |
891 | r1 = r7; \ |
892 | r2 = 8; \ |
893 | r3 = 0; \ |
894 | r4 = r10; \ |
895 | r4 += -16; \ |
896 | call %[bpf_dynptr_from_mem]; \ |
897 | r1 = r10; \ |
898 | r1 += -512; \ |
899 | r2 = 488; \ |
900 | r3 = r10; \ |
901 | r3 += -24; \ |
902 | r4 = 0; \ |
903 | r5 = 0; \ |
904 | call %[bpf_dynptr_read]; \ |
905 | r8 = 1; \ |
906 | if r0 != 0 goto sjmp2; \ |
907 | r8 = 0; \ |
908 | sjmp2: \ |
909 | r1 = r10; \ |
910 | r1 += -24; \ |
911 | r2 = 0; \ |
912 | call %[bpf_ringbuf_discard_dynptr]; " |
913 | : |
914 | : __imm(bpf_map_update_elem), |
915 | __imm(bpf_map_lookup_elem), |
916 | __imm(bpf_ringbuf_reserve_dynptr), |
917 | __imm(bpf_ringbuf_discard_dynptr), |
918 | __imm(bpf_dynptr_from_mem), |
919 | __imm(bpf_dynptr_read), |
920 | __imm_addr(ringbuf), |
921 | __imm_addr(array_map4) |
922 | : __clobber_all |
923 | ); |
924 | return 0; |
925 | } |
926 | |
927 | /* Test that it is allowed to overwrite unreferenced dynptr. */ |
928 | SEC("?raw_tp" ) |
929 | __success |
930 | int dynptr_overwrite_unref(void *ctx) |
931 | { |
932 | struct bpf_dynptr ptr; |
933 | |
934 | if (get_map_val_dynptr(ptr: &ptr)) |
935 | return 0; |
936 | if (get_map_val_dynptr(ptr: &ptr)) |
937 | return 0; |
938 | if (get_map_val_dynptr(ptr: &ptr)) |
939 | return 0; |
940 | |
941 | return 0; |
942 | } |
943 | |
944 | /* Test that slices are invalidated on reinitializing a dynptr. */ |
945 | SEC("?raw_tp" ) |
946 | __failure __msg("invalid mem access 'scalar'" ) |
947 | int dynptr_invalidate_slice_reinit(void *ctx) |
948 | { |
949 | struct bpf_dynptr ptr; |
950 | __u8 *p; |
951 | |
952 | if (get_map_val_dynptr(ptr: &ptr)) |
953 | return 0; |
954 | p = bpf_dynptr_data(&ptr, 0, 1); |
955 | if (!p) |
956 | return 0; |
957 | if (get_map_val_dynptr(ptr: &ptr)) |
958 | return 0; |
959 | /* this should fail */ |
960 | return *p; |
961 | } |
962 | |
963 | /* Invalidation of dynptr slices on destruction of dynptr should not miss |
964 | * mem_or_null pointers. |
965 | */ |
966 | SEC("?raw_tp" ) |
967 | __failure __msg("R1 type=scalar expected=percpu_ptr_" ) |
968 | int dynptr_invalidate_slice_or_null(void *ctx) |
969 | { |
970 | struct bpf_dynptr ptr; |
971 | __u8 *p; |
972 | |
973 | if (get_map_val_dynptr(ptr: &ptr)) |
974 | return 0; |
975 | |
976 | p = bpf_dynptr_data(&ptr, 0, 1); |
977 | *(__u8 *)&ptr = 0; |
978 | /* this should fail */ |
979 | bpf_this_cpu_ptr(p); |
980 | return 0; |
981 | } |
982 | |
983 | /* Destruction of dynptr should also any slices obtained from it */ |
984 | SEC("?raw_tp" ) |
985 | __failure __msg("R7 invalid mem access 'scalar'" ) |
986 | int dynptr_invalidate_slice_failure(void *ctx) |
987 | { |
988 | struct bpf_dynptr ptr1; |
989 | struct bpf_dynptr ptr2; |
990 | __u8 *p1, *p2; |
991 | |
992 | if (get_map_val_dynptr(ptr: &ptr1)) |
993 | return 0; |
994 | if (get_map_val_dynptr(ptr: &ptr2)) |
995 | return 0; |
996 | |
997 | p1 = bpf_dynptr_data(&ptr1, 0, 1); |
998 | if (!p1) |
999 | return 0; |
1000 | p2 = bpf_dynptr_data(&ptr2, 0, 1); |
1001 | if (!p2) |
1002 | return 0; |
1003 | |
1004 | *(__u8 *)&ptr1 = 0; |
1005 | /* this should fail */ |
1006 | return *p1; |
1007 | } |
1008 | |
1009 | /* Invalidation of slices should be scoped and should not prevent dereferencing |
1010 | * slices of another dynptr after destroying unrelated dynptr |
1011 | */ |
1012 | SEC("?raw_tp" ) |
1013 | __success |
1014 | int dynptr_invalidate_slice_success(void *ctx) |
1015 | { |
1016 | struct bpf_dynptr ptr1; |
1017 | struct bpf_dynptr ptr2; |
1018 | __u8 *p1, *p2; |
1019 | |
1020 | if (get_map_val_dynptr(ptr: &ptr1)) |
1021 | return 1; |
1022 | if (get_map_val_dynptr(ptr: &ptr2)) |
1023 | return 1; |
1024 | |
1025 | p1 = bpf_dynptr_data(&ptr1, 0, 1); |
1026 | if (!p1) |
1027 | return 1; |
1028 | p2 = bpf_dynptr_data(&ptr2, 0, 1); |
1029 | if (!p2) |
1030 | return 1; |
1031 | |
1032 | *(__u8 *)&ptr1 = 0; |
1033 | return *p2; |
1034 | } |
1035 | |
1036 | /* Overwriting referenced dynptr should be rejected */ |
1037 | SEC("?raw_tp" ) |
1038 | __failure __msg("cannot overwrite referenced dynptr" ) |
1039 | int dynptr_overwrite_ref(void *ctx) |
1040 | { |
1041 | struct bpf_dynptr ptr; |
1042 | |
1043 | bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr); |
1044 | /* this should fail */ |
1045 | if (get_map_val_dynptr(ptr: &ptr)) |
1046 | bpf_ringbuf_discard_dynptr(&ptr, 0); |
1047 | return 0; |
1048 | } |
1049 | |
1050 | /* Reject writes to dynptr slot from bpf_dynptr_read */ |
1051 | SEC("?raw_tp" ) |
1052 | __failure __msg("potential write to dynptr at off=-16" ) |
1053 | int dynptr_read_into_slot(void *ctx) |
1054 | { |
1055 | union { |
1056 | struct { |
1057 | char _pad[48]; |
1058 | struct bpf_dynptr ptr; |
1059 | }; |
1060 | char buf[64]; |
1061 | } data; |
1062 | |
1063 | bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &data.ptr); |
1064 | /* this should fail */ |
1065 | bpf_dynptr_read(data.buf, sizeof(data.buf), &data.ptr, 0, 0); |
1066 | |
1067 | return 0; |
1068 | } |
1069 | |
1070 | /* bpf_dynptr_slice()s are read-only and cannot be written to */ |
1071 | SEC("?tc" ) |
1072 | __failure __msg("R0 cannot write into rdonly_mem" ) |
1073 | int skb_invalid_slice_write(struct __sk_buff *skb) |
1074 | { |
1075 | struct bpf_dynptr ptr; |
1076 | struct ethhdr *hdr; |
1077 | char buffer[sizeof(*hdr)] = {}; |
1078 | |
1079 | bpf_dynptr_from_skb(skb, 0, &ptr); |
1080 | |
1081 | hdr = bpf_dynptr_slice(&ptr, 0, buffer, sizeof(buffer)); |
1082 | if (!hdr) |
1083 | return SK_DROP; |
1084 | |
1085 | /* this should fail */ |
1086 | hdr->h_proto = 1; |
1087 | |
1088 | return SK_PASS; |
1089 | } |
1090 | |
1091 | /* The read-only data slice is invalidated whenever a helper changes packet data */ |
1092 | SEC("?tc" ) |
1093 | __failure __msg("invalid mem access 'scalar'" ) |
1094 | int skb_invalid_data_slice1(struct __sk_buff *skb) |
1095 | { |
1096 | struct bpf_dynptr ptr; |
1097 | struct ethhdr *hdr; |
1098 | char buffer[sizeof(*hdr)] = {}; |
1099 | |
1100 | bpf_dynptr_from_skb(skb, 0, &ptr); |
1101 | |
1102 | hdr = bpf_dynptr_slice(&ptr, 0, buffer, sizeof(buffer)); |
1103 | if (!hdr) |
1104 | return SK_DROP; |
1105 | |
1106 | val = hdr->h_proto; |
1107 | |
1108 | if (bpf_skb_pull_data(skb, skb->len)) |
1109 | return SK_DROP; |
1110 | |
1111 | /* this should fail */ |
1112 | val = hdr->h_proto; |
1113 | |
1114 | return SK_PASS; |
1115 | } |
1116 | |
1117 | /* The read-write data slice is invalidated whenever a helper changes packet data */ |
1118 | SEC("?tc" ) |
1119 | __failure __msg("invalid mem access 'scalar'" ) |
1120 | int skb_invalid_data_slice2(struct __sk_buff *skb) |
1121 | { |
1122 | struct bpf_dynptr ptr; |
1123 | struct ethhdr *hdr; |
1124 | char buffer[sizeof(*hdr)] = {}; |
1125 | |
1126 | bpf_dynptr_from_skb(skb, 0, &ptr); |
1127 | |
1128 | hdr = bpf_dynptr_slice_rdwr(&ptr, 0, buffer, sizeof(buffer)); |
1129 | if (!hdr) |
1130 | return SK_DROP; |
1131 | |
1132 | hdr->h_proto = 123; |
1133 | |
1134 | if (bpf_skb_pull_data(skb, skb->len)) |
1135 | return SK_DROP; |
1136 | |
1137 | /* this should fail */ |
1138 | hdr->h_proto = 1; |
1139 | |
1140 | return SK_PASS; |
1141 | } |
1142 | |
1143 | /* The read-only data slice is invalidated whenever bpf_dynptr_write() is called */ |
1144 | SEC("?tc" ) |
1145 | __failure __msg("invalid mem access 'scalar'" ) |
1146 | int skb_invalid_data_slice3(struct __sk_buff *skb) |
1147 | { |
1148 | char write_data[64] = "hello there, world!!" ; |
1149 | struct bpf_dynptr ptr; |
1150 | struct ethhdr *hdr; |
1151 | char buffer[sizeof(*hdr)] = {}; |
1152 | |
1153 | bpf_dynptr_from_skb(skb, 0, &ptr); |
1154 | |
1155 | hdr = bpf_dynptr_slice(&ptr, 0, buffer, sizeof(buffer)); |
1156 | if (!hdr) |
1157 | return SK_DROP; |
1158 | |
1159 | val = hdr->h_proto; |
1160 | |
1161 | bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0); |
1162 | |
1163 | /* this should fail */ |
1164 | val = hdr->h_proto; |
1165 | |
1166 | return SK_PASS; |
1167 | } |
1168 | |
1169 | /* The read-write data slice is invalidated whenever bpf_dynptr_write() is called */ |
1170 | SEC("?tc" ) |
1171 | __failure __msg("invalid mem access 'scalar'" ) |
1172 | int skb_invalid_data_slice4(struct __sk_buff *skb) |
1173 | { |
1174 | char write_data[64] = "hello there, world!!" ; |
1175 | struct bpf_dynptr ptr; |
1176 | struct ethhdr *hdr; |
1177 | char buffer[sizeof(*hdr)] = {}; |
1178 | |
1179 | bpf_dynptr_from_skb(skb, 0, &ptr); |
1180 | hdr = bpf_dynptr_slice_rdwr(&ptr, 0, buffer, sizeof(buffer)); |
1181 | if (!hdr) |
1182 | return SK_DROP; |
1183 | |
1184 | hdr->h_proto = 123; |
1185 | |
1186 | bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0); |
1187 | |
1188 | /* this should fail */ |
1189 | hdr->h_proto = 1; |
1190 | |
1191 | return SK_PASS; |
1192 | } |
1193 | |
1194 | /* The read-only data slice is invalidated whenever a helper changes packet data */ |
1195 | SEC("?xdp" ) |
1196 | __failure __msg("invalid mem access 'scalar'" ) |
1197 | int xdp_invalid_data_slice1(struct xdp_md *xdp) |
1198 | { |
1199 | struct bpf_dynptr ptr; |
1200 | struct ethhdr *hdr; |
1201 | char buffer[sizeof(*hdr)] = {}; |
1202 | |
1203 | bpf_dynptr_from_xdp(xdp, 0, &ptr); |
1204 | hdr = bpf_dynptr_slice(&ptr, 0, buffer, sizeof(buffer)); |
1205 | if (!hdr) |
1206 | return SK_DROP; |
1207 | |
1208 | val = hdr->h_proto; |
1209 | |
1210 | if (bpf_xdp_adjust_head(xdp, 0 - (int)sizeof(*hdr))) |
1211 | return XDP_DROP; |
1212 | |
1213 | /* this should fail */ |
1214 | val = hdr->h_proto; |
1215 | |
1216 | return XDP_PASS; |
1217 | } |
1218 | |
1219 | /* The read-write data slice is invalidated whenever a helper changes packet data */ |
1220 | SEC("?xdp" ) |
1221 | __failure __msg("invalid mem access 'scalar'" ) |
1222 | int xdp_invalid_data_slice2(struct xdp_md *xdp) |
1223 | { |
1224 | struct bpf_dynptr ptr; |
1225 | struct ethhdr *hdr; |
1226 | char buffer[sizeof(*hdr)] = {}; |
1227 | |
1228 | bpf_dynptr_from_xdp(xdp, 0, &ptr); |
1229 | hdr = bpf_dynptr_slice_rdwr(&ptr, 0, buffer, sizeof(buffer)); |
1230 | if (!hdr) |
1231 | return SK_DROP; |
1232 | |
1233 | hdr->h_proto = 9; |
1234 | |
1235 | if (bpf_xdp_adjust_head(xdp, 0 - (int)sizeof(*hdr))) |
1236 | return XDP_DROP; |
1237 | |
1238 | /* this should fail */ |
1239 | hdr->h_proto = 1; |
1240 | |
1241 | return XDP_PASS; |
1242 | } |
1243 | |
1244 | /* Only supported prog type can create skb-type dynptrs */ |
1245 | SEC("?raw_tp" ) |
1246 | __failure __msg("calling kernel function bpf_dynptr_from_skb is not allowed" ) |
1247 | int skb_invalid_ctx(void *ctx) |
1248 | { |
1249 | struct bpf_dynptr ptr; |
1250 | |
1251 | /* this should fail */ |
1252 | bpf_dynptr_from_skb(ctx, 0, &ptr); |
1253 | |
1254 | return 0; |
1255 | } |
1256 | |
1257 | /* Reject writes to dynptr slot for uninit arg */ |
1258 | SEC("?raw_tp" ) |
1259 | __failure __msg("potential write to dynptr at off=-16" ) |
1260 | int uninit_write_into_slot(void *ctx) |
1261 | { |
1262 | struct { |
1263 | char buf[64]; |
1264 | struct bpf_dynptr ptr; |
1265 | } data; |
1266 | |
1267 | bpf_ringbuf_reserve_dynptr(&ringbuf, 80, 0, &data.ptr); |
1268 | /* this should fail */ |
1269 | bpf_get_current_comm(data.buf, 80); |
1270 | |
1271 | return 0; |
1272 | } |
1273 | |
1274 | /* Only supported prog type can create xdp-type dynptrs */ |
1275 | SEC("?raw_tp" ) |
1276 | __failure __msg("calling kernel function bpf_dynptr_from_xdp is not allowed" ) |
1277 | int xdp_invalid_ctx(void *ctx) |
1278 | { |
1279 | struct bpf_dynptr ptr; |
1280 | |
1281 | /* this should fail */ |
1282 | bpf_dynptr_from_xdp(ctx, 0, &ptr); |
1283 | |
1284 | return 0; |
1285 | } |
1286 | |
1287 | __u32 hdr_size = sizeof(struct ethhdr); |
1288 | /* Can't pass in variable-sized len to bpf_dynptr_slice */ |
1289 | SEC("?tc" ) |
1290 | __failure __msg("unbounded memory access" ) |
1291 | int dynptr_slice_var_len1(struct __sk_buff *skb) |
1292 | { |
1293 | struct bpf_dynptr ptr; |
1294 | struct ethhdr *hdr; |
1295 | char buffer[sizeof(*hdr)] = {}; |
1296 | |
1297 | bpf_dynptr_from_skb(skb, 0, &ptr); |
1298 | |
1299 | /* this should fail */ |
1300 | hdr = bpf_dynptr_slice(&ptr, 0, buffer, hdr_size); |
1301 | if (!hdr) |
1302 | return SK_DROP; |
1303 | |
1304 | return SK_PASS; |
1305 | } |
1306 | |
1307 | /* Can't pass in variable-sized len to bpf_dynptr_slice */ |
1308 | SEC("?tc" ) |
1309 | __failure __msg("must be a known constant" ) |
1310 | int dynptr_slice_var_len2(struct __sk_buff *skb) |
1311 | { |
1312 | char buffer[sizeof(struct ethhdr)] = {}; |
1313 | struct bpf_dynptr ptr; |
1314 | struct ethhdr *hdr; |
1315 | |
1316 | bpf_dynptr_from_skb(skb, 0, &ptr); |
1317 | |
1318 | if (hdr_size <= sizeof(buffer)) { |
1319 | /* this should fail */ |
1320 | hdr = bpf_dynptr_slice_rdwr(&ptr, 0, buffer, hdr_size); |
1321 | if (!hdr) |
1322 | return SK_DROP; |
1323 | hdr->h_proto = 12; |
1324 | } |
1325 | |
1326 | return SK_PASS; |
1327 | } |
1328 | |
1329 | static int callback(__u32 index, void *data) |
1330 | { |
1331 | *(__u32 *)data = 123; |
1332 | |
1333 | return 0; |
1334 | } |
1335 | |
1336 | /* If the dynptr is written into in a callback function, its data |
1337 | * slices should be invalidated as well. |
1338 | */ |
1339 | SEC("?raw_tp" ) |
1340 | __failure __msg("invalid mem access 'scalar'" ) |
1341 | int invalid_data_slices(void *ctx) |
1342 | { |
1343 | struct bpf_dynptr ptr; |
1344 | __u32 *slice; |
1345 | |
1346 | if (get_map_val_dynptr(ptr: &ptr)) |
1347 | return 0; |
1348 | |
1349 | slice = bpf_dynptr_data(&ptr, 0, sizeof(__u32)); |
1350 | if (!slice) |
1351 | return 0; |
1352 | |
1353 | bpf_loop(10, callback, &ptr, 0); |
1354 | |
1355 | /* this should fail */ |
1356 | *slice = 1; |
1357 | |
1358 | return 0; |
1359 | } |
1360 | |
1361 | /* Program types that don't allow writes to packet data should fail if |
1362 | * bpf_dynptr_slice_rdwr is called |
1363 | */ |
1364 | SEC("cgroup_skb/ingress" ) |
1365 | __failure __msg("the prog does not allow writes to packet data" ) |
1366 | int invalid_slice_rdwr_rdonly(struct __sk_buff *skb) |
1367 | { |
1368 | char buffer[sizeof(struct ethhdr)] = {}; |
1369 | struct bpf_dynptr ptr; |
1370 | struct ethhdr *hdr; |
1371 | |
1372 | bpf_dynptr_from_skb(skb, 0, &ptr); |
1373 | |
1374 | /* this should fail since cgroup_skb doesn't allow |
1375 | * changing packet data |
1376 | */ |
1377 | hdr = bpf_dynptr_slice_rdwr(&ptr, 0, buffer, sizeof(buffer)); |
1378 | __sink(hdr); |
1379 | |
1380 | return 0; |
1381 | } |
1382 | |
1383 | /* bpf_dynptr_adjust can only be called on initialized dynptrs */ |
1384 | SEC("?raw_tp" ) |
1385 | __failure __msg("Expected an initialized dynptr as arg #1" ) |
1386 | int dynptr_adjust_invalid(void *ctx) |
1387 | { |
1388 | struct bpf_dynptr ptr; |
1389 | |
1390 | /* this should fail */ |
1391 | bpf_dynptr_adjust(&ptr, 1, 2); |
1392 | |
1393 | return 0; |
1394 | } |
1395 | |
1396 | /* bpf_dynptr_is_null can only be called on initialized dynptrs */ |
1397 | SEC("?raw_tp" ) |
1398 | __failure __msg("Expected an initialized dynptr as arg #1" ) |
1399 | int dynptr_is_null_invalid(void *ctx) |
1400 | { |
1401 | struct bpf_dynptr ptr; |
1402 | |
1403 | /* this should fail */ |
1404 | bpf_dynptr_is_null(&ptr); |
1405 | |
1406 | return 0; |
1407 | } |
1408 | |
1409 | /* bpf_dynptr_is_rdonly can only be called on initialized dynptrs */ |
1410 | SEC("?raw_tp" ) |
1411 | __failure __msg("Expected an initialized dynptr as arg #1" ) |
1412 | int dynptr_is_rdonly_invalid(void *ctx) |
1413 | { |
1414 | struct bpf_dynptr ptr; |
1415 | |
1416 | /* this should fail */ |
1417 | bpf_dynptr_is_rdonly(&ptr); |
1418 | |
1419 | return 0; |
1420 | } |
1421 | |
1422 | /* bpf_dynptr_size can only be called on initialized dynptrs */ |
1423 | SEC("?raw_tp" ) |
1424 | __failure __msg("Expected an initialized dynptr as arg #1" ) |
1425 | int dynptr_size_invalid(void *ctx) |
1426 | { |
1427 | struct bpf_dynptr ptr; |
1428 | |
1429 | /* this should fail */ |
1430 | bpf_dynptr_size(&ptr); |
1431 | |
1432 | return 0; |
1433 | } |
1434 | |
1435 | /* Only initialized dynptrs can be cloned */ |
1436 | SEC("?raw_tp" ) |
1437 | __failure __msg("Expected an initialized dynptr as arg #1" ) |
1438 | int clone_invalid1(void *ctx) |
1439 | { |
1440 | struct bpf_dynptr ptr1; |
1441 | struct bpf_dynptr ptr2; |
1442 | |
1443 | /* this should fail */ |
1444 | bpf_dynptr_clone(&ptr1, &ptr2); |
1445 | |
1446 | return 0; |
1447 | } |
1448 | |
1449 | /* Can't overwrite an existing dynptr when cloning */ |
1450 | SEC("?xdp" ) |
1451 | __failure __msg("cannot overwrite referenced dynptr" ) |
1452 | int clone_invalid2(struct xdp_md *xdp) |
1453 | { |
1454 | struct bpf_dynptr ptr1; |
1455 | struct bpf_dynptr clone; |
1456 | |
1457 | bpf_dynptr_from_xdp(xdp, 0, &ptr1); |
1458 | |
1459 | bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &clone); |
1460 | |
1461 | /* this should fail */ |
1462 | bpf_dynptr_clone(&ptr1, &clone); |
1463 | |
1464 | bpf_ringbuf_submit_dynptr(&clone, 0); |
1465 | |
1466 | return 0; |
1467 | } |
1468 | |
1469 | /* Invalidating a dynptr should invalidate its clones */ |
1470 | SEC("?raw_tp" ) |
1471 | __failure __msg("Expected an initialized dynptr as arg #3" ) |
1472 | int clone_invalidate1(void *ctx) |
1473 | { |
1474 | struct bpf_dynptr clone; |
1475 | struct bpf_dynptr ptr; |
1476 | char read_data[64]; |
1477 | |
1478 | bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); |
1479 | |
1480 | bpf_dynptr_clone(&ptr, &clone); |
1481 | |
1482 | bpf_ringbuf_submit_dynptr(&ptr, 0); |
1483 | |
1484 | /* this should fail */ |
1485 | bpf_dynptr_read(read_data, sizeof(read_data), &clone, 0, 0); |
1486 | |
1487 | return 0; |
1488 | } |
1489 | |
1490 | /* Invalidating a dynptr should invalidate its parent */ |
1491 | SEC("?raw_tp" ) |
1492 | __failure __msg("Expected an initialized dynptr as arg #3" ) |
1493 | int clone_invalidate2(void *ctx) |
1494 | { |
1495 | struct bpf_dynptr ptr; |
1496 | struct bpf_dynptr clone; |
1497 | char read_data[64]; |
1498 | |
1499 | bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); |
1500 | |
1501 | bpf_dynptr_clone(&ptr, &clone); |
1502 | |
1503 | bpf_ringbuf_submit_dynptr(&clone, 0); |
1504 | |
1505 | /* this should fail */ |
1506 | bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0); |
1507 | |
1508 | return 0; |
1509 | } |
1510 | |
1511 | /* Invalidating a dynptr should invalidate its siblings */ |
1512 | SEC("?raw_tp" ) |
1513 | __failure __msg("Expected an initialized dynptr as arg #3" ) |
1514 | int clone_invalidate3(void *ctx) |
1515 | { |
1516 | struct bpf_dynptr ptr; |
1517 | struct bpf_dynptr clone1; |
1518 | struct bpf_dynptr clone2; |
1519 | char read_data[64]; |
1520 | |
1521 | bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); |
1522 | |
1523 | bpf_dynptr_clone(&ptr, &clone1); |
1524 | |
1525 | bpf_dynptr_clone(&ptr, &clone2); |
1526 | |
1527 | bpf_ringbuf_submit_dynptr(&clone2, 0); |
1528 | |
1529 | /* this should fail */ |
1530 | bpf_dynptr_read(read_data, sizeof(read_data), &clone1, 0, 0); |
1531 | |
1532 | return 0; |
1533 | } |
1534 | |
1535 | /* Invalidating a dynptr should invalidate any data slices |
1536 | * of its clones |
1537 | */ |
1538 | SEC("?raw_tp" ) |
1539 | __failure __msg("invalid mem access 'scalar'" ) |
1540 | int clone_invalidate4(void *ctx) |
1541 | { |
1542 | struct bpf_dynptr ptr; |
1543 | struct bpf_dynptr clone; |
1544 | int *data; |
1545 | |
1546 | bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); |
1547 | |
1548 | bpf_dynptr_clone(&ptr, &clone); |
1549 | data = bpf_dynptr_data(&clone, 0, sizeof(val)); |
1550 | if (!data) |
1551 | return 0; |
1552 | |
1553 | bpf_ringbuf_submit_dynptr(&ptr, 0); |
1554 | |
1555 | /* this should fail */ |
1556 | *data = 123; |
1557 | |
1558 | return 0; |
1559 | } |
1560 | |
1561 | /* Invalidating a dynptr should invalidate any data slices |
1562 | * of its parent |
1563 | */ |
1564 | SEC("?raw_tp" ) |
1565 | __failure __msg("invalid mem access 'scalar'" ) |
1566 | int clone_invalidate5(void *ctx) |
1567 | { |
1568 | struct bpf_dynptr ptr; |
1569 | struct bpf_dynptr clone; |
1570 | int *data; |
1571 | |
1572 | bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); |
1573 | data = bpf_dynptr_data(&ptr, 0, sizeof(val)); |
1574 | if (!data) |
1575 | return 0; |
1576 | |
1577 | bpf_dynptr_clone(&ptr, &clone); |
1578 | |
1579 | bpf_ringbuf_submit_dynptr(&clone, 0); |
1580 | |
1581 | /* this should fail */ |
1582 | *data = 123; |
1583 | |
1584 | return 0; |
1585 | } |
1586 | |
1587 | /* Invalidating a dynptr should invalidate any data slices |
1588 | * of its sibling |
1589 | */ |
1590 | SEC("?raw_tp" ) |
1591 | __failure __msg("invalid mem access 'scalar'" ) |
1592 | int clone_invalidate6(void *ctx) |
1593 | { |
1594 | struct bpf_dynptr ptr; |
1595 | struct bpf_dynptr clone1; |
1596 | struct bpf_dynptr clone2; |
1597 | int *data; |
1598 | |
1599 | bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); |
1600 | |
1601 | bpf_dynptr_clone(&ptr, &clone1); |
1602 | |
1603 | bpf_dynptr_clone(&ptr, &clone2); |
1604 | |
1605 | data = bpf_dynptr_data(&clone1, 0, sizeof(val)); |
1606 | if (!data) |
1607 | return 0; |
1608 | |
1609 | bpf_ringbuf_submit_dynptr(&clone2, 0); |
1610 | |
1611 | /* this should fail */ |
1612 | *data = 123; |
1613 | |
1614 | return 0; |
1615 | } |
1616 | |
1617 | /* A skb clone's data slices should be invalid anytime packet data changes */ |
1618 | SEC("?tc" ) |
1619 | __failure __msg("invalid mem access 'scalar'" ) |
1620 | int clone_skb_packet_data(struct __sk_buff *skb) |
1621 | { |
1622 | char buffer[sizeof(__u32)] = {}; |
1623 | struct bpf_dynptr clone; |
1624 | struct bpf_dynptr ptr; |
1625 | __u32 *data; |
1626 | |
1627 | bpf_dynptr_from_skb(skb, 0, &ptr); |
1628 | |
1629 | bpf_dynptr_clone(&ptr, &clone); |
1630 | data = bpf_dynptr_slice_rdwr(&clone, 0, buffer, sizeof(buffer)); |
1631 | if (!data) |
1632 | return XDP_DROP; |
1633 | |
1634 | if (bpf_skb_pull_data(skb, skb->len)) |
1635 | return SK_DROP; |
1636 | |
1637 | /* this should fail */ |
1638 | *data = 123; |
1639 | |
1640 | return 0; |
1641 | } |
1642 | |
1643 | /* A xdp clone's data slices should be invalid anytime packet data changes */ |
1644 | SEC("?xdp" ) |
1645 | __failure __msg("invalid mem access 'scalar'" ) |
1646 | int clone_xdp_packet_data(struct xdp_md *xdp) |
1647 | { |
1648 | char buffer[sizeof(__u32)] = {}; |
1649 | struct bpf_dynptr clone; |
1650 | struct bpf_dynptr ptr; |
1651 | struct ethhdr *hdr; |
1652 | __u32 *data; |
1653 | |
1654 | bpf_dynptr_from_xdp(xdp, 0, &ptr); |
1655 | |
1656 | bpf_dynptr_clone(&ptr, &clone); |
1657 | data = bpf_dynptr_slice_rdwr(&clone, 0, buffer, sizeof(buffer)); |
1658 | if (!data) |
1659 | return XDP_DROP; |
1660 | |
1661 | if (bpf_xdp_adjust_head(xdp, 0 - (int)sizeof(*hdr))) |
1662 | return XDP_DROP; |
1663 | |
1664 | /* this should fail */ |
1665 | *data = 123; |
1666 | |
1667 | return 0; |
1668 | } |
1669 | |
1670 | /* Buffers that are provided must be sufficiently long */ |
1671 | SEC("?cgroup_skb/egress" ) |
1672 | __failure __msg("memory, len pair leads to invalid memory access" ) |
1673 | int test_dynptr_skb_small_buff(struct __sk_buff *skb) |
1674 | { |
1675 | struct bpf_dynptr ptr; |
1676 | char buffer[8] = {}; |
1677 | __u64 *data; |
1678 | |
1679 | if (bpf_dynptr_from_skb(skb, 0, &ptr)) { |
1680 | err = 1; |
1681 | return 1; |
1682 | } |
1683 | |
1684 | /* This may return NULL. SKB may require a buffer */ |
1685 | data = bpf_dynptr_slice(&ptr, 0, buffer, 9); |
1686 | |
1687 | return !!data; |
1688 | } |
1689 | |