Contributors: 2
Author Tokens Token Proportion Commits Commit Proportion
Eduard Zingerman 816 99.88% 1 50.00%
Andrii Nakryiko 1 0.12% 1 50.00%
Total 817 2

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803
// SPDX-License-Identifier: GPL-2.0
/* Converted from tools/testing/selftests/bpf/verifier/direct_packet_access.c */

#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include "bpf_misc.h"

SEC("tc")
__description("pkt_end - pkt_start is allowed")
__success __retval(TEST_DATA_LEN)
__naked void end_pkt_start_is_allowed(void)
{
	asm volatile ("					\
	r0 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r0 -= r2;					\
	exit;						\
"	:
	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test1")
__success __retval(0)
__naked void direct_packet_access_test1(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r0 = r2;					\
	r0 += 8;					\
	if r0 > r3 goto l0_%=;				\
	r0 = *(u8*)(r2 + 0);				\
l0_%=:	r0 = 0;						\
	exit;						\
"	:
	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test2")
__success __retval(0)
__naked void direct_packet_access_test2(void)
{
	asm volatile ("					\
	r0 = 1;						\
	r4 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r3 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r5 = r3;					\
	r5 += 14;					\
	if r5 > r4 goto l0_%=;				\
	r0 = *(u8*)(r3 + 7);				\
	r4 = *(u8*)(r3 + 12);				\
	r4 *= 14;					\
	r3 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 += r4;					\
	r2 = *(u32*)(r1 + %[__sk_buff_len]);		\
	r2 <<= 49;					\
	r2 >>= 49;					\
	r3 += r2;					\
	r2 = r3;					\
	r2 += 8;					\
	r1 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	if r2 > r1 goto l1_%=;				\
	r1 = *(u8*)(r3 + 4);				\
l1_%=:	r0 = 0;						\
l0_%=:	exit;						\
"	:
	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)),
	  __imm_const(__sk_buff_len, offsetof(struct __sk_buff, len))
	: __clobber_all);
}

SEC("socket")
__description("direct packet access: test3")
__failure __msg("invalid bpf_context access off=76")
__failure_unpriv
__naked void direct_packet_access_test3(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r0 = 0;						\
	exit;						\
"	:
	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test4 (write)")
__success __retval(0)
__naked void direct_packet_access_test4_write(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r0 = r2;					\
	r0 += 8;					\
	if r0 > r3 goto l0_%=;				\
	*(u8*)(r2 + 0) = r2;				\
l0_%=:	r0 = 0;						\
	exit;						\
"	:
	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test5 (pkt_end >= reg, good access)")
__success __retval(0)
__naked void pkt_end_reg_good_access(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r0 = r2;					\
	r0 += 8;					\
	if r3 >= r0 goto l0_%=;				\
	r0 = 1;						\
	exit;						\
l0_%=:	r0 = *(u8*)(r2 + 0);				\
	r0 = 0;						\
	exit;						\
"	:
	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test6 (pkt_end >= reg, bad access)")
__failure __msg("invalid access to packet")
__naked void pkt_end_reg_bad_access(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r0 = r2;					\
	r0 += 8;					\
	if r3 >= r0 goto l0_%=;				\
	r0 = *(u8*)(r2 + 0);				\
	r0 = 1;						\
	exit;						\
l0_%=:	r0 = 0;						\
	exit;						\
"	:
	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test7 (pkt_end >= reg, both accesses)")
__failure __msg("invalid access to packet")
__naked void pkt_end_reg_both_accesses(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r0 = r2;					\
	r0 += 8;					\
	if r3 >= r0 goto l0_%=;				\
	r0 = *(u8*)(r2 + 0);				\
	r0 = 1;						\
	exit;						\
l0_%=:	r0 = *(u8*)(r2 + 0);				\
	r0 = 0;						\
	exit;						\
"	:
	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test8 (double test, variant 1)")
__success __retval(0)
__naked void test8_double_test_variant_1(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r0 = r2;					\
	r0 += 8;					\
	if r3 >= r0 goto l0_%=;				\
	if r0 > r3 goto l1_%=;				\
	r0 = *(u8*)(r2 + 0);				\
l1_%=:	r0 = 1;						\
	exit;						\
l0_%=:	r0 = *(u8*)(r2 + 0);				\
	r0 = 0;						\
	exit;						\
"	:
	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test9 (double test, variant 2)")
__success __retval(0)
__naked void test9_double_test_variant_2(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r0 = r2;					\
	r0 += 8;					\
	if r3 >= r0 goto l0_%=;				\
	r0 = 1;						\
	exit;						\
l0_%=:	if r0 > r3 goto l1_%=;				\
	r0 = *(u8*)(r2 + 0);				\
l1_%=:	r0 = *(u8*)(r2 + 0);				\
	r0 = 0;						\
	exit;						\
"	:
	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test10 (write invalid)")
__failure __msg("invalid access to packet")
__naked void packet_access_test10_write_invalid(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r0 = r2;					\
	r0 += 8;					\
	if r0 > r3 goto l0_%=;				\
	r0 = 0;						\
	exit;						\
l0_%=:	*(u8*)(r2 + 0) = r2;				\
	r0 = 0;						\
	exit;						\
"	:
	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test11 (shift, good access)")
__success __retval(1)
__naked void access_test11_shift_good_access(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r0 = r2;					\
	r0 += 22;					\
	if r0 > r3 goto l0_%=;				\
	r3 = 144;					\
	r5 = r3;					\
	r5 += 23;					\
	r5 >>= 3;					\
	r6 = r2;					\
	r6 += r5;					\
	r0 = 1;						\
	exit;						\
l0_%=:	r0 = 0;						\
	exit;						\
"	:
	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test12 (and, good access)")
__success __retval(1)
__naked void access_test12_and_good_access(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r0 = r2;					\
	r0 += 22;					\
	if r0 > r3 goto l0_%=;				\
	r3 = 144;					\
	r5 = r3;					\
	r5 += 23;					\
	r5 &= 15;					\
	r6 = r2;					\
	r6 += r5;					\
	r0 = 1;						\
	exit;						\
l0_%=:	r0 = 0;						\
	exit;						\
"	:
	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test13 (branches, good access)")
__success __retval(1)
__naked void access_test13_branches_good_access(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r0 = r2;					\
	r0 += 22;					\
	if r0 > r3 goto l0_%=;				\
	r3 = *(u32*)(r1 + %[__sk_buff_mark]);		\
	r4 = 1;						\
	if r3 > r4 goto l1_%=;				\
	r3 = 14;					\
	goto l2_%=;					\
l1_%=:	r3 = 24;					\
l2_%=:	r5 = r3;					\
	r5 += 23;					\
	r5 &= 15;					\
	r6 = r2;					\
	r6 += r5;					\
	r0 = 1;						\
	exit;						\
l0_%=:	r0 = 0;						\
	exit;						\
"	:
	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)),
	  __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test14 (pkt_ptr += 0, CONST_IMM, good access)")
__success __retval(1)
__naked void _0_const_imm_good_access(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r0 = r2;					\
	r0 += 22;					\
	if r0 > r3 goto l0_%=;				\
	r5 = 12;					\
	r5 >>= 4;					\
	r6 = r2;					\
	r6 += r5;					\
	r0 = *(u8*)(r6 + 0);				\
	r0 = 1;						\
	exit;						\
l0_%=:	r0 = 0;						\
	exit;						\
"	:
	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test15 (spill with xadd)")
__failure __msg("R2 invalid mem access 'scalar'")
__flag(BPF_F_ANY_ALIGNMENT)
__naked void access_test15_spill_with_xadd(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r0 = r2;					\
	r0 += 8;					\
	if r0 > r3 goto l0_%=;				\
	r5 = 4096;					\
	r4 = r10;					\
	r4 += -8;					\
	*(u64*)(r4 + 0) = r2;				\
	lock *(u64 *)(r4 + 0) += r5;			\
	r2 = *(u64*)(r4 + 0);				\
	*(u32*)(r2 + 0) = r5;				\
	r0 = 0;						\
l0_%=:	exit;						\
"	:
	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test16 (arith on data_end)")
__failure __msg("R3 pointer arithmetic on pkt_end")
__naked void test16_arith_on_data_end(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r0 = r2;					\
	r0 += 8;					\
	r3 += 16;					\
	if r0 > r3 goto l0_%=;				\
	*(u8*)(r2 + 0) = r2;				\
l0_%=:	r0 = 0;						\
	exit;						\
"	:
	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test17 (pruning, alignment)")
__failure __msg("misaligned packet access off 2+0+15+-4 size 4")
__flag(BPF_F_STRICT_ALIGNMENT)
__naked void packet_access_test17_pruning_alignment(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r7 = *(u32*)(r1 + %[__sk_buff_mark]);		\
	r0 = r2;					\
	r0 += 14;					\
	if r7 > 1 goto l0_%=;				\
l2_%=:	if r0 > r3 goto l1_%=;				\
	*(u32*)(r0 - 4) = r0;				\
l1_%=:	r0 = 0;						\
	exit;						\
l0_%=:	r0 += 1;					\
	goto l2_%=;					\
"	:
	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)),
	  __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test18 (imm += pkt_ptr, 1)")
__success __retval(0)
__naked void test18_imm_pkt_ptr_1(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r0 = 8;						\
	r0 += r2;					\
	if r0 > r3 goto l0_%=;				\
	*(u8*)(r2 + 0) = r2;				\
l0_%=:	r0 = 0;						\
	exit;						\
"	:
	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test19 (imm += pkt_ptr, 2)")
__success __retval(0)
__naked void test19_imm_pkt_ptr_2(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r0 = r2;					\
	r0 += 8;					\
	if r0 > r3 goto l0_%=;				\
	r4 = 4;						\
	r4 += r2;					\
	*(u8*)(r4 + 0) = r4;				\
l0_%=:	r0 = 0;						\
	exit;						\
"	:
	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test20 (x += pkt_ptr, 1)")
__success __retval(0) __flag(BPF_F_ANY_ALIGNMENT)
__naked void test20_x_pkt_ptr_1(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r0 = 0xffffffff;				\
	*(u64*)(r10 - 8) = r0;				\
	r0 = *(u64*)(r10 - 8);				\
	r0 &= 0x7fff;					\
	r4 = r0;					\
	r4 += r2;					\
	r5 = r4;					\
	r4 += %[__imm_0];				\
	if r4 > r3 goto l0_%=;				\
	*(u64*)(r5 + 0) = r4;				\
l0_%=:	r0 = 0;						\
	exit;						\
"	:
	: __imm_const(__imm_0, 0x7fff - 1),
	  __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test21 (x += pkt_ptr, 2)")
__success __retval(0) __flag(BPF_F_ANY_ALIGNMENT)
__naked void test21_x_pkt_ptr_2(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r0 = r2;					\
	r0 += 8;					\
	if r0 > r3 goto l0_%=;				\
	r4 = 0xffffffff;				\
	*(u64*)(r10 - 8) = r4;				\
	r4 = *(u64*)(r10 - 8);				\
	r4 &= 0x7fff;					\
	r4 += r2;					\
	r5 = r4;					\
	r4 += %[__imm_0];				\
	if r4 > r3 goto l0_%=;				\
	*(u64*)(r5 + 0) = r4;				\
l0_%=:	r0 = 0;						\
	exit;						\
"	:
	: __imm_const(__imm_0, 0x7fff - 1),
	  __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test22 (x += pkt_ptr, 3)")
__success __retval(0) __flag(BPF_F_ANY_ALIGNMENT)
__naked void test22_x_pkt_ptr_3(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r0 = r2;					\
	r0 += 8;					\
	*(u64*)(r10 - 8) = r2;				\
	*(u64*)(r10 - 16) = r3;				\
	r3 = *(u64*)(r10 - 16);				\
	if r0 > r3 goto l0_%=;				\
	r2 = *(u64*)(r10 - 8);				\
	r4 = 0xffffffff;				\
	lock *(u64 *)(r10 - 8) += r4;			\
	r4 = *(u64*)(r10 - 8);				\
	r4 >>= 49;					\
	r4 += r2;					\
	r0 = r4;					\
	r0 += 2;					\
	if r0 > r3 goto l0_%=;				\
	r2 = 1;						\
	*(u16*)(r4 + 0) = r2;				\
l0_%=:	r0 = 0;						\
	exit;						\
"	:
	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test23 (x += pkt_ptr, 4)")
__failure __msg("invalid access to packet, off=0 size=8, R5(id=2,off=0,r=0)")
__flag(BPF_F_ANY_ALIGNMENT)
__naked void test23_x_pkt_ptr_4(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r0 = *(u32*)(r1 + %[__sk_buff_mark]);		\
	*(u64*)(r10 - 8) = r0;				\
	r0 = *(u64*)(r10 - 8);				\
	r0 &= 0xffff;					\
	r4 = r0;					\
	r0 = 31;					\
	r0 += r4;					\
	r0 += r2;					\
	r5 = r0;					\
	r0 += %[__imm_0];				\
	if r0 > r3 goto l0_%=;				\
	*(u64*)(r5 + 0) = r0;				\
l0_%=:	r0 = 0;						\
	exit;						\
"	:
	: __imm_const(__imm_0, 0xffff - 1),
	  __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)),
	  __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test24 (x += pkt_ptr, 5)")
__success __retval(0) __flag(BPF_F_ANY_ALIGNMENT)
__naked void test24_x_pkt_ptr_5(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r0 = 0xffffffff;				\
	*(u64*)(r10 - 8) = r0;				\
	r0 = *(u64*)(r10 - 8);				\
	r0 &= 0xff;					\
	r4 = r0;					\
	r0 = 64;					\
	r0 += r4;					\
	r0 += r2;					\
	r5 = r0;					\
	r0 += %[__imm_0];				\
	if r0 > r3 goto l0_%=;				\
	*(u64*)(r5 + 0) = r0;				\
l0_%=:	r0 = 0;						\
	exit;						\
"	:
	: __imm_const(__imm_0, 0x7fff - 1),
	  __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test25 (marking on <, good access)")
__success __retval(0)
__naked void test25_marking_on_good_access(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r0 = r2;					\
	r0 += 8;					\
	if r0 < r3 goto l0_%=;				\
l1_%=:	r0 = 0;						\
	exit;						\
l0_%=:	r0 = *(u8*)(r2 + 0);				\
	goto l1_%=;					\
"	:
	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test26 (marking on <, bad access)")
__failure __msg("invalid access to packet")
__naked void test26_marking_on_bad_access(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r0 = r2;					\
	r0 += 8;					\
	if r0 < r3 goto l0_%=;				\
	r0 = *(u8*)(r2 + 0);				\
l1_%=:	r0 = 0;						\
	exit;						\
l0_%=:	goto l1_%=;					\
"	:
	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test27 (marking on <=, good access)")
__success __retval(1)
__naked void test27_marking_on_good_access(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r0 = r2;					\
	r0 += 8;					\
	if r3 <= r0 goto l0_%=;				\
	r0 = *(u8*)(r2 + 0);				\
l0_%=:	r0 = 1;						\
	exit;						\
"	:
	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test28 (marking on <=, bad access)")
__failure __msg("invalid access to packet")
__naked void test28_marking_on_bad_access(void)
{
	asm volatile ("					\
	r2 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r0 = r2;					\
	r0 += 8;					\
	if r3 <= r0 goto l0_%=;				\
l1_%=:	r0 = 1;						\
	exit;						\
l0_%=:	r0 = *(u8*)(r2 + 0);				\
	goto l1_%=;					\
"	:
	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
	: __clobber_all);
}

SEC("tc")
__description("direct packet access: test29 (reg > pkt_end in subprog)")
__success __retval(0)
__naked void reg_pkt_end_in_subprog(void)
{
	asm volatile ("					\
	r6 = *(u32*)(r1 + %[__sk_buff_data]);		\
	r2 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
	r3 = r6;					\
	r3 += 8;					\
	call reg_pkt_end_in_subprog__1;			\
	if r0 == 0 goto l0_%=;				\
	r0 = *(u8*)(r6 + 0);				\
l0_%=:	r0 = 0;						\
	exit;						\
"	:
	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
	: __clobber_all);
}

static __naked __noinline __attribute__((used))
void reg_pkt_end_in_subprog__1(void)
{
	asm volatile ("					\
	r0 = 0;						\
	if r3 > r2 goto l0_%=;				\
	r0 = 1;						\
l0_%=:	exit;						\
"	::: __clobber_all);
}

SEC("tc")
__description("direct packet access: test30 (check_id() in regsafe(), bad access)")
__failure __msg("invalid access to packet, off=0 size=1, R2")
__flag(BPF_F_TEST_STATE_FREQ)
__naked void id_in_regsafe_bad_access(void)
{
	asm volatile ("					\
	/* r9 = ctx */					\
	r9 = r1;					\
	/* r7 = ktime_get_ns() */			\
	call %[bpf_ktime_get_ns];			\
	r7 = r0;					\
	/* r6 = ktime_get_ns() */			\
	call %[bpf_ktime_get_ns];			\
	r6 = r0;					\
	/* r2 = ctx->data				\
	 * r3 = ctx->data				\
	 * r4 = ctx->data_end				\
	 */						\
	r2 = *(u32*)(r9 + %[__sk_buff_data]);		\
	r3 = *(u32*)(r9 + %[__sk_buff_data]);		\
	r4 = *(u32*)(r9 + %[__sk_buff_data_end]);	\
	/* if r6 > 100 goto exit			\
	 * if r7 > 100 goto exit			\
	 */						\
	if r6 > 100 goto l0_%=;				\
	if r7 > 100 goto l0_%=;				\
	/* r2 += r6              ; this forces assignment of ID to r2\
	 * r2 += 1               ; get some fixed off for r2\
	 * r3 += r7              ; this forces assignment of ID to r3\
	 * r3 += 1               ; get some fixed off for r3\
	 */						\
	r2 += r6;					\
	r2 += 1;					\
	r3 += r7;					\
	r3 += 1;					\
	/* if r6 > r7 goto +1    ; no new information about the state is derived from\
	 *                       ; this check, thus produced verifier states differ\
	 *                       ; only in 'insn_idx'	\
	 * r2 = r3               ; optionally share ID between r2 and r3\
	 */						\
	if r6 != r7 goto l1_%=;				\
	r2 = r3;					\
l1_%=:	/* if r3 > ctx->data_end goto exit */		\
	if r3 > r4 goto l0_%=;				\
	/* r5 = *(u8 *) (r2 - 1) ; access packet memory using r2,\
	 *                       ; this is not always safe\
	 */						\
	r5 = *(u8*)(r2 - 1);				\
l0_%=:	/* exit(0) */					\
	r0 = 0;						\
	exit;						\
"	:
	: __imm(bpf_ktime_get_ns),
	  __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
	: __clobber_all);
}

char _license[] SEC("license") = "GPL";