| { |
| "calls: basic sanity", |
| .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(), |
| }, |
| .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, |
| .retval = 1, |
| }, |
| { |
| "calls: div by 0 in subprog", |
| .insns = { |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 8), |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), |
| BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_1, |
| offsetof(struct __sk_buff, data_end)), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_0), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, 8), |
| BPF_JMP_REG(BPF_JGT, BPF_REG_2, BPF_REG_1, 1), |
| BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0), |
| BPF_MOV64_IMM(BPF_REG_0, 1), |
| BPF_EXIT_INSN(), |
| BPF_MOV32_IMM(BPF_REG_2, 0), |
| BPF_MOV32_IMM(BPF_REG_3, 1), |
| BPF_ALU32_REG(BPF_DIV, BPF_REG_3, BPF_REG_2), |
| BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, |
| offsetof(struct __sk_buff, data)), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
| .result = ACCEPT, |
| .retval = 1, |
| }, |
| { |
| "calls: multiple ret types in subprog 1", |
| .insns = { |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 8), |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), |
| BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_1, |
| offsetof(struct __sk_buff, data_end)), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_0), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, 8), |
| BPF_JMP_REG(BPF_JGT, BPF_REG_2, BPF_REG_1, 1), |
| BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0), |
| BPF_MOV64_IMM(BPF_REG_0, 1), |
| BPF_EXIT_INSN(), |
| BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, |
| offsetof(struct __sk_buff, data)), |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), |
| BPF_MOV32_IMM(BPF_REG_0, 42), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
| .result = REJECT, |
| .errstr = "R0 invalid mem access 'inv'", |
| }, |
| { |
| "calls: multiple ret types in subprog 2", |
| .insns = { |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 8), |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), |
| BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_1, |
| offsetof(struct __sk_buff, data_end)), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_0), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, 8), |
| BPF_JMP_REG(BPF_JGT, BPF_REG_2, BPF_REG_1, 1), |
| BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0), |
| BPF_MOV64_IMM(BPF_REG_0, 1), |
| BPF_EXIT_INSN(), |
| BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, |
| offsetof(struct __sk_buff, data)), |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 9), |
| BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), |
| BPF_LD_MAP_FD(BPF_REG_1, 0), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), |
| BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_6, |
| offsetof(struct __sk_buff, data)), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 64), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
| .fixup_map_hash_8b = { 16 }, |
| .result = REJECT, |
| .errstr = "R0 min value is outside of the array range", |
| }, |
| { |
| "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_SOCKET_FILTER, |
| .errstr_unpriv = "back-edge from insn", |
| .result_unpriv = REJECT, |
| .result = ACCEPT, |
| .retval = 1, |
| }, |
| { |
| "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_SCHED_CLS, |
| .result = ACCEPT, |
| .retval = 1, |
| }, |
| { |
| "calls: conditional call 6", |
| .insns = { |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), |
| BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, -3), |
| 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_SCHED_CLS, |
| .errstr = "infinite loop detected", |
| .result = REJECT, |
| }, |
| { |
| "calls: using r0 returned by callee", |
| .insns = { |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1), |
| BPF_EXIT_INSN(), |
| BPF_MOV64_IMM(BPF_REG_0, 2), |
| BPF_EXIT_INSN(), |
| }, |
| .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 = { |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1), |
| BPF_EXIT_INSN(), |
| BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, |
| offsetof(struct __sk_buff, len)), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_SCHED_ACT, |
| .result = ACCEPT, |
| .retval = TEST_DATA_LEN, |
| }, |
| { |
| "calls: callee using args1", |
| .insns = { |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1), |
| BPF_EXIT_INSN(), |
| BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), |
| BPF_EXIT_INSN(), |
| }, |
| .errstr_unpriv = "allowed for root only", |
| .result_unpriv = REJECT, |
| .result = ACCEPT, |
| .retval = POINTER_VALUE, |
| }, |
| { |
| "calls: callee using wrong args2", |
| .insns = { |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1), |
| BPF_EXIT_INSN(), |
| BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
| .errstr = "R2 !read_ok", |
| .result = REJECT, |
| }, |
| { |
| "calls: callee using two args", |
| .insns = { |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
| BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_6, |
| offsetof(struct __sk_buff, len)), |
| BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_6, |
| offsetof(struct __sk_buff, len)), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1), |
| BPF_EXIT_INSN(), |
| BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), |
| BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_2), |
| BPF_EXIT_INSN(), |
| }, |
| .errstr_unpriv = "allowed for root only", |
| .result_unpriv = REJECT, |
| .result = ACCEPT, |
| .retval = TEST_DATA_LEN + TEST_DATA_LEN - ETH_HLEN - ETH_HLEN, |
| }, |
| { |
| "calls: callee changing pkt pointers", |
| .insns = { |
| BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, offsetof(struct xdp_md, data)), |
| BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_1, |
| offsetof(struct xdp_md, data_end)), |
| BPF_MOV64_REG(BPF_REG_8, BPF_REG_6), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_8, 8), |
| BPF_JMP_REG(BPF_JGT, BPF_REG_8, BPF_REG_7, 2), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 3), |
| /* clear_all_pkt_pointers() has to walk all frames |
| * to make sure that pkt pointers in the caller |
| * are cleared when callee is calling a helper that |
| * adjusts packet size |
| */ |
| BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_6, 0), |
| BPF_MOV32_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| BPF_MOV64_IMM(BPF_REG_2, 0), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_xdp_adjust_head), |
| BPF_EXIT_INSN(), |
| }, |
| .result = REJECT, |
| .errstr = "R6 invalid mem access 'inv'", |
| .prog_type = BPF_PROG_TYPE_XDP, |
| .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
| }, |
| { |
| "calls: ptr null check in subprog", |
| .insns = { |
| BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), |
| BPF_LD_MAP_FD(BPF_REG_1, 0), |
| BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_0), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 3), |
| BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), |
| BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_6, 0), |
| BPF_EXIT_INSN(), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), |
| BPF_MOV64_IMM(BPF_REG_0, 1), |
| BPF_EXIT_INSN(), |
| }, |
| .errstr_unpriv = "function calls to other bpf functions are allowed for root only", |
| .fixup_map_hash_48b = { 3 }, |
| .result_unpriv = REJECT, |
| .result = ACCEPT, |
| .retval = 0, |
| }, |
| { |
| "calls: two calls with args", |
| .insns = { |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1), |
| BPF_EXIT_INSN(), |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 6), |
| BPF_MOV64_REG(BPF_REG_7, BPF_REG_0), |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 3), |
| BPF_ALU64_REG(BPF_ADD, BPF_REG_7, BPF_REG_0), |
| BPF_MOV64_REG(BPF_REG_0, BPF_REG_7), |
| BPF_EXIT_INSN(), |
| BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, |
| offsetof(struct __sk_buff, len)), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
| .result = ACCEPT, |
| .retval = TEST_DATA_LEN + TEST_DATA_LEN, |
| }, |
| { |
| "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, |
| .retval = 42, |
| }, |
| { |
| "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, |
| .retval = 43, |
| }, |
| { |
| "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 = { |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1), |
| BPF_EXIT_INSN(), |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 6), |
| BPF_MOV64_REG(BPF_REG_7, BPF_REG_0), |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 3), |
| BPF_ALU64_REG(BPF_ADD, BPF_REG_7, BPF_REG_0), |
| BPF_MOV64_REG(BPF_REG_0, BPF_REG_7), |
| BPF_EXIT_INSN(), |
| BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, |
| offsetof(struct __sk_buff, len)), |
| BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, -3), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
| .errstr = "jump out of range from insn 11 to 9", |
| .result = REJECT, |
| }, |
| { |
| "calls: recursive call. test1", |
| .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, -1), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
| .errstr = "back-edge", |
| .result = REJECT, |
| }, |
| { |
| "calls: recursive call. test2", |
| .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, -3), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
| .errstr = "back-edge", |
| .result = REJECT, |
| }, |
| { |
| "calls: unreachable code", |
| .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, 1), |
| BPF_EXIT_INSN(), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
| .errstr = "unreachable insn 6", |
| .result = REJECT, |
| }, |
| { |
| "calls: invalid call", |
| .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, -4), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
| .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 = { |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, -3), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
| .errstr = "jump out of range", |
| .result = REJECT, |
| }, |
| { |
| "calls: jumping across function bodies. test2", |
| .insns = { |
| BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 3), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
| .errstr = "jump out of range", |
| .result = REJECT, |
| }, |
| { |
| "calls: call without exit", |
| .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, 1), |
| BPF_EXIT_INSN(), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, -2), |
| }, |
| .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
| .errstr = "not an exit", |
| .result = REJECT, |
| }, |
| { |
| "calls: call into middle of ld_imm64", |
| .insns = { |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 3), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 3), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| BPF_LD_IMM64(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
| .errstr = "last insn", |
| .result = REJECT, |
| }, |
| { |
| "calls: call into middle of other call", |
| .insns = { |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 3), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 3), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
| .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 = { |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1), |
| BPF_EXIT_INSN(), |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 6), |
| BPF_MOV64_REG(BPF_REG_7, BPF_REG_0), |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 3), |
| BPF_ALU64_REG(BPF_ADD, BPF_REG_7, BPF_REG_0), |
| BPF_MOV64_REG(BPF_REG_0, BPF_REG_7), |
| BPF_MOV64_REG(BPF_REG_0, BPF_REG_0), |
| BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, |
| offsetof(struct __sk_buff, len)), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
| .errstr = "not an exit", |
| .result = REJECT, |
| }, |
| { |
| "calls: two calls with stack read", |
| .insns = { |
| BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1), |
| BPF_EXIT_INSN(), |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 6), |
| BPF_MOV64_REG(BPF_REG_7, BPF_REG_0), |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 3), |
| BPF_ALU64_REG(BPF_ADD, BPF_REG_7, BPF_REG_0), |
| BPF_MOV64_REG(BPF_REG_0, BPF_REG_7), |
| BPF_EXIT_INSN(), |
| BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_XDP, |
| .result = ACCEPT, |
| }, |
| { |
| "calls: two calls with stack write", |
| .insns = { |
| /* main prog */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -16), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), |
| BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_10, -16), |
| BPF_EXIT_INSN(), |
| |
| /* subprog 1 */ |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
| BPF_MOV64_REG(BPF_REG_7, BPF_REG_2), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 7), |
| BPF_MOV64_REG(BPF_REG_8, BPF_REG_0), |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 4), |
| BPF_ALU64_REG(BPF_ADD, BPF_REG_8, BPF_REG_0), |
| BPF_MOV64_REG(BPF_REG_0, BPF_REG_8), |
| /* write into stack frame of main prog */ |
| BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| |
| /* subprog 2 */ |
| /* read from stack frame of main prog */ |
| BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_XDP, |
| .result = ACCEPT, |
| }, |
| { |
| "calls: stack overflow using two frames (pre-call access)", |
| .insns = { |
| /* prog 1 */ |
| BPF_ST_MEM(BPF_B, BPF_REG_10, -300, 0), |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), |
| BPF_EXIT_INSN(), |
| |
| /* prog 2 */ |
| BPF_ST_MEM(BPF_B, BPF_REG_10, -300, 0), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_XDP, |
| .errstr = "combined stack size", |
| .result = REJECT, |
| }, |
| { |
| "calls: stack overflow using two frames (post-call access)", |
| .insns = { |
| /* prog 1 */ |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 2), |
| BPF_ST_MEM(BPF_B, BPF_REG_10, -300, 0), |
| BPF_EXIT_INSN(), |
| |
| /* prog 2 */ |
| BPF_ST_MEM(BPF_B, BPF_REG_10, -300, 0), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_XDP, |
| .errstr = "combined stack size", |
| .result = REJECT, |
| }, |
| { |
| "calls: stack depth check using three frames. test1", |
| .insns = { |
| /* main */ |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 4), /* call A */ |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 5), /* call B */ |
| BPF_ST_MEM(BPF_B, BPF_REG_10, -32, 0), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| /* A */ |
| BPF_ST_MEM(BPF_B, BPF_REG_10, -256, 0), |
| BPF_EXIT_INSN(), |
| /* B */ |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, -3), /* call A */ |
| BPF_ST_MEM(BPF_B, BPF_REG_10, -64, 0), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_XDP, |
| /* stack_main=32, stack_A=256, stack_B=64 |
| * and max(main+A, main+A+B) < 512 |
| */ |
| .result = ACCEPT, |
| }, |
| { |
| "calls: stack depth check using three frames. test2", |
| .insns = { |
| /* main */ |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 4), /* call A */ |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 5), /* call B */ |
| BPF_ST_MEM(BPF_B, BPF_REG_10, -32, 0), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| /* A */ |
| BPF_ST_MEM(BPF_B, BPF_REG_10, -64, 0), |
| BPF_EXIT_INSN(), |
| /* B */ |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, -3), /* call A */ |
| BPF_ST_MEM(BPF_B, BPF_REG_10, -256, 0), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_XDP, |
| /* stack_main=32, stack_A=64, stack_B=256 |
| * and max(main+A, main+A+B) < 512 |
| */ |
| .result = ACCEPT, |
| }, |
| { |
| "calls: stack depth check using three frames. test3", |
| .insns = { |
| /* main */ |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 6), /* call A */ |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 8), /* call B */ |
| BPF_JMP_IMM(BPF_JGE, BPF_REG_6, 0, 1), |
| BPF_ST_MEM(BPF_B, BPF_REG_10, -64, 0), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| /* A */ |
| BPF_JMP_IMM(BPF_JLT, BPF_REG_1, 10, 1), |
| BPF_EXIT_INSN(), |
| BPF_ST_MEM(BPF_B, BPF_REG_10, -224, 0), |
| BPF_JMP_IMM(BPF_JA, 0, 0, -3), |
| /* B */ |
| BPF_JMP_IMM(BPF_JGT, BPF_REG_1, 2, 1), |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, -6), /* call A */ |
| BPF_ST_MEM(BPF_B, BPF_REG_10, -256, 0), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_XDP, |
| /* stack_main=64, stack_A=224, stack_B=256 |
| * and max(main+A, main+A+B) > 512 |
| */ |
| .errstr = "combined stack", |
| .result = REJECT, |
| }, |
| { |
| "calls: stack depth check using three frames. test4", |
| /* void main(void) { |
| * func1(0); |
| * func1(1); |
| * func2(1); |
| * } |
| * void func1(int alloc_or_recurse) { |
| * if (alloc_or_recurse) { |
| * frame_pointer[-300] = 1; |
| * } else { |
| * func2(alloc_or_recurse); |
| * } |
| * } |
| * void func2(int alloc_or_recurse) { |
| * if (alloc_or_recurse) { |
| * frame_pointer[-300] = 1; |
| * } |
| * } |
| */ |
| .insns = { |
| /* main */ |
| BPF_MOV64_IMM(BPF_REG_1, 0), |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 6), /* call A */ |
| BPF_MOV64_IMM(BPF_REG_1, 1), |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 4), /* call A */ |
| BPF_MOV64_IMM(BPF_REG_1, 1), |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 7), /* call B */ |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| /* A */ |
| BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 2), |
| BPF_ST_MEM(BPF_B, BPF_REG_10, -300, 0), |
| BPF_EXIT_INSN(), |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call B */ |
| BPF_EXIT_INSN(), |
| /* B */ |
| BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), |
| BPF_ST_MEM(BPF_B, BPF_REG_10, -300, 0), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_XDP, |
| .result = REJECT, |
| .errstr = "combined stack", |
| }, |
| { |
| "calls: stack depth check using three frames. test5", |
| .insns = { |
| /* main */ |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call A */ |
| BPF_EXIT_INSN(), |
| /* A */ |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call B */ |
| BPF_EXIT_INSN(), |
| /* B */ |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call C */ |
| BPF_EXIT_INSN(), |
| /* C */ |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call D */ |
| BPF_EXIT_INSN(), |
| /* D */ |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call E */ |
| BPF_EXIT_INSN(), |
| /* E */ |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call F */ |
| BPF_EXIT_INSN(), |
| /* F */ |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call G */ |
| BPF_EXIT_INSN(), |
| /* G */ |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call H */ |
| BPF_EXIT_INSN(), |
| /* H */ |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_XDP, |
| .errstr = "call stack", |
| .result = REJECT, |
| }, |
| { |
| "calls: stack depth check in dead code", |
| .insns = { |
| /* main */ |
| BPF_MOV64_IMM(BPF_REG_1, 0), |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call A */ |
| BPF_EXIT_INSN(), |
| /* A */ |
| BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 2), /* call B */ |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| /* B */ |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call C */ |
| BPF_EXIT_INSN(), |
| /* C */ |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call D */ |
| BPF_EXIT_INSN(), |
| /* D */ |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call E */ |
| BPF_EXIT_INSN(), |
| /* E */ |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call F */ |
| BPF_EXIT_INSN(), |
| /* F */ |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call G */ |
| BPF_EXIT_INSN(), |
| /* G */ |
| BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 1), /* call H */ |
| BPF_EXIT_INSN(), |
| /* H */ |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_XDP, |
| .errstr = "call stack", |
| .result = REJECT, |
| }, |
| { |
| "calls: spill into caller stack frame", |
| .insns = { |
| BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1), |
| BPF_EXIT_INSN(), |
| BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_1, 0), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_XDP, |
| .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, |
| .retval = 42, |
| }, |
| { |
| "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 = { |
| /* main prog */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -16), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), |
| BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_10, -16), |
| BPF_EXIT_INSN(), |
| |
| /* subprog 1 */ |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
| BPF_MOV64_REG(BPF_REG_7, BPF_REG_2), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 3), |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1), |
| BPF_EXIT_INSN(), |
| |
| /* subprog 2 */ |
| /* write into stack frame of main prog */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 0), |
| BPF_EXIT_INSN(), /* void return */ |
| }, |
| .prog_type = BPF_PROG_TYPE_XDP, |
| .result = ACCEPT, |
| }, |
| { |
| "calls: ambiguous return value", |
| .insns = { |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 5), |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), |
| BPF_EXIT_INSN(), |
| BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| }, |
| .errstr_unpriv = "allowed for root only", |
| .result_unpriv = REJECT, |
| .errstr = "R0 !read_ok", |
| .result = REJECT, |
| }, |
| { |
| "calls: two calls that return map_value", |
| .insns = { |
| /* main prog */ |
| /* pass fp-16, fp-8 into a function */ |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -16), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 8), |
| |
| /* fetch map_value_ptr from the stack of this function */ |
| BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_10, -8), |
| BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), |
| /* write into map value */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0), |
| /* fetch secound map_value_ptr from the stack */ |
| BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_10, -16), |
| BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), |
| /* write into map value */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| |
| /* subprog 1 */ |
| /* call 3rd function twice */ |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
| BPF_MOV64_REG(BPF_REG_7, BPF_REG_2), |
| /* first time with fp-8 */ |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 3), |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), |
| /* second time with fp-16 */ |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1), |
| BPF_EXIT_INSN(), |
| |
| /* subprog 2 */ |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
| /* lookup from map */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), |
| BPF_LD_MAP_FD(BPF_REG_1, 0), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), |
| /* write map_value_ptr into stack frame of main prog */ |
| BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_0, 0), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), /* return 0 */ |
| }, |
| .prog_type = BPF_PROG_TYPE_XDP, |
| .fixup_map_hash_8b = { 23 }, |
| .result = ACCEPT, |
| }, |
| { |
| "calls: two calls that return map_value with bool condition", |
| .insns = { |
| /* main prog */ |
| /* pass fp-16, fp-8 into a function */ |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -16), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| |
| /* subprog 1 */ |
| /* call 3rd function twice */ |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
| BPF_MOV64_REG(BPF_REG_7, BPF_REG_2), |
| /* first time with fp-8 */ |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 9), |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 1, 2), |
| /* fetch map_value_ptr from the stack of this function */ |
| BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_6, 0), |
| /* write into map value */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0), |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), |
| /* second time with fp-16 */ |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 4), |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 1, 2), |
| /* fetch secound map_value_ptr from the stack */ |
| BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_7, 0), |
| /* write into map value */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0), |
| BPF_EXIT_INSN(), |
| |
| /* subprog 2 */ |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
| /* lookup from map */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), |
| BPF_LD_MAP_FD(BPF_REG_1, 0), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), /* return 0 */ |
| /* write map_value_ptr into stack frame of main prog */ |
| BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_0, 0), |
| BPF_MOV64_IMM(BPF_REG_0, 1), |
| BPF_EXIT_INSN(), /* return 1 */ |
| }, |
| .prog_type = BPF_PROG_TYPE_XDP, |
| .fixup_map_hash_8b = { 23 }, |
| .result = ACCEPT, |
| }, |
| { |
| "calls: two calls that return map_value with incorrect bool check", |
| .insns = { |
| /* main prog */ |
| /* pass fp-16, fp-8 into a function */ |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -16), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| |
| /* subprog 1 */ |
| /* call 3rd function twice */ |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
| BPF_MOV64_REG(BPF_REG_7, BPF_REG_2), |
| /* first time with fp-8 */ |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 9), |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 1, 2), |
| /* fetch map_value_ptr from the stack of this function */ |
| BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_6, 0), |
| /* write into map value */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0), |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), |
| /* second time with fp-16 */ |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 4), |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), |
| /* fetch secound map_value_ptr from the stack */ |
| BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_7, 0), |
| /* write into map value */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0), |
| BPF_EXIT_INSN(), |
| |
| /* subprog 2 */ |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
| /* lookup from map */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), |
| BPF_LD_MAP_FD(BPF_REG_1, 0), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), /* return 0 */ |
| /* write map_value_ptr into stack frame of main prog */ |
| BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_0, 0), |
| BPF_MOV64_IMM(BPF_REG_0, 1), |
| BPF_EXIT_INSN(), /* return 1 */ |
| }, |
| .prog_type = BPF_PROG_TYPE_XDP, |
| .fixup_map_hash_8b = { 23 }, |
| .result = REJECT, |
| .errstr = "invalid read from stack off -16+0 size 8", |
| }, |
| { |
| "calls: two calls that receive map_value via arg=ptr_stack_of_caller. test1", |
| .insns = { |
| /* main prog */ |
| /* pass fp-16, fp-8 into a function */ |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -16), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| |
| /* subprog 1 */ |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
| BPF_MOV64_REG(BPF_REG_7, BPF_REG_2), |
| /* 1st lookup from map */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), |
| BPF_LD_MAP_FD(BPF_REG_1, 0), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), |
| BPF_MOV64_IMM(BPF_REG_8, 0), |
| BPF_JMP_IMM(BPF_JA, 0, 0, 2), |
| /* write map_value_ptr into stack frame of main prog at fp-8 */ |
| BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_0, 0), |
| BPF_MOV64_IMM(BPF_REG_8, 1), |
| |
| /* 2nd lookup from map */ |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), /* 20 */ |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), |
| BPF_LD_MAP_FD(BPF_REG_1, 0), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, /* 24 */ |
| BPF_FUNC_map_lookup_elem), |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), |
| BPF_MOV64_IMM(BPF_REG_9, 0), |
| BPF_JMP_IMM(BPF_JA, 0, 0, 2), |
| /* write map_value_ptr into stack frame of main prog at fp-16 */ |
| BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
| BPF_MOV64_IMM(BPF_REG_9, 1), |
| |
| /* call 3rd func with fp-8, 0|1, fp-16, 0|1 */ |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), /* 30 */ |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_8), |
| BPF_MOV64_REG(BPF_REG_3, BPF_REG_7), |
| BPF_MOV64_REG(BPF_REG_4, BPF_REG_9), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1), /* 34 */ |
| BPF_EXIT_INSN(), |
| |
| /* subprog 2 */ |
| /* if arg2 == 1 do *arg1 = 0 */ |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_2, 1, 2), |
| /* fetch map_value_ptr from the stack of this function */ |
| BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 0), |
| /* write into map value */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0), |
| |
| /* if arg4 == 1 do *arg3 = 0 */ |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_4, 1, 2), |
| /* fetch map_value_ptr from the stack of this function */ |
| BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_3, 0), |
| /* write into map value */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_0, 2, 0), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
| .fixup_map_hash_8b = { 12, 22 }, |
| .result = REJECT, |
| .errstr = "invalid access to map value, value_size=8 off=2 size=8", |
| .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
| }, |
| { |
| "calls: two calls that receive map_value via arg=ptr_stack_of_caller. test2", |
| .insns = { |
| /* main prog */ |
| /* pass fp-16, fp-8 into a function */ |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -16), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| |
| /* subprog 1 */ |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
| BPF_MOV64_REG(BPF_REG_7, BPF_REG_2), |
| /* 1st lookup from map */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), |
| BPF_LD_MAP_FD(BPF_REG_1, 0), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), |
| BPF_MOV64_IMM(BPF_REG_8, 0), |
| BPF_JMP_IMM(BPF_JA, 0, 0, 2), |
| /* write map_value_ptr into stack frame of main prog at fp-8 */ |
| BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_0, 0), |
| BPF_MOV64_IMM(BPF_REG_8, 1), |
| |
| /* 2nd lookup from map */ |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), /* 20 */ |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), |
| BPF_LD_MAP_FD(BPF_REG_1, 0), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, /* 24 */ |
| BPF_FUNC_map_lookup_elem), |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), |
| BPF_MOV64_IMM(BPF_REG_9, 0), |
| BPF_JMP_IMM(BPF_JA, 0, 0, 2), |
| /* write map_value_ptr into stack frame of main prog at fp-16 */ |
| BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
| BPF_MOV64_IMM(BPF_REG_9, 1), |
| |
| /* call 3rd func with fp-8, 0|1, fp-16, 0|1 */ |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), /* 30 */ |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_8), |
| BPF_MOV64_REG(BPF_REG_3, BPF_REG_7), |
| BPF_MOV64_REG(BPF_REG_4, BPF_REG_9), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1), /* 34 */ |
| BPF_EXIT_INSN(), |
| |
| /* subprog 2 */ |
| /* if arg2 == 1 do *arg1 = 0 */ |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_2, 1, 2), |
| /* fetch map_value_ptr from the stack of this function */ |
| BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 0), |
| /* write into map value */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0), |
| |
| /* if arg4 == 1 do *arg3 = 0 */ |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_4, 1, 2), |
| /* fetch map_value_ptr from the stack of this function */ |
| BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_3, 0), |
| /* write into map value */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
| .fixup_map_hash_8b = { 12, 22 }, |
| .result = ACCEPT, |
| }, |
| { |
| "calls: two jumps that receive map_value via arg=ptr_stack_of_jumper. test3", |
| .insns = { |
| /* main prog */ |
| /* pass fp-16, fp-8 into a function */ |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -16), |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, 2), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| |
| /* subprog 1 */ |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
| BPF_MOV64_REG(BPF_REG_7, BPF_REG_2), |
| /* 1st lookup from map */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_10, -24, 0), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -24), |
| BPF_LD_MAP_FD(BPF_REG_1, 0), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), |
| BPF_MOV64_IMM(BPF_REG_8, 0), |
| BPF_JMP_IMM(BPF_JA, 0, 0, 2), |
| /* write map_value_ptr into stack frame of main prog at fp-8 */ |
| BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_0, 0), |
| BPF_MOV64_IMM(BPF_REG_8, 1), |
| |
| /* 2nd lookup from map */ |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -24), |
| BPF_LD_MAP_FD(BPF_REG_1, 0), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), |
| BPF_MOV64_IMM(BPF_REG_9, 0), // 26 |
| BPF_JMP_IMM(BPF_JA, 0, 0, 2), |
| /* write map_value_ptr into stack frame of main prog at fp-16 */ |
| BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
| BPF_MOV64_IMM(BPF_REG_9, 1), |
| |
| /* call 3rd func with fp-8, 0|1, fp-16, 0|1 */ |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), // 30 |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_8), |
| BPF_MOV64_REG(BPF_REG_3, BPF_REG_7), |
| BPF_MOV64_REG(BPF_REG_4, BPF_REG_9), |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, 1), // 34 |
| BPF_JMP_IMM(BPF_JA, 0, 0, -30), |
| |
| /* subprog 2 */ |
| /* if arg2 == 1 do *arg1 = 0 */ |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_2, 1, 2), |
| /* fetch map_value_ptr from the stack of this function */ |
| BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 0), |
| /* write into map value */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0), |
| |
| /* if arg4 == 1 do *arg3 = 0 */ |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_4, 1, 2), |
| /* fetch map_value_ptr from the stack of this function */ |
| BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_3, 0), |
| /* write into map value */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_0, 2, 0), |
| BPF_JMP_IMM(BPF_JA, 0, 0, -8), |
| }, |
| .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
| .fixup_map_hash_8b = { 12, 22 }, |
| .result = REJECT, |
| .errstr = "invalid access to map value, value_size=8 off=2 size=8", |
| .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
| }, |
| { |
| "calls: two calls that receive map_value_ptr_or_null via arg. test1", |
| .insns = { |
| /* main prog */ |
| /* pass fp-16, fp-8 into a function */ |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -16), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| |
| /* subprog 1 */ |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
| BPF_MOV64_REG(BPF_REG_7, BPF_REG_2), |
| /* 1st lookup from map */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), |
| BPF_LD_MAP_FD(BPF_REG_1, 0), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), |
| /* write map_value_ptr_or_null into stack frame of main prog at fp-8 */ |
| BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_0, 0), |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), |
| BPF_MOV64_IMM(BPF_REG_8, 0), |
| BPF_JMP_IMM(BPF_JA, 0, 0, 1), |
| BPF_MOV64_IMM(BPF_REG_8, 1), |
| |
| /* 2nd lookup from map */ |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), |
| BPF_LD_MAP_FD(BPF_REG_1, 0), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), |
| /* write map_value_ptr_or_null into stack frame of main prog at fp-16 */ |
| BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), |
| BPF_MOV64_IMM(BPF_REG_9, 0), |
| BPF_JMP_IMM(BPF_JA, 0, 0, 1), |
| BPF_MOV64_IMM(BPF_REG_9, 1), |
| |
| /* call 3rd func with fp-8, 0|1, fp-16, 0|1 */ |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_8), |
| BPF_MOV64_REG(BPF_REG_3, BPF_REG_7), |
| BPF_MOV64_REG(BPF_REG_4, BPF_REG_9), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1), |
| BPF_EXIT_INSN(), |
| |
| /* subprog 2 */ |
| /* if arg2 == 1 do *arg1 = 0 */ |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_2, 1, 2), |
| /* fetch map_value_ptr from the stack of this function */ |
| BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 0), |
| /* write into map value */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0), |
| |
| /* if arg4 == 1 do *arg3 = 0 */ |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_4, 1, 2), |
| /* fetch map_value_ptr from the stack of this function */ |
| BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_3, 0), |
| /* write into map value */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
| .fixup_map_hash_8b = { 12, 22 }, |
| .result = ACCEPT, |
| }, |
| { |
| "calls: two calls that receive map_value_ptr_or_null via arg. test2", |
| .insns = { |
| /* main prog */ |
| /* pass fp-16, fp-8 into a function */ |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -16), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| |
| /* subprog 1 */ |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
| BPF_MOV64_REG(BPF_REG_7, BPF_REG_2), |
| /* 1st lookup from map */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), |
| BPF_LD_MAP_FD(BPF_REG_1, 0), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), |
| /* write map_value_ptr_or_null into stack frame of main prog at fp-8 */ |
| BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_0, 0), |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), |
| BPF_MOV64_IMM(BPF_REG_8, 0), |
| BPF_JMP_IMM(BPF_JA, 0, 0, 1), |
| BPF_MOV64_IMM(BPF_REG_8, 1), |
| |
| /* 2nd lookup from map */ |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), |
| BPF_LD_MAP_FD(BPF_REG_1, 0), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), |
| /* write map_value_ptr_or_null into stack frame of main prog at fp-16 */ |
| BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), |
| BPF_MOV64_IMM(BPF_REG_9, 0), |
| BPF_JMP_IMM(BPF_JA, 0, 0, 1), |
| BPF_MOV64_IMM(BPF_REG_9, 1), |
| |
| /* call 3rd func with fp-8, 0|1, fp-16, 0|1 */ |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_8), |
| BPF_MOV64_REG(BPF_REG_3, BPF_REG_7), |
| BPF_MOV64_REG(BPF_REG_4, BPF_REG_9), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1), |
| BPF_EXIT_INSN(), |
| |
| /* subprog 2 */ |
| /* if arg2 == 1 do *arg1 = 0 */ |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_2, 1, 2), |
| /* fetch map_value_ptr from the stack of this function */ |
| BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 0), |
| /* write into map value */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0), |
| |
| /* if arg4 == 0 do *arg3 = 0 */ |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_4, 0, 2), |
| /* fetch map_value_ptr from the stack of this function */ |
| BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_3, 0), |
| /* write into map value */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
| .fixup_map_hash_8b = { 12, 22 }, |
| .result = REJECT, |
| .errstr = "R0 invalid mem access 'inv'", |
| }, |
| { |
| "calls: pkt_ptr spill into caller stack", |
| .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, 1), |
| 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(), |
| }, |
| .result = ACCEPT, |
| .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
| .retval = POINTER_VALUE, |
| .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
| }, |
| { |
| "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, |
| .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
| }, |
| { |
| "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, |
| .retval = 1, |
| .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
| }, |
| { |
| "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, |
| .retval = 1, |
| .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
| }, |
| { |
| "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, |
| .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
| }, |
| { |
| "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, |
| .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
| }, |
| { |
| "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, |
| .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
| }, |
| { |
| "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, |
| .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
| }, |
| { |
| "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, |
| .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
| }, |
| { |
| "calls: caller stack init to zero or map_value_or_null", |
| .insns = { |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 4), |
| /* fetch map_value_or_null or const_zero from stack */ |
| BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_10, -8), |
| BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), |
| /* store into map_value */ |
| BPF_ST_MEM(BPF_W, BPF_REG_0, 0, 0), |
| BPF_EXIT_INSN(), |
| |
| /* subprog 1 */ |
| /* if (ctx == 0) return; */ |
| BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 8), |
| /* else bpf_map_lookup() and *(fp - 8) = r0 */ |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_2), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), |
| BPF_LD_MAP_FD(BPF_REG_1, 0), |
| BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), |
| /* write map_value_ptr_or_null into stack frame of main prog at fp-8 */ |
| BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| }, |
| .fixup_map_hash_8b = { 13 }, |
| .result = ACCEPT, |
| .prog_type = BPF_PROG_TYPE_XDP, |
| }, |
| { |
| "calls: stack init to zero and pruning", |
| .insns = { |
| /* first make allocated_stack 16 byte */ |
| BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 0), |
| /* now fork the execution such that the false branch |
| * of JGT insn will be verified second and it skisp zero |
| * init of fp-8 stack slot. If stack liveness marking |
| * is missing live_read marks from call map_lookup |
| * processing then pruning will incorrectly assume |
| * that fp-8 stack slot was unused in the fall-through |
| * branch and will accept the program incorrectly |
| */ |
| BPF_JMP_IMM(BPF_JGT, BPF_REG_1, 2, 2), |
| BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), |
| BPF_JMP_IMM(BPF_JA, 0, 0, 0), |
| BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), |
| BPF_LD_MAP_FD(BPF_REG_1, 0), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), |
| BPF_EXIT_INSN(), |
| }, |
| .fixup_map_hash_48b = { 6 }, |
| .errstr = "invalid indirect read from stack off -8+0 size 8", |
| .result = REJECT, |
| .prog_type = BPF_PROG_TYPE_XDP, |
| }, |
| { |
| "calls: ctx read at start of subprog", |
| .insns = { |
| BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 5), |
| BPF_JMP_REG(BPF_JSGT, BPF_REG_0, BPF_REG_0, 0), |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), |
| BPF_EXIT_INSN(), |
| BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_1, 0), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_SOCKET_FILTER, |
| .errstr_unpriv = "function calls to other bpf functions are allowed for root only", |
| .result_unpriv = REJECT, |
| .result = ACCEPT, |
| }, |
| { |
| "calls: cross frame pruning", |
| .insns = { |
| /* r8 = !!random(); |
| * call pruner() |
| * if (r8) |
| * do something bad; |
| */ |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_prandom_u32), |
| BPF_MOV64_IMM(BPF_REG_8, 0), |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), |
| BPF_MOV64_IMM(BPF_REG_8, 1), |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_8), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 4), |
| BPF_JMP_IMM(BPF_JEQ, BPF_REG_8, 1, 1), |
| BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_1, 0), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 0), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_SOCKET_FILTER, |
| .errstr_unpriv = "function calls to other bpf functions are allowed for root only", |
| .errstr = "!read_ok", |
| .result = REJECT, |
| }, |
| { |
| "calls: cross frame pruning - liveness propagation", |
| .insns = { |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_prandom_u32), |
| BPF_MOV64_IMM(BPF_REG_8, 0), |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), |
| BPF_MOV64_IMM(BPF_REG_8, 1), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_prandom_u32), |
| BPF_MOV64_IMM(BPF_REG_9, 0), |
| BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), |
| BPF_MOV64_IMM(BPF_REG_9, 1), |
| BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), |
| BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 4), |
| BPF_JMP_IMM(BPF_JEQ, BPF_REG_8, 1, 1), |
| BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_2, 0), |
| BPF_MOV64_IMM(BPF_REG_0, 0), |
| BPF_EXIT_INSN(), |
| BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 0), |
| BPF_EXIT_INSN(), |
| }, |
| .prog_type = BPF_PROG_TYPE_SOCKET_FILTER, |
| .errstr_unpriv = "function calls to other bpf functions are allowed for root only", |
| .errstr = "!read_ok", |
| .result = REJECT, |
| }, |