selftests/bpf: additional bpf_call tests
authorDaniel Borkmann <daniel@iogearbox.net>
Fri, 15 Dec 2017 01:55:17 +0000 (17:55 -0800)
committerDaniel Borkmann <daniel@iogearbox.net>
Sun, 17 Dec 2017 19:34:36 +0000 (20:34 +0100)
Add some additional checks for few more corner cases.

Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
tools/testing/selftests/bpf/test_verifier.c

index eaf294822a8f2460af2ca871fbe75e471265a5c8..3bacff0d6f917c844ec34ac1a1e80cd113a9d199 100644 (file)
@@ -8110,6 +8110,180 @@ static struct bpf_test tests[] = {
                .prog_type = BPF_PROG_TYPE_TRACEPOINT,
                .result = ACCEPT,
        },
+       {
+               "calls: not on unpriviledged",
+               .insns = {
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(BPF_REG_0, 2),
+                       BPF_EXIT_INSN(),
+               },
+               .errstr_unpriv = "function calls to other bpf functions are allowed for root only",
+               .result_unpriv = REJECT,
+               .result = ACCEPT,
+       },
+       {
+               "calls: overlapping caller/callee",
+               .insns = {
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+               .errstr = "last insn is not an exit or jmp",
+               .result = REJECT,
+       },
+       {
+               "calls: wrong recursive calls",
+               .insns = {
+                       BPF_JMP_IMM(BPF_JA, 0, 0, 4),
+                       BPF_JMP_IMM(BPF_JA, 0, 0, 4),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, -2),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, -2),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, -2),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+               .errstr = "jump out of range",
+               .result = REJECT,
+       },
+       {
+               "calls: wrong src reg",
+               .insns = {
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 2, 0, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+               .errstr = "BPF_CALL uses reserved fields",
+               .result = REJECT,
+       },
+       {
+               "calls: wrong off value",
+               .insns = {
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, -1, 2),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(BPF_REG_0, 2),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+               .errstr = "BPF_CALL uses reserved fields",
+               .result = REJECT,
+       },
+       {
+               "calls: jump back loop",
+               .insns = {
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, -1),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+               .errstr = "back-edge from insn 0 to 0",
+               .result = REJECT,
+       },
+       {
+               "calls: conditional call",
+               .insns = {
+                       BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+                                   offsetof(struct __sk_buff, mark)),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(BPF_REG_0, 2),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+               .errstr = "jump out of range",
+               .result = REJECT,
+       },
+       {
+               "calls: conditional call 2",
+               .insns = {
+                       BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+                                   offsetof(struct __sk_buff, mark)),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 4),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(BPF_REG_0, 2),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(BPF_REG_0, 3),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+               .result = ACCEPT,
+       },
+       {
+               "calls: conditional call 3",
+               .insns = {
+                       BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+                                   offsetof(struct __sk_buff, mark)),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
+                       BPF_JMP_IMM(BPF_JA, 0, 0, 4),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_JMP_IMM(BPF_JA, 0, 0, -6),
+                       BPF_MOV64_IMM(BPF_REG_0, 3),
+                       BPF_JMP_IMM(BPF_JA, 0, 0, -6),
+               },
+               .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+               .errstr = "back-edge from insn",
+               .result = REJECT,
+       },
+       {
+               "calls: conditional call 4",
+               .insns = {
+                       BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+                                   offsetof(struct __sk_buff, mark)),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 4),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_JMP_IMM(BPF_JA, 0, 0, -5),
+                       BPF_MOV64_IMM(BPF_REG_0, 3),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+               .result = ACCEPT,
+       },
+       {
+               "calls: conditional call 5",
+               .insns = {
+                       BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+                                   offsetof(struct __sk_buff, mark)),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 4),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_JMP_IMM(BPF_JA, 0, 0, -6),
+                       BPF_MOV64_IMM(BPF_REG_0, 3),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+               .errstr = "back-edge from insn",
+               .result = REJECT,
+       },
+       {
+               "calls: conditional call 6",
+               .insns = {
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, -2),
+                       BPF_EXIT_INSN(),
+                       BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+                                   offsetof(struct __sk_buff, mark)),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+               .errstr = "back-edge from insn",
+               .result = REJECT,
+       },
        {
                "calls: using r0 returned by callee",
                .insns = {
@@ -8121,6 +8295,17 @@ static struct bpf_test tests[] = {
                .prog_type = BPF_PROG_TYPE_TRACEPOINT,
                .result = ACCEPT,
        },
+       {
+               "calls: using uninit r0 from callee",
+               .insns = {
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+               .errstr = "!read_ok",
+               .result = REJECT,
+       },
        {
                "calls: callee is using r1",
                .insns = {
@@ -8223,6 +8408,71 @@ static struct bpf_test tests[] = {
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
                .result = ACCEPT,
        },
+       {
+               "calls: calls with stack arith",
+               .insns = {
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -64),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -64),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -64),
+                       BPF_MOV64_IMM(BPF_REG_0, 42),
+                       BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+               .result = ACCEPT,
+       },
+       {
+               "calls: calls with misaligned stack access",
+               .insns = {
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -63),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -61),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -63),
+                       BPF_MOV64_IMM(BPF_REG_0, 42),
+                       BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+               .flags = F_LOAD_WITH_STRICT_ALIGNMENT,
+               .errstr = "misaligned stack access",
+               .result = REJECT,
+       },
+       {
+               "calls: calls control flow, jump test",
+               .insns = {
+                       BPF_MOV64_IMM(BPF_REG_0, 42),
+                       BPF_JMP_IMM(BPF_JA, 0, 0, 2),
+                       BPF_MOV64_IMM(BPF_REG_0, 43),
+                       BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+                       BPF_JMP_IMM(BPF_JA, 0, 0, -3),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+               .result = ACCEPT,
+       },
+       {
+               "calls: calls control flow, jump test 2",
+               .insns = {
+                       BPF_MOV64_IMM(BPF_REG_0, 42),
+                       BPF_JMP_IMM(BPF_JA, 0, 0, 2),
+                       BPF_MOV64_IMM(BPF_REG_0, 43),
+                       BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, -3),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+               .errstr = "jump out of range from insn 1 to 4",
+               .result = REJECT,
+       },
        {
                "calls: two calls with bad jump",
                .insns = {
@@ -8297,6 +8547,18 @@ static struct bpf_test tests[] = {
                .errstr = "invalid destination",
                .result = REJECT,
        },
+       {
+               "calls: invalid call 2",
+               .insns = {
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 0x7fffffff),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+               .errstr = "invalid destination",
+               .result = REJECT,
+       },
        {
                "calls: jumping across function bodies. test1",
                .insns = {
@@ -8366,6 +8628,30 @@ static struct bpf_test tests[] = {
                .errstr = "last insn",
                .result = REJECT,
        },
+       {
+               "calls: ld_abs with changing ctx data in callee",
+               .insns = {
+                       BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
+                       BPF_LD_ABS(BPF_B, 0),
+                       BPF_LD_ABS(BPF_H, 0),
+                       BPF_LD_ABS(BPF_W, 0),
+                       BPF_MOV64_REG(BPF_REG_7, BPF_REG_6),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 5),
+                       BPF_MOV64_REG(BPF_REG_6, BPF_REG_7),
+                       BPF_LD_ABS(BPF_B, 0),
+                       BPF_LD_ABS(BPF_H, 0),
+                       BPF_LD_ABS(BPF_W, 0),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(BPF_REG_2, 1),
+                       BPF_MOV64_IMM(BPF_REG_3, 2),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_skb_vlan_push),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+               .errstr = "BPF_LD_[ABS|IND] instructions cannot be mixed",
+               .result = REJECT,
+       },
        {
                "calls: two calls with bad fallthrough",
                .insns = {
@@ -8459,6 +8745,36 @@ static struct bpf_test tests[] = {
                .errstr = "cannot spill",
                .result = REJECT,
        },
+       {
+               "calls: write into caller stack frame",
+               .insns = {
+                       BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8),
+                       BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2),
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_6, 0),
+                       BPF_EXIT_INSN(),
+                       BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 42),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_XDP,
+               .result = ACCEPT,
+       },
+       {
+               "calls: write into callee stack frame",
+               .insns = {
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2),
+                       BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 42),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_REG(BPF_REG_0, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, -8),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_XDP,
+               .errstr = "cannot return stack pointer",
+               .result = REJECT,
+       },
        {
                "calls: two calls with stack write and void return",
                .insns = {
@@ -9056,6 +9372,287 @@ static struct bpf_test tests[] = {
                .result = ACCEPT,
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
        },
+       {
+               "calls: pkt_ptr spill into caller stack 2",
+               .insns = {
+                       BPF_MOV64_REG(BPF_REG_4, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, -8),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 3),
+                       /* Marking is still kept, but not in all cases safe. */
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_10, -8),
+                       BPF_ST_MEM(BPF_W, BPF_REG_4, 0, 0),
+                       BPF_EXIT_INSN(),
+
+                       /* subprog 1 */
+                       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                                   offsetof(struct __sk_buff, data)),
+                       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                                   offsetof(struct __sk_buff, data_end)),
+                       BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8),
+                       /* spill unchecked pkt_ptr into stack of caller */
+                       BPF_STX_MEM(BPF_DW, BPF_REG_4, BPF_REG_2, 0),
+                       BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 2),
+                       /* now the pkt range is verified, read pkt_ptr from stack */
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_4, 0),
+                       /* write 4 bytes into packet */
+                       BPF_ST_MEM(BPF_W, BPF_REG_2, 0, 0),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+               .errstr = "invalid access to packet",
+               .result = REJECT,
+       },
+       {
+               "calls: pkt_ptr spill into caller stack 3",
+               .insns = {
+                       BPF_MOV64_REG(BPF_REG_4, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, -8),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 4),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
+                       /* Marking is still kept and safe here. */
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_10, -8),
+                       BPF_ST_MEM(BPF_W, BPF_REG_4, 0, 0),
+                       BPF_EXIT_INSN(),
+
+                       /* subprog 1 */
+                       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                                   offsetof(struct __sk_buff, data)),
+                       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                                   offsetof(struct __sk_buff, data_end)),
+                       BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8),
+                       /* spill unchecked pkt_ptr into stack of caller */
+                       BPF_STX_MEM(BPF_DW, BPF_REG_4, BPF_REG_2, 0),
+                       BPF_MOV64_IMM(BPF_REG_5, 0),
+                       BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 3),
+                       BPF_MOV64_IMM(BPF_REG_5, 1),
+                       /* now the pkt range is verified, read pkt_ptr from stack */
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_4, 0),
+                       /* write 4 bytes into packet */
+                       BPF_ST_MEM(BPF_W, BPF_REG_2, 0, 0),
+                       BPF_MOV64_REG(BPF_REG_0, BPF_REG_5),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+               .result = ACCEPT,
+       },
+       {
+               "calls: pkt_ptr spill into caller stack 4",
+               .insns = {
+                       BPF_MOV64_REG(BPF_REG_4, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, -8),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 4),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
+                       /* Check marking propagated. */
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_10, -8),
+                       BPF_ST_MEM(BPF_W, BPF_REG_4, 0, 0),
+                       BPF_EXIT_INSN(),
+
+                       /* subprog 1 */
+                       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                                   offsetof(struct __sk_buff, data)),
+                       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                                   offsetof(struct __sk_buff, data_end)),
+                       BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8),
+                       /* spill unchecked pkt_ptr into stack of caller */
+                       BPF_STX_MEM(BPF_DW, BPF_REG_4, BPF_REG_2, 0),
+                       BPF_MOV64_IMM(BPF_REG_5, 0),
+                       BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 2),
+                       BPF_MOV64_IMM(BPF_REG_5, 1),
+                       /* don't read back pkt_ptr from stack here */
+                       /* write 4 bytes into packet */
+                       BPF_ST_MEM(BPF_W, BPF_REG_2, 0, 0),
+                       BPF_MOV64_REG(BPF_REG_0, BPF_REG_5),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+               .result = ACCEPT,
+       },
+       {
+               "calls: pkt_ptr spill into caller stack 5",
+               .insns = {
+                       BPF_MOV64_REG(BPF_REG_4, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, -8),
+                       BPF_STX_MEM(BPF_DW, BPF_REG_4, BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 3),
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_10, -8),
+                       BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_4, 0),
+                       BPF_EXIT_INSN(),
+
+                       /* subprog 1 */
+                       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                                   offsetof(struct __sk_buff, data)),
+                       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                                   offsetof(struct __sk_buff, data_end)),
+                       BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8),
+                       BPF_MOV64_IMM(BPF_REG_5, 0),
+                       BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 3),
+                       /* spill checked pkt_ptr into stack of caller */
+                       BPF_STX_MEM(BPF_DW, BPF_REG_4, BPF_REG_2, 0),
+                       BPF_MOV64_IMM(BPF_REG_5, 1),
+                       /* don't read back pkt_ptr from stack here */
+                       /* write 4 bytes into packet */
+                       BPF_ST_MEM(BPF_W, BPF_REG_2, 0, 0),
+                       BPF_MOV64_REG(BPF_REG_0, BPF_REG_5),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+               .errstr = "same insn cannot be used with different",
+               .result = REJECT,
+       },
+       {
+               "calls: pkt_ptr spill into caller stack 6",
+               .insns = {
+                       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                                   offsetof(struct __sk_buff, data_end)),
+                       BPF_MOV64_REG(BPF_REG_4, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, -8),
+                       BPF_STX_MEM(BPF_DW, BPF_REG_4, BPF_REG_2, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 3),
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_10, -8),
+                       BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_4, 0),
+                       BPF_EXIT_INSN(),
+
+                       /* subprog 1 */
+                       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                                   offsetof(struct __sk_buff, data)),
+                       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                                   offsetof(struct __sk_buff, data_end)),
+                       BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8),
+                       BPF_MOV64_IMM(BPF_REG_5, 0),
+                       BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 3),
+                       /* spill checked pkt_ptr into stack of caller */
+                       BPF_STX_MEM(BPF_DW, BPF_REG_4, BPF_REG_2, 0),
+                       BPF_MOV64_IMM(BPF_REG_5, 1),
+                       /* don't read back pkt_ptr from stack here */
+                       /* write 4 bytes into packet */
+                       BPF_ST_MEM(BPF_W, BPF_REG_2, 0, 0),
+                       BPF_MOV64_REG(BPF_REG_0, BPF_REG_5),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+               .errstr = "R4 invalid mem access",
+               .result = REJECT,
+       },
+       {
+               "calls: pkt_ptr spill into caller stack 7",
+               .insns = {
+                       BPF_MOV64_IMM(BPF_REG_2, 0),
+                       BPF_MOV64_REG(BPF_REG_4, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, -8),
+                       BPF_STX_MEM(BPF_DW, BPF_REG_4, BPF_REG_2, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 3),
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_10, -8),
+                       BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_4, 0),
+                       BPF_EXIT_INSN(),
+
+                       /* subprog 1 */
+                       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                                   offsetof(struct __sk_buff, data)),
+                       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                                   offsetof(struct __sk_buff, data_end)),
+                       BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8),
+                       BPF_MOV64_IMM(BPF_REG_5, 0),
+                       BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 3),
+                       /* spill checked pkt_ptr into stack of caller */
+                       BPF_STX_MEM(BPF_DW, BPF_REG_4, BPF_REG_2, 0),
+                       BPF_MOV64_IMM(BPF_REG_5, 1),
+                       /* don't read back pkt_ptr from stack here */
+                       /* write 4 bytes into packet */
+                       BPF_ST_MEM(BPF_W, BPF_REG_2, 0, 0),
+                       BPF_MOV64_REG(BPF_REG_0, BPF_REG_5),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+               .errstr = "R4 invalid mem access",
+               .result = REJECT,
+       },
+       {
+               "calls: pkt_ptr spill into caller stack 8",
+               .insns = {
+                       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                                   offsetof(struct __sk_buff, data)),
+                       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                                   offsetof(struct __sk_buff, data_end)),
+                       BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8),
+                       BPF_JMP_REG(BPF_JLE, BPF_REG_0, BPF_REG_3, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_REG(BPF_REG_4, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, -8),
+                       BPF_STX_MEM(BPF_DW, BPF_REG_4, BPF_REG_2, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 3),
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_10, -8),
+                       BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_4, 0),
+                       BPF_EXIT_INSN(),
+
+                       /* subprog 1 */
+                       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                                   offsetof(struct __sk_buff, data)),
+                       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                                   offsetof(struct __sk_buff, data_end)),
+                       BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8),
+                       BPF_MOV64_IMM(BPF_REG_5, 0),
+                       BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 3),
+                       /* spill checked pkt_ptr into stack of caller */
+                       BPF_STX_MEM(BPF_DW, BPF_REG_4, BPF_REG_2, 0),
+                       BPF_MOV64_IMM(BPF_REG_5, 1),
+                       /* don't read back pkt_ptr from stack here */
+                       /* write 4 bytes into packet */
+                       BPF_ST_MEM(BPF_W, BPF_REG_2, 0, 0),
+                       BPF_MOV64_REG(BPF_REG_0, BPF_REG_5),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+               .result = ACCEPT,
+       },
+       {
+               "calls: pkt_ptr spill into caller stack 9",
+               .insns = {
+                       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                                   offsetof(struct __sk_buff, data)),
+                       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                                   offsetof(struct __sk_buff, data_end)),
+                       BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8),
+                       BPF_JMP_REG(BPF_JLE, BPF_REG_0, BPF_REG_3, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_REG(BPF_REG_4, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, -8),
+                       BPF_STX_MEM(BPF_DW, BPF_REG_4, BPF_REG_2, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 3),
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_10, -8),
+                       BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_4, 0),
+                       BPF_EXIT_INSN(),
+
+                       /* subprog 1 */
+                       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                                   offsetof(struct __sk_buff, data)),
+                       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                                   offsetof(struct __sk_buff, data_end)),
+                       BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8),
+                       BPF_MOV64_IMM(BPF_REG_5, 0),
+                       /* spill unchecked pkt_ptr into stack of caller */
+                       BPF_STX_MEM(BPF_DW, BPF_REG_4, BPF_REG_2, 0),
+                       BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 2),
+                       BPF_MOV64_IMM(BPF_REG_5, 1),
+                       /* don't read back pkt_ptr from stack here */
+                       /* write 4 bytes into packet */
+                       BPF_ST_MEM(BPF_W, BPF_REG_2, 0, 0),
+                       BPF_MOV64_REG(BPF_REG_0, BPF_REG_5),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+               .errstr = "invalid access to packet",
+               .result = REJECT,
+       },
        {
                "calls: caller stack init to zero or map_value_or_null",
                .insns = {