1 // SPDX-License-Identifier: GPL-2.0
2 /* Converted from tools/testing/selftests/bpf/verifier/ref_tracking.c */
3
4 #include <linux/bpf.h>
5 #include <bpf/bpf_helpers.h>
6 #include "../../../include/linux/filter.h"
7 #include "bpf_misc.h"
8
9 #define BPF_SK_LOOKUP(func) \
10 /* struct bpf_sock_tuple tuple = {} */ \
11 "r2 = 0;" \
12 "*(u32*)(r10 - 8) = r2;" \
13 "*(u64*)(r10 - 16) = r2;" \
14 "*(u64*)(r10 - 24) = r2;" \
15 "*(u64*)(r10 - 32) = r2;" \
16 "*(u64*)(r10 - 40) = r2;" \
17 "*(u64*)(r10 - 48) = r2;" \
18 /* sk = func(ctx, &tuple, sizeof tuple, 0, 0) */ \
19 "r2 = r10;" \
20 "r2 += -48;" \
21 "r3 = %[sizeof_bpf_sock_tuple];"\
22 "r4 = 0;" \
23 "r5 = 0;" \
24 "call %[" #func "];"
25
26 struct bpf_key {} __attribute__((preserve_access_index));
27
28 extern void bpf_key_put(struct bpf_key *key) __ksym;
29 extern struct bpf_key *bpf_lookup_system_key(__u64 id) __ksym;
30 extern struct bpf_key *bpf_lookup_user_key(__u32 serial, __u64 flags) __ksym;
31
32 /* BTF FUNC records are not generated for kfuncs referenced
33 * from inline assembly. These records are necessary for
34 * libbpf to link the program. The function below is a hack
35 * to ensure that BTF FUNC records are generated.
36 */
__kfunc_btf_root(void)37 void __kfunc_btf_root(void)
38 {
39 bpf_key_put(0);
40 bpf_lookup_system_key(0);
41 bpf_lookup_user_key(0, 0);
42 }
43
44 #define MAX_ENTRIES 11
45
46 struct test_val {
47 unsigned int index;
48 int foo[MAX_ENTRIES];
49 };
50
51 struct {
52 __uint(type, BPF_MAP_TYPE_ARRAY);
53 __uint(max_entries, 1);
54 __type(key, int);
55 __type(value, struct test_val);
56 } map_array_48b SEC(".maps");
57
58 struct {
59 __uint(type, BPF_MAP_TYPE_RINGBUF);
60 __uint(max_entries, 4096);
61 } map_ringbuf SEC(".maps");
62
63 void dummy_prog_42_tc(void);
64 void dummy_prog_24_tc(void);
65 void dummy_prog_loop1_tc(void);
66
67 struct {
68 __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
69 __uint(max_entries, 4);
70 __uint(key_size, sizeof(int));
71 __array(values, void (void));
72 } map_prog1_tc SEC(".maps") = {
73 .values = {
74 [0] = (void *)&dummy_prog_42_tc,
75 [1] = (void *)&dummy_prog_loop1_tc,
76 [2] = (void *)&dummy_prog_24_tc,
77 },
78 };
79
80 SEC("tc")
81 __auxiliary
dummy_prog_42_tc(void)82 __naked void dummy_prog_42_tc(void)
83 {
84 asm volatile ("r0 = 42; exit;");
85 }
86
87 SEC("tc")
88 __auxiliary
dummy_prog_24_tc(void)89 __naked void dummy_prog_24_tc(void)
90 {
91 asm volatile ("r0 = 24; exit;");
92 }
93
94 SEC("tc")
95 __auxiliary
dummy_prog_loop1_tc(void)96 __naked void dummy_prog_loop1_tc(void)
97 {
98 asm volatile (" \
99 r3 = 1; \
100 r2 = %[map_prog1_tc] ll; \
101 call %[bpf_tail_call]; \
102 r0 = 41; \
103 exit; \
104 " :
105 : __imm(bpf_tail_call),
106 __imm_addr(map_prog1_tc)
107 : __clobber_all);
108 }
109
110 SEC("tc")
111 __description("reference tracking: leak potential reference")
112 __failure __msg("Unreleased reference")
reference_tracking_leak_potential_reference(void)113 __naked void reference_tracking_leak_potential_reference(void)
114 {
115 asm volatile (
116 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
117 " r6 = r0; /* leak reference */ \
118 exit; \
119 " :
120 : __imm(bpf_sk_lookup_tcp),
121 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
122 : __clobber_all);
123 }
124
125 SEC("tc")
126 __description("reference tracking: leak potential reference to sock_common")
127 __failure __msg("Unreleased reference")
potential_reference_to_sock_common_1(void)128 __naked void potential_reference_to_sock_common_1(void)
129 {
130 asm volatile (
131 BPF_SK_LOOKUP(bpf_skc_lookup_tcp)
132 " r6 = r0; /* leak reference */ \
133 exit; \
134 " :
135 : __imm(bpf_skc_lookup_tcp),
136 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
137 : __clobber_all);
138 }
139
140 SEC("tc")
141 __description("reference tracking: leak potential reference on stack")
142 __failure __msg("Unreleased reference")
leak_potential_reference_on_stack(void)143 __naked void leak_potential_reference_on_stack(void)
144 {
145 asm volatile (
146 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
147 " r4 = r10; \
148 r4 += -8; \
149 *(u64*)(r4 + 0) = r0; \
150 r0 = 0; \
151 exit; \
152 " :
153 : __imm(bpf_sk_lookup_tcp),
154 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
155 : __clobber_all);
156 }
157
158 SEC("tc")
159 __description("reference tracking: leak potential reference on stack 2")
160 __failure __msg("Unreleased reference")
potential_reference_on_stack_2(void)161 __naked void potential_reference_on_stack_2(void)
162 {
163 asm volatile (
164 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
165 " r4 = r10; \
166 r4 += -8; \
167 *(u64*)(r4 + 0) = r0; \
168 r0 = 0; \
169 r1 = 0; \
170 *(u64*)(r4 + 0) = r1; \
171 exit; \
172 " :
173 : __imm(bpf_sk_lookup_tcp),
174 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
175 : __clobber_all);
176 }
177
178 SEC("tc")
179 __description("reference tracking: zero potential reference")
180 __failure __msg("Unreleased reference")
reference_tracking_zero_potential_reference(void)181 __naked void reference_tracking_zero_potential_reference(void)
182 {
183 asm volatile (
184 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
185 " r0 = 0; /* leak reference */ \
186 exit; \
187 " :
188 : __imm(bpf_sk_lookup_tcp),
189 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
190 : __clobber_all);
191 }
192
193 SEC("tc")
194 __description("reference tracking: zero potential reference to sock_common")
195 __failure __msg("Unreleased reference")
potential_reference_to_sock_common_2(void)196 __naked void potential_reference_to_sock_common_2(void)
197 {
198 asm volatile (
199 BPF_SK_LOOKUP(bpf_skc_lookup_tcp)
200 " r0 = 0; /* leak reference */ \
201 exit; \
202 " :
203 : __imm(bpf_skc_lookup_tcp),
204 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
205 : __clobber_all);
206 }
207
208 SEC("tc")
209 __description("reference tracking: copy and zero potential references")
210 __failure __msg("Unreleased reference")
copy_and_zero_potential_references(void)211 __naked void copy_and_zero_potential_references(void)
212 {
213 asm volatile (
214 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
215 " r7 = r0; \
216 r0 = 0; \
217 r7 = 0; /* leak reference */ \
218 exit; \
219 " :
220 : __imm(bpf_sk_lookup_tcp),
221 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
222 : __clobber_all);
223 }
224
225 SEC("lsm.s/bpf")
226 __description("reference tracking: acquire/release user key reference")
227 __success
acquire_release_user_key_reference(void)228 __naked void acquire_release_user_key_reference(void)
229 {
230 asm volatile (" \
231 r1 = -3; \
232 r2 = 0; \
233 call %[bpf_lookup_user_key]; \
234 if r0 == 0 goto l0_%=; \
235 r1 = r0; \
236 call %[bpf_key_put]; \
237 l0_%=: r0 = 0; \
238 exit; \
239 " :
240 : __imm(bpf_key_put),
241 __imm(bpf_lookup_user_key)
242 : __clobber_all);
243 }
244
245 SEC("lsm.s/bpf")
246 __description("reference tracking: acquire/release system key reference")
247 __success
acquire_release_system_key_reference(void)248 __naked void acquire_release_system_key_reference(void)
249 {
250 asm volatile (" \
251 r1 = 1; \
252 call %[bpf_lookup_system_key]; \
253 if r0 == 0 goto l0_%=; \
254 r1 = r0; \
255 call %[bpf_key_put]; \
256 l0_%=: r0 = 0; \
257 exit; \
258 " :
259 : __imm(bpf_key_put),
260 __imm(bpf_lookup_system_key)
261 : __clobber_all);
262 }
263
264 SEC("lsm.s/bpf")
265 __description("reference tracking: release user key reference without check")
266 __failure __msg("Possibly NULL pointer passed to trusted arg0")
user_key_reference_without_check(void)267 __naked void user_key_reference_without_check(void)
268 {
269 asm volatile (" \
270 r1 = -3; \
271 r2 = 0; \
272 call %[bpf_lookup_user_key]; \
273 r1 = r0; \
274 call %[bpf_key_put]; \
275 r0 = 0; \
276 exit; \
277 " :
278 : __imm(bpf_key_put),
279 __imm(bpf_lookup_user_key)
280 : __clobber_all);
281 }
282
283 SEC("lsm.s/bpf")
284 __description("reference tracking: release system key reference without check")
285 __failure __msg("Possibly NULL pointer passed to trusted arg0")
system_key_reference_without_check(void)286 __naked void system_key_reference_without_check(void)
287 {
288 asm volatile (" \
289 r1 = 1; \
290 call %[bpf_lookup_system_key]; \
291 r1 = r0; \
292 call %[bpf_key_put]; \
293 r0 = 0; \
294 exit; \
295 " :
296 : __imm(bpf_key_put),
297 __imm(bpf_lookup_system_key)
298 : __clobber_all);
299 }
300
301 SEC("lsm.s/bpf")
302 __description("reference tracking: release with NULL key pointer")
303 __failure __msg("Possibly NULL pointer passed to trusted arg0")
release_with_null_key_pointer(void)304 __naked void release_with_null_key_pointer(void)
305 {
306 asm volatile (" \
307 r1 = 0; \
308 call %[bpf_key_put]; \
309 r0 = 0; \
310 exit; \
311 " :
312 : __imm(bpf_key_put)
313 : __clobber_all);
314 }
315
316 SEC("lsm.s/bpf")
317 __description("reference tracking: leak potential reference to user key")
318 __failure __msg("Unreleased reference")
potential_reference_to_user_key(void)319 __naked void potential_reference_to_user_key(void)
320 {
321 asm volatile (" \
322 r1 = -3; \
323 r2 = 0; \
324 call %[bpf_lookup_user_key]; \
325 exit; \
326 " :
327 : __imm(bpf_lookup_user_key)
328 : __clobber_all);
329 }
330
331 SEC("lsm.s/bpf")
332 __description("reference tracking: leak potential reference to system key")
333 __failure __msg("Unreleased reference")
potential_reference_to_system_key(void)334 __naked void potential_reference_to_system_key(void)
335 {
336 asm volatile (" \
337 r1 = 1; \
338 call %[bpf_lookup_system_key]; \
339 exit; \
340 " :
341 : __imm(bpf_lookup_system_key)
342 : __clobber_all);
343 }
344
345 SEC("tc")
346 __description("reference tracking: release reference without check")
347 __failure __msg("type=sock_or_null expected=sock")
tracking_release_reference_without_check(void)348 __naked void tracking_release_reference_without_check(void)
349 {
350 asm volatile (
351 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
352 " /* reference in r0 may be NULL */ \
353 r1 = r0; \
354 r2 = 0; \
355 call %[bpf_sk_release]; \
356 exit; \
357 " :
358 : __imm(bpf_sk_lookup_tcp),
359 __imm(bpf_sk_release),
360 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
361 : __clobber_all);
362 }
363
364 SEC("tc")
365 __description("reference tracking: release reference to sock_common without check")
366 __failure __msg("type=sock_common_or_null expected=sock")
to_sock_common_without_check(void)367 __naked void to_sock_common_without_check(void)
368 {
369 asm volatile (
370 BPF_SK_LOOKUP(bpf_skc_lookup_tcp)
371 " /* reference in r0 may be NULL */ \
372 r1 = r0; \
373 r2 = 0; \
374 call %[bpf_sk_release]; \
375 exit; \
376 " :
377 : __imm(bpf_sk_release),
378 __imm(bpf_skc_lookup_tcp),
379 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
380 : __clobber_all);
381 }
382
383 SEC("tc")
384 __description("reference tracking: release reference")
385 __success __retval(0)
reference_tracking_release_reference(void)386 __naked void reference_tracking_release_reference(void)
387 {
388 asm volatile (
389 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
390 " r1 = r0; \
391 if r0 == 0 goto l0_%=; \
392 call %[bpf_sk_release]; \
393 l0_%=: exit; \
394 " :
395 : __imm(bpf_sk_lookup_tcp),
396 __imm(bpf_sk_release),
397 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
398 : __clobber_all);
399 }
400
401 SEC("tc")
402 __description("reference tracking: release reference to sock_common")
403 __success __retval(0)
release_reference_to_sock_common(void)404 __naked void release_reference_to_sock_common(void)
405 {
406 asm volatile (
407 BPF_SK_LOOKUP(bpf_skc_lookup_tcp)
408 " r1 = r0; \
409 if r0 == 0 goto l0_%=; \
410 call %[bpf_sk_release]; \
411 l0_%=: exit; \
412 " :
413 : __imm(bpf_sk_release),
414 __imm(bpf_skc_lookup_tcp),
415 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
416 : __clobber_all);
417 }
418
419 SEC("tc")
420 __description("reference tracking: release reference 2")
421 __success __retval(0)
reference_tracking_release_reference_2(void)422 __naked void reference_tracking_release_reference_2(void)
423 {
424 asm volatile (
425 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
426 " r1 = r0; \
427 if r0 != 0 goto l0_%=; \
428 exit; \
429 l0_%=: call %[bpf_sk_release]; \
430 exit; \
431 " :
432 : __imm(bpf_sk_lookup_tcp),
433 __imm(bpf_sk_release),
434 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
435 : __clobber_all);
436 }
437
438 SEC("tc")
439 __description("reference tracking: release reference twice")
440 __failure __msg("type=scalar expected=sock")
reference_tracking_release_reference_twice(void)441 __naked void reference_tracking_release_reference_twice(void)
442 {
443 asm volatile (
444 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
445 " r1 = r0; \
446 r6 = r0; \
447 if r0 == 0 goto l0_%=; \
448 call %[bpf_sk_release]; \
449 l0_%=: r1 = r6; \
450 call %[bpf_sk_release]; \
451 exit; \
452 " :
453 : __imm(bpf_sk_lookup_tcp),
454 __imm(bpf_sk_release),
455 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
456 : __clobber_all);
457 }
458
459 SEC("tc")
460 __description("reference tracking: release reference twice inside branch")
461 __failure __msg("type=scalar expected=sock")
release_reference_twice_inside_branch(void)462 __naked void release_reference_twice_inside_branch(void)
463 {
464 asm volatile (
465 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
466 " r1 = r0; \
467 r6 = r0; \
468 if r0 == 0 goto l0_%=; /* goto end */ \
469 call %[bpf_sk_release]; \
470 r1 = r6; \
471 call %[bpf_sk_release]; \
472 l0_%=: exit; \
473 " :
474 : __imm(bpf_sk_lookup_tcp),
475 __imm(bpf_sk_release),
476 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
477 : __clobber_all);
478 }
479
480 SEC("tc")
481 __description("reference tracking: alloc, check, free in one subbranch")
482 __failure __msg("Unreleased reference")
__flag(BPF_F_ANY_ALIGNMENT)483 __flag(BPF_F_ANY_ALIGNMENT)
484 __naked void check_free_in_one_subbranch(void)
485 {
486 asm volatile (" \
487 r2 = *(u32*)(r1 + %[__sk_buff_data]); \
488 r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \
489 r0 = r2; \
490 r0 += 16; \
491 /* if (offsetof(skb, mark) > data_len) exit; */ \
492 if r0 <= r3 goto l0_%=; \
493 exit; \
494 l0_%=: r6 = *(u32*)(r2 + %[__sk_buff_mark]); \
495 " BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
496 " if r6 == 0 goto l1_%=; /* mark == 0? */\
497 /* Leak reference in R0 */ \
498 exit; \
499 l1_%=: if r0 == 0 goto l2_%=; /* sk NULL? */ \
500 r1 = r0; \
501 call %[bpf_sk_release]; \
502 l2_%=: exit; \
503 " :
504 : __imm(bpf_sk_lookup_tcp),
505 __imm(bpf_sk_release),
506 __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
507 __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)),
508 __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark)),
509 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
510 : __clobber_all);
511 }
512
513 SEC("tc")
514 __description("reference tracking: alloc, check, free in both subbranches")
__flag(BPF_F_ANY_ALIGNMENT)515 __success __retval(0) __flag(BPF_F_ANY_ALIGNMENT)
516 __naked void check_free_in_both_subbranches(void)
517 {
518 asm volatile (" \
519 r2 = *(u32*)(r1 + %[__sk_buff_data]); \
520 r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \
521 r0 = r2; \
522 r0 += 16; \
523 /* if (offsetof(skb, mark) > data_len) exit; */ \
524 if r0 <= r3 goto l0_%=; \
525 exit; \
526 l0_%=: r6 = *(u32*)(r2 + %[__sk_buff_mark]); \
527 " BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
528 " if r6 == 0 goto l1_%=; /* mark == 0? */\
529 if r0 == 0 goto l2_%=; /* sk NULL? */ \
530 r1 = r0; \
531 call %[bpf_sk_release]; \
532 l2_%=: exit; \
533 l1_%=: if r0 == 0 goto l3_%=; /* sk NULL? */ \
534 r1 = r0; \
535 call %[bpf_sk_release]; \
536 l3_%=: exit; \
537 " :
538 : __imm(bpf_sk_lookup_tcp),
539 __imm(bpf_sk_release),
540 __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
541 __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)),
542 __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark)),
543 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
544 : __clobber_all);
545 }
546
547 SEC("tc")
548 __description("reference tracking in call: free reference in subprog")
549 __success __retval(0)
call_free_reference_in_subprog(void)550 __naked void call_free_reference_in_subprog(void)
551 {
552 asm volatile (
553 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
554 " r1 = r0; /* unchecked reference */ \
555 call call_free_reference_in_subprog__1; \
556 r0 = 0; \
557 exit; \
558 " :
559 : __imm(bpf_sk_lookup_tcp),
560 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
561 : __clobber_all);
562 }
563
564 static __naked __noinline __attribute__((used))
call_free_reference_in_subprog__1(void)565 void call_free_reference_in_subprog__1(void)
566 {
567 asm volatile (" \
568 /* subprog 1 */ \
569 r2 = r1; \
570 if r2 == 0 goto l0_%=; \
571 call %[bpf_sk_release]; \
572 l0_%=: exit; \
573 " :
574 : __imm(bpf_sk_release)
575 : __clobber_all);
576 }
577
578 SEC("tc")
579 __description("reference tracking in call: free reference in subprog and outside")
580 __failure __msg("type=scalar expected=sock")
reference_in_subprog_and_outside(void)581 __naked void reference_in_subprog_and_outside(void)
582 {
583 asm volatile (
584 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
585 " r1 = r0; /* unchecked reference */ \
586 r6 = r0; \
587 call reference_in_subprog_and_outside__1; \
588 r1 = r6; \
589 call %[bpf_sk_release]; \
590 exit; \
591 " :
592 : __imm(bpf_sk_lookup_tcp),
593 __imm(bpf_sk_release),
594 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
595 : __clobber_all);
596 }
597
598 static __naked __noinline __attribute__((used))
reference_in_subprog_and_outside__1(void)599 void reference_in_subprog_and_outside__1(void)
600 {
601 asm volatile (" \
602 /* subprog 1 */ \
603 r2 = r1; \
604 if r2 == 0 goto l0_%=; \
605 call %[bpf_sk_release]; \
606 l0_%=: exit; \
607 " :
608 : __imm(bpf_sk_release)
609 : __clobber_all);
610 }
611
612 SEC("tc")
613 __description("reference tracking in call: alloc & leak reference in subprog")
614 __failure __msg("Unreleased reference")
alloc_leak_reference_in_subprog(void)615 __naked void alloc_leak_reference_in_subprog(void)
616 {
617 asm volatile (" \
618 r4 = r10; \
619 r4 += -8; \
620 call alloc_leak_reference_in_subprog__1; \
621 r1 = r0; \
622 r0 = 0; \
623 exit; \
624 " ::: __clobber_all);
625 }
626
627 static __naked __noinline __attribute__((used))
alloc_leak_reference_in_subprog__1(void)628 void alloc_leak_reference_in_subprog__1(void)
629 {
630 asm volatile (" \
631 /* subprog 1 */ \
632 r6 = r4; \
633 " BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
634 " /* spill unchecked sk_ptr into stack of caller */\
635 *(u64*)(r6 + 0) = r0; \
636 r1 = r0; \
637 exit; \
638 " :
639 : __imm(bpf_sk_lookup_tcp),
640 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
641 : __clobber_all);
642 }
643
644 SEC("tc")
645 __description("reference tracking in call: alloc in subprog, release outside")
__retval(POINTER_VALUE)646 __success __retval(POINTER_VALUE)
647 __naked void alloc_in_subprog_release_outside(void)
648 {
649 asm volatile (" \
650 r4 = r10; \
651 call alloc_in_subprog_release_outside__1; \
652 r1 = r0; \
653 if r0 == 0 goto l0_%=; \
654 call %[bpf_sk_release]; \
655 l0_%=: exit; \
656 " :
657 : __imm(bpf_sk_release)
658 : __clobber_all);
659 }
660
661 static __naked __noinline __attribute__((used))
alloc_in_subprog_release_outside__1(void)662 void alloc_in_subprog_release_outside__1(void)
663 {
664 asm volatile (" \
665 /* subprog 1 */ \
666 " BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
667 " exit; /* return sk */ \
668 " :
669 : __imm(bpf_sk_lookup_tcp),
670 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
671 : __clobber_all);
672 }
673
674 SEC("tc")
675 __description("reference tracking in call: sk_ptr leak into caller stack")
676 __failure __msg("Unreleased reference")
ptr_leak_into_caller_stack(void)677 __naked void ptr_leak_into_caller_stack(void)
678 {
679 asm volatile (" \
680 r4 = r10; \
681 r4 += -8; \
682 call ptr_leak_into_caller_stack__1; \
683 r0 = 0; \
684 exit; \
685 " ::: __clobber_all);
686 }
687
688 static __naked __noinline __attribute__((used))
ptr_leak_into_caller_stack__1(void)689 void ptr_leak_into_caller_stack__1(void)
690 {
691 asm volatile (" \
692 /* subprog 1 */ \
693 r5 = r10; \
694 r5 += -8; \
695 *(u64*)(r5 + 0) = r4; \
696 call ptr_leak_into_caller_stack__2; \
697 /* spill unchecked sk_ptr into stack of caller */\
698 r5 = r10; \
699 r5 += -8; \
700 r4 = *(u64*)(r5 + 0); \
701 *(u64*)(r4 + 0) = r0; \
702 exit; \
703 " ::: __clobber_all);
704 }
705
706 static __naked __noinline __attribute__((used))
ptr_leak_into_caller_stack__2(void)707 void ptr_leak_into_caller_stack__2(void)
708 {
709 asm volatile (" \
710 /* subprog 2 */ \
711 " BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
712 " exit; \
713 " :
714 : __imm(bpf_sk_lookup_tcp),
715 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
716 : __clobber_all);
717 }
718
719 SEC("tc")
720 __description("reference tracking in call: sk_ptr spill into caller stack")
721 __success __retval(0)
ptr_spill_into_caller_stack(void)722 __naked void ptr_spill_into_caller_stack(void)
723 {
724 asm volatile (" \
725 r4 = r10; \
726 r4 += -8; \
727 call ptr_spill_into_caller_stack__1; \
728 r0 = 0; \
729 exit; \
730 " ::: __clobber_all);
731 }
732
733 static __naked __noinline __attribute__((used))
ptr_spill_into_caller_stack__1(void)734 void ptr_spill_into_caller_stack__1(void)
735 {
736 asm volatile (" \
737 /* subprog 1 */ \
738 r5 = r10; \
739 r5 += -8; \
740 *(u64*)(r5 + 0) = r4; \
741 call ptr_spill_into_caller_stack__2; \
742 /* spill unchecked sk_ptr into stack of caller */\
743 r5 = r10; \
744 r5 += -8; \
745 r4 = *(u64*)(r5 + 0); \
746 *(u64*)(r4 + 0) = r0; \
747 if r0 == 0 goto l0_%=; \
748 /* now the sk_ptr is verified, free the reference */\
749 r1 = *(u64*)(r4 + 0); \
750 call %[bpf_sk_release]; \
751 l0_%=: exit; \
752 " :
753 : __imm(bpf_sk_release)
754 : __clobber_all);
755 }
756
757 static __naked __noinline __attribute__((used))
ptr_spill_into_caller_stack__2(void)758 void ptr_spill_into_caller_stack__2(void)
759 {
760 asm volatile (" \
761 /* subprog 2 */ \
762 " BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
763 " exit; \
764 " :
765 : __imm(bpf_sk_lookup_tcp),
766 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
767 : __clobber_all);
768 }
769
770 SEC("tc")
771 __description("reference tracking: allow LD_ABS")
772 __success __retval(0)
reference_tracking_allow_ld_abs(void)773 __naked void reference_tracking_allow_ld_abs(void)
774 {
775 asm volatile (" \
776 r6 = r1; \
777 " BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
778 " r1 = r0; \
779 if r0 == 0 goto l0_%=; \
780 call %[bpf_sk_release]; \
781 l0_%=: r0 = *(u8*)skb[0]; \
782 r0 = *(u16*)skb[0]; \
783 r0 = *(u32*)skb[0]; \
784 exit; \
785 " :
786 : __imm(bpf_sk_lookup_tcp),
787 __imm(bpf_sk_release),
788 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
789 : __clobber_all);
790 }
791
792 SEC("tc")
793 __description("reference tracking: forbid LD_ABS while holding reference")
794 __failure __msg("BPF_LD_[ABS|IND] cannot be mixed with socket references")
ld_abs_while_holding_reference(void)795 __naked void ld_abs_while_holding_reference(void)
796 {
797 asm volatile (" \
798 r6 = r1; \
799 " BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
800 " r0 = *(u8*)skb[0]; \
801 r0 = *(u16*)skb[0]; \
802 r0 = *(u32*)skb[0]; \
803 r1 = r0; \
804 if r0 == 0 goto l0_%=; \
805 call %[bpf_sk_release]; \
806 l0_%=: exit; \
807 " :
808 : __imm(bpf_sk_lookup_tcp),
809 __imm(bpf_sk_release),
810 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
811 : __clobber_all);
812 }
813
814 SEC("tc")
815 __description("reference tracking: allow LD_IND")
816 __success __retval(1)
reference_tracking_allow_ld_ind(void)817 __naked void reference_tracking_allow_ld_ind(void)
818 {
819 asm volatile (" \
820 r6 = r1; \
821 " BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
822 " r1 = r0; \
823 if r0 == 0 goto l0_%=; \
824 call %[bpf_sk_release]; \
825 l0_%=: r7 = 1; \
826 .8byte %[ld_ind]; \
827 r0 = r7; \
828 exit; \
829 " :
830 : __imm(bpf_sk_lookup_tcp),
831 __imm(bpf_sk_release),
832 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple)),
833 __imm_insn(ld_ind, BPF_LD_IND(BPF_W, BPF_REG_7, -0x200000))
834 : __clobber_all);
835 }
836
837 SEC("tc")
838 __description("reference tracking: forbid LD_IND while holding reference")
839 __failure __msg("BPF_LD_[ABS|IND] cannot be mixed with socket references")
ld_ind_while_holding_reference(void)840 __naked void ld_ind_while_holding_reference(void)
841 {
842 asm volatile (" \
843 r6 = r1; \
844 " BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
845 " r4 = r0; \
846 r7 = 1; \
847 .8byte %[ld_ind]; \
848 r0 = r7; \
849 r1 = r4; \
850 if r1 == 0 goto l0_%=; \
851 call %[bpf_sk_release]; \
852 l0_%=: exit; \
853 " :
854 : __imm(bpf_sk_lookup_tcp),
855 __imm(bpf_sk_release),
856 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple)),
857 __imm_insn(ld_ind, BPF_LD_IND(BPF_W, BPF_REG_7, -0x200000))
858 : __clobber_all);
859 }
860
861 SEC("tc")
862 __description("reference tracking: check reference or tail call")
863 __success __retval(0)
check_reference_or_tail_call(void)864 __naked void check_reference_or_tail_call(void)
865 {
866 asm volatile (" \
867 r7 = r1; \
868 " BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
869 " /* if (sk) bpf_sk_release() */ \
870 r1 = r0; \
871 if r1 != 0 goto l0_%=; \
872 /* bpf_tail_call() */ \
873 r3 = 3; \
874 r2 = %[map_prog1_tc] ll; \
875 r1 = r7; \
876 call %[bpf_tail_call]; \
877 r0 = 0; \
878 exit; \
879 l0_%=: call %[bpf_sk_release]; \
880 exit; \
881 " :
882 : __imm(bpf_sk_lookup_tcp),
883 __imm(bpf_sk_release),
884 __imm(bpf_tail_call),
885 __imm_addr(map_prog1_tc),
886 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
887 : __clobber_all);
888 }
889
890 SEC("tc")
891 __description("reference tracking: release reference then tail call")
892 __success __retval(0)
release_reference_then_tail_call(void)893 __naked void release_reference_then_tail_call(void)
894 {
895 asm volatile (" \
896 r7 = r1; \
897 " BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
898 " /* if (sk) bpf_sk_release() */ \
899 r1 = r0; \
900 if r1 == 0 goto l0_%=; \
901 call %[bpf_sk_release]; \
902 l0_%=: /* bpf_tail_call() */ \
903 r3 = 3; \
904 r2 = %[map_prog1_tc] ll; \
905 r1 = r7; \
906 call %[bpf_tail_call]; \
907 r0 = 0; \
908 exit; \
909 " :
910 : __imm(bpf_sk_lookup_tcp),
911 __imm(bpf_sk_release),
912 __imm(bpf_tail_call),
913 __imm_addr(map_prog1_tc),
914 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
915 : __clobber_all);
916 }
917
918 SEC("tc")
919 __description("reference tracking: leak possible reference over tail call")
920 __failure __msg("tail_call would lead to reference leak")
possible_reference_over_tail_call(void)921 __naked void possible_reference_over_tail_call(void)
922 {
923 asm volatile (" \
924 r7 = r1; \
925 /* Look up socket and store in REG_6 */ \
926 " BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
927 " /* bpf_tail_call() */ \
928 r6 = r0; \
929 r3 = 3; \
930 r2 = %[map_prog1_tc] ll; \
931 r1 = r7; \
932 call %[bpf_tail_call]; \
933 r0 = 0; \
934 /* if (sk) bpf_sk_release() */ \
935 r1 = r6; \
936 if r1 == 0 goto l0_%=; \
937 call %[bpf_sk_release]; \
938 l0_%=: exit; \
939 " :
940 : __imm(bpf_sk_lookup_tcp),
941 __imm(bpf_sk_release),
942 __imm(bpf_tail_call),
943 __imm_addr(map_prog1_tc),
944 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
945 : __clobber_all);
946 }
947
948 SEC("tc")
949 __description("reference tracking: leak checked reference over tail call")
950 __failure __msg("tail_call would lead to reference leak")
checked_reference_over_tail_call(void)951 __naked void checked_reference_over_tail_call(void)
952 {
953 asm volatile (" \
954 r7 = r1; \
955 /* Look up socket and store in REG_6 */ \
956 " BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
957 " r6 = r0; \
958 /* if (!sk) goto end */ \
959 if r0 == 0 goto l0_%=; \
960 /* bpf_tail_call() */ \
961 r3 = 0; \
962 r2 = %[map_prog1_tc] ll; \
963 r1 = r7; \
964 call %[bpf_tail_call]; \
965 r0 = 0; \
966 r1 = r6; \
967 l0_%=: call %[bpf_sk_release]; \
968 exit; \
969 " :
970 : __imm(bpf_sk_lookup_tcp),
971 __imm(bpf_sk_release),
972 __imm(bpf_tail_call),
973 __imm_addr(map_prog1_tc),
974 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
975 : __clobber_all);
976 }
977
978 SEC("tc")
979 __description("reference tracking: mangle and release sock_or_null")
980 __failure __msg("R1 pointer arithmetic on sock_or_null prohibited")
and_release_sock_or_null(void)981 __naked void and_release_sock_or_null(void)
982 {
983 asm volatile (
984 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
985 " r1 = r0; \
986 r1 += 5; \
987 if r0 == 0 goto l0_%=; \
988 call %[bpf_sk_release]; \
989 l0_%=: exit; \
990 " :
991 : __imm(bpf_sk_lookup_tcp),
992 __imm(bpf_sk_release),
993 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
994 : __clobber_all);
995 }
996
997 SEC("tc")
998 __description("reference tracking: mangle and release sock")
999 __failure __msg("R1 pointer arithmetic on sock prohibited")
tracking_mangle_and_release_sock(void)1000 __naked void tracking_mangle_and_release_sock(void)
1001 {
1002 asm volatile (
1003 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
1004 " r1 = r0; \
1005 if r0 == 0 goto l0_%=; \
1006 r1 += 5; \
1007 call %[bpf_sk_release]; \
1008 l0_%=: exit; \
1009 " :
1010 : __imm(bpf_sk_lookup_tcp),
1011 __imm(bpf_sk_release),
1012 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
1013 : __clobber_all);
1014 }
1015
1016 SEC("tc")
1017 __description("reference tracking: access member")
1018 __success __retval(0)
reference_tracking_access_member(void)1019 __naked void reference_tracking_access_member(void)
1020 {
1021 asm volatile (
1022 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
1023 " r6 = r0; \
1024 if r0 == 0 goto l0_%=; \
1025 r2 = *(u32*)(r0 + 4); \
1026 r1 = r6; \
1027 call %[bpf_sk_release]; \
1028 l0_%=: exit; \
1029 " :
1030 : __imm(bpf_sk_lookup_tcp),
1031 __imm(bpf_sk_release),
1032 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
1033 : __clobber_all);
1034 }
1035
1036 SEC("tc")
1037 __description("reference tracking: write to member")
1038 __failure __msg("cannot write into sock")
reference_tracking_write_to_member(void)1039 __naked void reference_tracking_write_to_member(void)
1040 {
1041 asm volatile (
1042 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
1043 " r6 = r0; \
1044 if r0 == 0 goto l0_%=; \
1045 r1 = r6; \
1046 r2 = 42 ll; \
1047 *(u32*)(r1 + %[bpf_sock_mark]) = r2; \
1048 r1 = r6; \
1049 l0_%=: call %[bpf_sk_release]; \
1050 r0 = 0 ll; \
1051 exit; \
1052 " :
1053 : __imm(bpf_sk_lookup_tcp),
1054 __imm(bpf_sk_release),
1055 __imm_const(bpf_sock_mark, offsetof(struct bpf_sock, mark)),
1056 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
1057 : __clobber_all);
1058 }
1059
1060 SEC("tc")
1061 __description("reference tracking: invalid 64-bit access of member")
1062 __failure __msg("invalid sock access off=0 size=8")
_64_bit_access_of_member(void)1063 __naked void _64_bit_access_of_member(void)
1064 {
1065 asm volatile (
1066 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
1067 " r6 = r0; \
1068 if r0 == 0 goto l0_%=; \
1069 r2 = *(u64*)(r0 + 0); \
1070 r1 = r6; \
1071 call %[bpf_sk_release]; \
1072 l0_%=: exit; \
1073 " :
1074 : __imm(bpf_sk_lookup_tcp),
1075 __imm(bpf_sk_release),
1076 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
1077 : __clobber_all);
1078 }
1079
1080 SEC("tc")
1081 __description("reference tracking: access after release")
1082 __failure __msg("!read_ok")
reference_tracking_access_after_release(void)1083 __naked void reference_tracking_access_after_release(void)
1084 {
1085 asm volatile (
1086 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
1087 " r1 = r0; \
1088 if r0 == 0 goto l0_%=; \
1089 call %[bpf_sk_release]; \
1090 r2 = *(u32*)(r1 + 0); \
1091 l0_%=: exit; \
1092 " :
1093 : __imm(bpf_sk_lookup_tcp),
1094 __imm(bpf_sk_release),
1095 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
1096 : __clobber_all);
1097 }
1098
1099 SEC("tc")
1100 __description("reference tracking: direct access for lookup")
1101 __success __retval(0)
tracking_direct_access_for_lookup(void)1102 __naked void tracking_direct_access_for_lookup(void)
1103 {
1104 asm volatile (" \
1105 /* Check that the packet is at least 64B long */\
1106 r2 = *(u32*)(r1 + %[__sk_buff_data]); \
1107 r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \
1108 r0 = r2; \
1109 r0 += 64; \
1110 if r0 > r3 goto l0_%=; \
1111 /* sk = sk_lookup_tcp(ctx, skb->data, ...) */ \
1112 r3 = %[sizeof_bpf_sock_tuple]; \
1113 r4 = 0; \
1114 r5 = 0; \
1115 call %[bpf_sk_lookup_tcp]; \
1116 r6 = r0; \
1117 if r0 == 0 goto l0_%=; \
1118 r2 = *(u32*)(r0 + 4); \
1119 r1 = r6; \
1120 call %[bpf_sk_release]; \
1121 l0_%=: exit; \
1122 " :
1123 : __imm(bpf_sk_lookup_tcp),
1124 __imm(bpf_sk_release),
1125 __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
1126 __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)),
1127 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
1128 : __clobber_all);
1129 }
1130
1131 SEC("tc")
1132 __description("reference tracking: use ptr from bpf_tcp_sock() after release")
1133 __failure __msg("invalid mem access")
__flag(BPF_F_ANY_ALIGNMENT)1134 __flag(BPF_F_ANY_ALIGNMENT)
1135 __naked void bpf_tcp_sock_after_release(void)
1136 {
1137 asm volatile (
1138 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
1139 " if r0 != 0 goto l0_%=; \
1140 exit; \
1141 l0_%=: r6 = r0; \
1142 r1 = r0; \
1143 call %[bpf_tcp_sock]; \
1144 if r0 != 0 goto l1_%=; \
1145 r1 = r6; \
1146 call %[bpf_sk_release]; \
1147 exit; \
1148 l1_%=: r7 = r0; \
1149 r1 = r6; \
1150 call %[bpf_sk_release]; \
1151 r0 = *(u32*)(r7 + %[bpf_tcp_sock_snd_cwnd]); \
1152 exit; \
1153 " :
1154 : __imm(bpf_sk_lookup_tcp),
1155 __imm(bpf_sk_release),
1156 __imm(bpf_tcp_sock),
1157 __imm_const(bpf_tcp_sock_snd_cwnd, offsetof(struct bpf_tcp_sock, snd_cwnd)),
1158 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
1159 : __clobber_all);
1160 }
1161
1162 SEC("tc")
1163 __description("reference tracking: use ptr from bpf_sk_fullsock() after release")
1164 __failure __msg("invalid mem access")
__flag(BPF_F_ANY_ALIGNMENT)1165 __flag(BPF_F_ANY_ALIGNMENT)
1166 __naked void bpf_sk_fullsock_after_release(void)
1167 {
1168 asm volatile (
1169 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
1170 " if r0 != 0 goto l0_%=; \
1171 exit; \
1172 l0_%=: r6 = r0; \
1173 r1 = r0; \
1174 call %[bpf_sk_fullsock]; \
1175 if r0 != 0 goto l1_%=; \
1176 r1 = r6; \
1177 call %[bpf_sk_release]; \
1178 exit; \
1179 l1_%=: r7 = r0; \
1180 r1 = r6; \
1181 call %[bpf_sk_release]; \
1182 r0 = *(u32*)(r7 + %[bpf_sock_type]); \
1183 exit; \
1184 " :
1185 : __imm(bpf_sk_fullsock),
1186 __imm(bpf_sk_lookup_tcp),
1187 __imm(bpf_sk_release),
1188 __imm_const(bpf_sock_type, offsetof(struct bpf_sock, type)),
1189 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
1190 : __clobber_all);
1191 }
1192
1193 SEC("tc")
1194 __description("reference tracking: use ptr from bpf_sk_fullsock(tp) after release")
1195 __failure __msg("invalid mem access")
__flag(BPF_F_ANY_ALIGNMENT)1196 __flag(BPF_F_ANY_ALIGNMENT)
1197 __naked void sk_fullsock_tp_after_release(void)
1198 {
1199 asm volatile (
1200 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
1201 " if r0 != 0 goto l0_%=; \
1202 exit; \
1203 l0_%=: r6 = r0; \
1204 r1 = r0; \
1205 call %[bpf_tcp_sock]; \
1206 if r0 != 0 goto l1_%=; \
1207 r1 = r6; \
1208 call %[bpf_sk_release]; \
1209 exit; \
1210 l1_%=: r1 = r0; \
1211 call %[bpf_sk_fullsock]; \
1212 r1 = r6; \
1213 r6 = r0; \
1214 call %[bpf_sk_release]; \
1215 if r6 != 0 goto l2_%=; \
1216 exit; \
1217 l2_%=: r0 = *(u32*)(r6 + %[bpf_sock_type]); \
1218 exit; \
1219 " :
1220 : __imm(bpf_sk_fullsock),
1221 __imm(bpf_sk_lookup_tcp),
1222 __imm(bpf_sk_release),
1223 __imm(bpf_tcp_sock),
1224 __imm_const(bpf_sock_type, offsetof(struct bpf_sock, type)),
1225 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
1226 : __clobber_all);
1227 }
1228
1229 SEC("tc")
1230 __description("reference tracking: use sk after bpf_sk_release(tp)")
1231 __failure __msg("invalid mem access")
__flag(BPF_F_ANY_ALIGNMENT)1232 __flag(BPF_F_ANY_ALIGNMENT)
1233 __naked void after_bpf_sk_release_tp(void)
1234 {
1235 asm volatile (
1236 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
1237 " if r0 != 0 goto l0_%=; \
1238 exit; \
1239 l0_%=: r6 = r0; \
1240 r1 = r0; \
1241 call %[bpf_tcp_sock]; \
1242 if r0 != 0 goto l1_%=; \
1243 r1 = r6; \
1244 call %[bpf_sk_release]; \
1245 exit; \
1246 l1_%=: r1 = r0; \
1247 call %[bpf_sk_release]; \
1248 r0 = *(u32*)(r6 + %[bpf_sock_type]); \
1249 exit; \
1250 " :
1251 : __imm(bpf_sk_lookup_tcp),
1252 __imm(bpf_sk_release),
1253 __imm(bpf_tcp_sock),
1254 __imm_const(bpf_sock_type, offsetof(struct bpf_sock, type)),
1255 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
1256 : __clobber_all);
1257 }
1258
1259 SEC("tc")
1260 __description("reference tracking: use ptr from bpf_get_listener_sock() after bpf_sk_release(sk)")
1261 __success __retval(0)
after_bpf_sk_release_sk(void)1262 __naked void after_bpf_sk_release_sk(void)
1263 {
1264 asm volatile (
1265 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
1266 " if r0 != 0 goto l0_%=; \
1267 exit; \
1268 l0_%=: r6 = r0; \
1269 r1 = r0; \
1270 call %[bpf_get_listener_sock]; \
1271 if r0 != 0 goto l1_%=; \
1272 r1 = r6; \
1273 call %[bpf_sk_release]; \
1274 exit; \
1275 l1_%=: r1 = r6; \
1276 r6 = r0; \
1277 call %[bpf_sk_release]; \
1278 r0 = *(u32*)(r6 + %[bpf_sock_src_port]); \
1279 exit; \
1280 " :
1281 : __imm(bpf_get_listener_sock),
1282 __imm(bpf_sk_lookup_tcp),
1283 __imm(bpf_sk_release),
1284 __imm_const(bpf_sock_src_port, offsetof(struct bpf_sock, src_port)),
1285 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
1286 : __clobber_all);
1287 }
1288
1289 SEC("tc")
1290 __description("reference tracking: bpf_sk_release(listen_sk)")
1291 __failure __msg("R1 must be referenced when passed to release function")
bpf_sk_release_listen_sk(void)1292 __naked void bpf_sk_release_listen_sk(void)
1293 {
1294 asm volatile (
1295 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
1296 " if r0 != 0 goto l0_%=; \
1297 exit; \
1298 l0_%=: r6 = r0; \
1299 r1 = r0; \
1300 call %[bpf_get_listener_sock]; \
1301 if r0 != 0 goto l1_%=; \
1302 r1 = r6; \
1303 call %[bpf_sk_release]; \
1304 exit; \
1305 l1_%=: r1 = r0; \
1306 call %[bpf_sk_release]; \
1307 r0 = *(u32*)(r6 + %[bpf_sock_type]); \
1308 r1 = r6; \
1309 call %[bpf_sk_release]; \
1310 exit; \
1311 " :
1312 : __imm(bpf_get_listener_sock),
1313 __imm(bpf_sk_lookup_tcp),
1314 __imm(bpf_sk_release),
1315 __imm_const(bpf_sock_type, offsetof(struct bpf_sock, type)),
1316 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
1317 : __clobber_all);
1318 }
1319
1320 /* !bpf_sk_fullsock(sk) is checked but !bpf_tcp_sock(sk) is not checked */
1321 SEC("tc")
1322 __description("reference tracking: tp->snd_cwnd after bpf_sk_fullsock(sk) and bpf_tcp_sock(sk)")
1323 __failure __msg("invalid mem access")
and_bpf_tcp_sock_sk(void)1324 __naked void and_bpf_tcp_sock_sk(void)
1325 {
1326 asm volatile (
1327 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
1328 " if r0 != 0 goto l0_%=; \
1329 exit; \
1330 l0_%=: r6 = r0; \
1331 r1 = r0; \
1332 call %[bpf_sk_fullsock]; \
1333 r7 = r0; \
1334 r1 = r6; \
1335 call %[bpf_tcp_sock]; \
1336 r8 = r0; \
1337 if r7 != 0 goto l1_%=; \
1338 r1 = r6; \
1339 call %[bpf_sk_release]; \
1340 exit; \
1341 l1_%=: r0 = *(u32*)(r8 + %[bpf_tcp_sock_snd_cwnd]); \
1342 r1 = r6; \
1343 call %[bpf_sk_release]; \
1344 exit; \
1345 " :
1346 : __imm(bpf_sk_fullsock),
1347 __imm(bpf_sk_lookup_tcp),
1348 __imm(bpf_sk_release),
1349 __imm(bpf_tcp_sock),
1350 __imm_const(bpf_tcp_sock_snd_cwnd, offsetof(struct bpf_tcp_sock, snd_cwnd)),
1351 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
1352 : __clobber_all);
1353 }
1354
1355 SEC("tc")
1356 __description("reference tracking: branch tracking valid pointer null comparison")
1357 __success __retval(0)
tracking_valid_pointer_null_comparison(void)1358 __naked void tracking_valid_pointer_null_comparison(void)
1359 {
1360 asm volatile (
1361 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
1362 " r6 = r0; \
1363 r3 = 1; \
1364 if r6 != 0 goto l0_%=; \
1365 r3 = 0; \
1366 l0_%=: if r6 == 0 goto l1_%=; \
1367 r1 = r6; \
1368 call %[bpf_sk_release]; \
1369 l1_%=: exit; \
1370 " :
1371 : __imm(bpf_sk_lookup_tcp),
1372 __imm(bpf_sk_release),
1373 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
1374 : __clobber_all);
1375 }
1376
1377 SEC("tc")
1378 __description("reference tracking: branch tracking valid pointer value comparison")
1379 __failure __msg("Unreleased reference")
tracking_valid_pointer_value_comparison(void)1380 __naked void tracking_valid_pointer_value_comparison(void)
1381 {
1382 asm volatile (
1383 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
1384 " r6 = r0; \
1385 r3 = 1; \
1386 if r6 == 0 goto l0_%=; \
1387 r3 = 0; \
1388 if r6 == 1234 goto l0_%=; \
1389 r1 = r6; \
1390 call %[bpf_sk_release]; \
1391 l0_%=: exit; \
1392 " :
1393 : __imm(bpf_sk_lookup_tcp),
1394 __imm(bpf_sk_release),
1395 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
1396 : __clobber_all);
1397 }
1398
1399 SEC("tc")
1400 __description("reference tracking: bpf_sk_release(btf_tcp_sock)")
1401 __success
1402 __retval(0)
sk_release_btf_tcp_sock(void)1403 __naked void sk_release_btf_tcp_sock(void)
1404 {
1405 asm volatile (
1406 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
1407 " if r0 != 0 goto l0_%=; \
1408 exit; \
1409 l0_%=: r6 = r0; \
1410 r1 = r0; \
1411 call %[bpf_skc_to_tcp_sock]; \
1412 if r0 != 0 goto l1_%=; \
1413 r1 = r6; \
1414 call %[bpf_sk_release]; \
1415 exit; \
1416 l1_%=: r1 = r0; \
1417 call %[bpf_sk_release]; \
1418 exit; \
1419 " :
1420 : __imm(bpf_sk_lookup_tcp),
1421 __imm(bpf_sk_release),
1422 __imm(bpf_skc_to_tcp_sock),
1423 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
1424 : __clobber_all);
1425 }
1426
1427 SEC("tc")
1428 __description("reference tracking: use ptr from bpf_skc_to_tcp_sock() after release")
1429 __failure __msg("invalid mem access")
to_tcp_sock_after_release(void)1430 __naked void to_tcp_sock_after_release(void)
1431 {
1432 asm volatile (
1433 BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
1434 " if r0 != 0 goto l0_%=; \
1435 exit; \
1436 l0_%=: r6 = r0; \
1437 r1 = r0; \
1438 call %[bpf_skc_to_tcp_sock]; \
1439 if r0 != 0 goto l1_%=; \
1440 r1 = r6; \
1441 call %[bpf_sk_release]; \
1442 exit; \
1443 l1_%=: r7 = r0; \
1444 r1 = r6; \
1445 call %[bpf_sk_release]; \
1446 r0 = *(u8*)(r7 + 0); \
1447 exit; \
1448 " :
1449 : __imm(bpf_sk_lookup_tcp),
1450 __imm(bpf_sk_release),
1451 __imm(bpf_skc_to_tcp_sock),
1452 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
1453 : __clobber_all);
1454 }
1455
1456 SEC("socket")
1457 __description("reference tracking: try to leak released ptr reg")
1458 __success __failure_unpriv __msg_unpriv("R8 !read_ok")
1459 __retval(0)
to_leak_released_ptr_reg(void)1460 __naked void to_leak_released_ptr_reg(void)
1461 {
1462 asm volatile (" \
1463 r0 = 0; \
1464 *(u32*)(r10 - 4) = r0; \
1465 r2 = r10; \
1466 r2 += -4; \
1467 r1 = %[map_array_48b] ll; \
1468 call %[bpf_map_lookup_elem]; \
1469 if r0 != 0 goto l0_%=; \
1470 exit; \
1471 l0_%=: r9 = r0; \
1472 r0 = 0; \
1473 r1 = %[map_ringbuf] ll; \
1474 r2 = 8; \
1475 r3 = 0; \
1476 call %[bpf_ringbuf_reserve]; \
1477 if r0 != 0 goto l1_%=; \
1478 exit; \
1479 l1_%=: r8 = r0; \
1480 r1 = r8; \
1481 r2 = 0; \
1482 call %[bpf_ringbuf_discard]; \
1483 r0 = 0; \
1484 *(u64*)(r9 + 0) = r8; \
1485 exit; \
1486 " :
1487 : __imm(bpf_map_lookup_elem),
1488 __imm(bpf_ringbuf_discard),
1489 __imm(bpf_ringbuf_reserve),
1490 __imm_addr(map_array_48b),
1491 __imm_addr(map_ringbuf)
1492 : __clobber_all);
1493 }
1494
1495 char _license[] SEC("license") = "GPL";
1496