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