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
26struct bpf_key {} __attribute__((preserve_access_index));
27
28extern void bpf_key_put(struct bpf_key *key) __ksym;
29extern struct bpf_key *bpf_lookup_system_key(__u64 id) __ksym;
30extern 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 */
37void __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
46struct test_val {
47 unsigned int index;
48 int foo[MAX_ENTRIES];
49};
50
51struct {
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
58struct {
59 __uint(type, BPF_MAP_TYPE_RINGBUF);
60 __uint(max_entries, 4096);
61} map_ringbuf SEC(".maps");
62
63void dummy_prog_42_tc(void);
64void dummy_prog_24_tc(void);
65void dummy_prog_loop1_tc(void);
66
67struct {
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
80SEC("tc")
81__auxiliary
82__naked void dummy_prog_42_tc(void)
83{
84 asm volatile ("r0 = 42; exit;");
85}
86
87SEC("tc")
88__auxiliary
89__naked void dummy_prog_24_tc(void)
90{
91 asm volatile ("r0 = 24; exit;");
92}
93
94SEC("tc")
95__auxiliary
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
110SEC("tc")
111__description("reference tracking: leak potential reference")
112__failure __msg("Unreleased reference")
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
125SEC("tc")
126__description("reference tracking: leak potential reference to sock_common")
127__failure __msg("Unreleased reference")
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
140SEC("tc")
141__description("reference tracking: leak potential reference on stack")
142__failure __msg("Unreleased reference")
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
158SEC("tc")
159__description("reference tracking: leak potential reference on stack 2")
160__failure __msg("Unreleased reference")
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
178SEC("tc")
179__description("reference tracking: zero potential reference")
180__failure __msg("Unreleased reference")
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
193SEC("tc")
194__description("reference tracking: zero potential reference to sock_common")
195__failure __msg("Unreleased reference")
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
208SEC("tc")
209__description("reference tracking: copy and zero potential references")
210__failure __msg("Unreleased reference")
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
225SEC("lsm.s/bpf")
226__description("reference tracking: acquire/release user key reference")
227__success
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]; \
237l0_%=: r0 = 0; \
238 exit; \
239" :
240 : __imm(bpf_key_put),
241 __imm(bpf_lookup_user_key)
242 : __clobber_all);
243}
244
245SEC("lsm.s/bpf")
246__description("reference tracking: acquire/release system key reference")
247__success
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]; \
256l0_%=: r0 = 0; \
257 exit; \
258" :
259 : __imm(bpf_key_put),
260 __imm(bpf_lookup_system_key)
261 : __clobber_all);
262}
263
264SEC("lsm.s/bpf")
265__description("reference tracking: release user key reference without check")
266__failure __msg("Possibly NULL pointer passed to trusted arg0")
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
283SEC("lsm.s/bpf")
284__description("reference tracking: release system key reference without check")
285__failure __msg("Possibly NULL pointer passed to trusted arg0")
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
301SEC("lsm.s/bpf")
302__description("reference tracking: release with NULL key pointer")
303__failure __msg("Possibly NULL pointer passed to trusted arg0")
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
316SEC("lsm.s/bpf")
317__description("reference tracking: leak potential reference to user key")
318__failure __msg("Unreleased reference")
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
331SEC("lsm.s/bpf")
332__description("reference tracking: leak potential reference to system key")
333__failure __msg("Unreleased reference")
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
345SEC("tc")
346__description("reference tracking: release reference without check")
347__failure __msg("type=sock_or_null expected=sock")
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
364SEC("tc")
365__description("reference tracking: release reference to sock_common without check")
366__failure __msg("type=sock_common_or_null expected=sock")
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
383SEC("tc")
384__description("reference tracking: release reference")
385__success __retval(0)
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]; \
393l0_%=: 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
401SEC("tc")
402__description("reference tracking: release reference to sock_common")
403__success __retval(0)
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]; \
411l0_%=: 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
419SEC("tc")
420__description("reference tracking: release reference 2")
421__success __retval(0)
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; \
429l0_%=: 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
438SEC("tc")
439__description("reference tracking: release reference twice")
440__failure __msg("type=scalar expected=sock")
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]; \
449l0_%=: 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
459SEC("tc")
460__description("reference tracking: release reference twice inside branch")
461__failure __msg("type=scalar expected=sock")
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]; \
472l0_%=: 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
480SEC("tc")
481__description("reference tracking: alloc, check, free in one subbranch")
482__failure __msg("Unreleased reference")
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; \
494l0_%=: 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; \
499l1_%=: if r0 == 0 goto l2_%=; /* sk NULL? */ \
500 r1 = r0; \
501 call %[bpf_sk_release]; \
502l2_%=: 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
513SEC("tc")
514__description("reference tracking: alloc, check, free in both subbranches")
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; \
526l0_%=: 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]; \
532l2_%=: exit; \
533l1_%=: if r0 == 0 goto l3_%=; /* sk NULL? */ \
534 r1 = r0; \
535 call %[bpf_sk_release]; \
536l3_%=: 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
547SEC("tc")
548__description("reference tracking in call: free reference in subprog")
549__success __retval(0)
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
564static __naked __noinline __attribute__((used))
565void 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]; \
572l0_%=: exit; \
573" :
574 : __imm(bpf_sk_release)
575 : __clobber_all);
576}
577
578SEC("tc")
579__description("reference tracking in call: free reference in subprog and outside")
580__failure __msg("type=scalar expected=sock")
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
598static __naked __noinline __attribute__((used))
599void 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]; \
606l0_%=: exit; \
607" :
608 : __imm(bpf_sk_release)
609 : __clobber_all);
610}
611
612SEC("tc")
613__description("reference tracking in call: alloc & leak reference in subprog")
614__failure __msg("Unreleased reference")
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
627static __naked __noinline __attribute__((used))
628void 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
644SEC("tc")
645__description("reference tracking in call: alloc in subprog, release outside")
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]; \
655l0_%=: exit; \
656" :
657 : __imm(bpf_sk_release)
658 : __clobber_all);
659}
660
661static __naked __noinline __attribute__((used))
662void 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
674SEC("tc")
675__description("reference tracking in call: sk_ptr leak into caller stack")
676__failure __msg("Unreleased reference")
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
688static __naked __noinline __attribute__((used))
689void 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
706static __naked __noinline __attribute__((used))
707void 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
719SEC("tc")
720__description("reference tracking in call: sk_ptr spill into caller stack")
721__success __retval(0)
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
733static __naked __noinline __attribute__((used))
734void 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]; \
751l0_%=: exit; \
752" :
753 : __imm(bpf_sk_release)
754 : __clobber_all);
755}
756
757static __naked __noinline __attribute__((used))
758void 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
770SEC("tc")
771__description("reference tracking: allow LD_ABS")
772__success __retval(0)
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]; \
781l0_%=: 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
792SEC("tc")
793__description("reference tracking: forbid LD_ABS while holding reference")
794__failure __msg("BPF_LD_[ABS|IND] cannot be mixed with socket references")
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]; \
806l0_%=: 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
814SEC("tc")
815__description("reference tracking: allow LD_IND")
816__success __retval(1)
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]; \
825l0_%=: 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
837SEC("tc")
838__description("reference tracking: forbid LD_IND while holding reference")
839__failure __msg("BPF_LD_[ABS|IND] cannot be mixed with socket references")
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]; \
852l0_%=: 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
861SEC("tc")
862__description("reference tracking: check reference or tail call")
863__success __retval(0)
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; \
879l0_%=: 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
890SEC("tc")
891__description("reference tracking: release reference then tail call")
892__success __retval(0)
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]; \
902l0_%=: /* 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
918SEC("tc")
919__description("reference tracking: leak possible reference over tail call")
920__failure __msg("tail_call would lead to reference leak")
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]; \
938l0_%=: 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
948SEC("tc")
949__description("reference tracking: leak checked reference over tail call")
950__failure __msg("tail_call would lead to reference leak")
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; \
967l0_%=: 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
978SEC("tc")
979__description("reference tracking: mangle and release sock_or_null")
980__failure __msg("R1 pointer arithmetic on sock_or_null prohibited")
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]; \
989l0_%=: 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
997SEC("tc")
998__description("reference tracking: mangle and release sock")
999__failure __msg("R1 pointer arithmetic on sock prohibited")
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]; \
1008l0_%=: 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
1016SEC("tc")
1017__description("reference tracking: access member")
1018__success __retval(0)
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]; \
1028l0_%=: 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
1036SEC("tc")
1037__description("reference tracking: write to member")
1038__failure __msg("cannot write into sock")
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; \
1049l0_%=: 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
1060SEC("tc")
1061__description("reference tracking: invalid 64-bit access of member")
1062__failure __msg("invalid sock access off=0 size=8")
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]; \
1072l0_%=: 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
1080SEC("tc")
1081__description("reference tracking: access after release")
1082__failure __msg("!read_ok")
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); \
1091l0_%=: 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
1099SEC("tc")
1100__description("reference tracking: direct access for lookup")
1101__success __retval(0)
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]; \
1121l0_%=: 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
1131SEC("tc")
1132__description("reference tracking: use ptr from bpf_tcp_sock() after release")
1133__failure __msg("invalid mem access")
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; \
1141l0_%=: 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; \
1148l1_%=: 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
1162SEC("tc")
1163__description("reference tracking: use ptr from bpf_sk_fullsock() after release")
1164__failure __msg("invalid mem access")
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; \
1172l0_%=: 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; \
1179l1_%=: 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
1193SEC("tc")
1194__description("reference tracking: use ptr from bpf_sk_fullsock(tp) after release")
1195__failure __msg("invalid mem access")
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; \
1203l0_%=: 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; \
1210l1_%=: 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; \
1217l2_%=: 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
1229SEC("tc")
1230__description("reference tracking: use sk after bpf_sk_release(tp)")
1231__failure __msg("invalid mem access")
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; \
1239l0_%=: 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; \
1246l1_%=: 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
1259SEC("tc")
1260__description("reference tracking: use ptr from bpf_get_listener_sock() after bpf_sk_release(sk)")
1261__success __retval(0)
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; \
1268l0_%=: 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; \
1275l1_%=: 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
1289SEC("tc")
1290__description("reference tracking: bpf_sk_release(listen_sk)")
1291__failure __msg("R1 must be referenced when passed to release function")
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; \
1298l0_%=: 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; \
1305l1_%=: 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 */
1321SEC("tc")
1322__description("reference tracking: tp->snd_cwnd after bpf_sk_fullsock(sk) and bpf_tcp_sock(sk)")
1323__failure __msg("invalid mem access")
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; \
1330l0_%=: 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; \
1341l1_%=: 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
1355SEC("tc")
1356__description("reference tracking: branch tracking valid pointer null comparison")
1357__success __retval(0)
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; \
1366l0_%=: if r6 == 0 goto l1_%=; \
1367 r1 = r6; \
1368 call %[bpf_sk_release]; \
1369l1_%=: 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
1377SEC("tc")
1378__description("reference tracking: branch tracking valid pointer value comparison")
1379__failure __msg("Unreleased reference")
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]; \
1391l0_%=: 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
1399SEC("tc")
1400__description("reference tracking: bpf_sk_release(btf_tcp_sock)")
1401__success
1402__retval(0)
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; \
1409l0_%=: 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; \
1416l1_%=: 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
1427SEC("tc")
1428__description("reference tracking: use ptr from bpf_skc_to_tcp_sock() after release")
1429__failure __msg("invalid mem access")
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; \
1436l0_%=: 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; \
1443l1_%=: 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
1456SEC("socket")
1457__description("reference tracking: try to leak released ptr reg")
1458__success __failure_unpriv __msg_unpriv("R8 !read_ok")
1459__retval(0)
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; \
1471l0_%=: 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; \
1479l1_%=: 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
1495char _license[] SEC("license") = "GPL";
1496

source code of linux/tools/testing/selftests/bpf/progs/verifier_ref_tracking.c