Linux Audio

Check our new training course

Loading...
v6.13.7
   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] would lead to reference leak")
 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] would lead to reference leak")
 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";
v6.8
   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";