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

#include <linux/if_ether.h>
#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+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=31 size=8, R5(id=3,off=31,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);
}

#define access_test_non_linear(name, type, desc, retval, linear_sz, off)                        \
        SEC(type)                                                                               \
        __description("direct packet access: " #name " (non-linear, " type ", " desc ")")       \
        __success __retval(retval)                                                              \
        __linear_size(linear_sz)                                                                \
        __naked void access_non_linear_##name(void)                                             \
        {                                                                                       \
                asm volatile ("                                                                 \
                r2 = *(u32*)(r1 + %[skb_data]);                                                 \
                r3 = *(u32*)(r1 + %[skb_data_end]);                                             \
                r0 = r2;                                                                        \
                r0 += %[offset];                                                                \
                if r0 > r3 goto l0_%=;                                                          \
                r0 = *(u8*)(r0 - 1);                                                            \
                r0 = 0;                                                                         \
                exit;                                                                           \
        l0_%=:  r0 = 1;                                                                         \
                exit;                                                                           \
        "       :                                                                               \
                : __imm_const(skb_data, offsetof(struct __sk_buff, data)),                      \
                  __imm_const(skb_data_end, offsetof(struct __sk_buff, data_end)),              \
                  __imm_const(offset, off)                                                      \
                : __clobber_all);                                                               \
        }

access_test_non_linear(test31, "tc", "too short eth", 1, ETH_HLEN, 22);
access_test_non_linear(test32, "tc", "too short 1", 1, 1, 22);
access_test_non_linear(test33, "tc", "long enough", 0, 22, 22);
access_test_non_linear(test34, "cgroup_skb/ingress", "too short eth", 1, ETH_HLEN, 8);
access_test_non_linear(test35, "cgroup_skb/ingress", "too short 1", 1, 1, 8);
access_test_non_linear(test36, "cgroup_skb/ingress", "long enough", 0, 22, 8);

SEC("tc")
__description("direct packet access: test37 (non-linear, linearized)")
__success __retval(0)
__linear_size(ETH_HLEN)
__naked void access_non_linear_linearized(void)
{
        asm volatile ("                         \
        r6 = r1;                                \
        r2 = 22;                                \
        call %[bpf_skb_pull_data];              \
        r2 = *(u32*)(r6 + %[skb_data]);         \
        r3 = *(u32*)(r6 + %[skb_data_end]);     \
        r0 = r2;                                \
        r0 += 22;                               \
        if r0 > r3 goto l0_%=;                  \
        r0 = *(u8*)(r0 - 1);                    \
        exit;                                   \
l0_%=:  r0 = 1;                                 \
        exit;                                   \
"       :
        : __imm(bpf_skb_pull_data),
          __imm_const(skb_data, offsetof(struct __sk_buff, data)),
          __imm_const(skb_data_end, offsetof(struct __sk_buff, data_end))
        : __clobber_all);
}

SEC("tc")
__description("direct packet access: pkt_range cleared after sub with known scalar")
__failure __msg("invalid access to packet")
__naked void pkt_range_clear_after_sub(void)
{
        asm volatile ("                                 \
        r9 = *(u32*)(r1 + %[__sk_buff_data]);           \
        r8 = *(u32*)(r1 + %[__sk_buff_data_end]);       \
        r9 += 256;                                      \
        if r9 >= r8 goto l0_%=;                         \
        r0 = 0;                                         \
        exit;                                           \
l0_%=:  /* r9 has AT_PKT_END (pkt + 256 >= pkt_end) */  \
        r9 -= 256;                                      \
        /*                                              \
         * AT_PKT_END must not survive the arithmetic.  \
         * is_pkt_ptr_branch_taken must validate both   \
         * branches when visiting the next condition.   \
         */                                             \
        if r9 < r8 goto l1_%=;                          \
        r0 = 0;                                         \
        exit;                                           \
l1_%=:  r0 = *(u8*)(r9 + 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: pkt_range cleared after add with known scalar")
__failure __msg("invalid access to packet")
__naked void pkt_range_clear_after_add(void)
{
        asm volatile ("                                 \
        r9 = *(u32*)(r1 + %[__sk_buff_data]);           \
        r8 = *(u32*)(r1 + %[__sk_buff_data_end]);       \
        r9 += 256;                                      \
        if r9 >= r8 goto l0_%=;                         \
        r0 = 0;                                         \
        exit;                                           \
l0_%=:  /* r9 has AT_PKT_END (pkt + 256 >= pkt_end) */  \
        r9 += -256;                                     \
        /*                                              \
         * Same as sub, but goes through BPF_ADD path.  \
         * AT_PKT_END must not survive the arithmetic.  \
         */                                             \
        if r9 < r8 goto l1_%=;                          \
        r0 = 0;                                         \
        exit;                                           \
l1_%=:  r0 = *(u8*)(r9 + 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);
}

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