Loading lib/test_bpf.c +6 −2 Original line number Diff line number Diff line Loading @@ -2003,10 +2003,14 @@ static struct bpf_test tests[] = { { { 4, 0 }, { 5, 10 } } }, { "INT: DIV by zero", /* This one doesn't go through verifier, but is just raw insn * as opposed to cBPF tests from here. Thus div by 0 tests are * done in test_verifier in BPF kselftests. */ "INT: DIV by -1", .u.insns_int = { BPF_ALU64_REG(BPF_MOV, R6, R1), BPF_ALU64_IMM(BPF_MOV, R7, 0), BPF_ALU64_IMM(BPF_MOV, R7, -1), BPF_LD_ABS(BPF_B, 3), BPF_ALU32_REG(BPF_DIV, R0, R7), BPF_EXIT_INSN(), Loading tools/testing/selftests/bpf/test_verifier.c +330 −13 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <stddef.h> #include <stdbool.h> #include <sched.h> #include <limits.h> #include <sys/capability.h> #include <sys/resource.h> Loading Loading @@ -111,7 +112,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .result = ACCEPT, .retval = 0, .retval = 42, }, { "DIV32 by 0, zero check 2", Loading @@ -123,7 +124,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .result = ACCEPT, .retval = 0, .retval = 42, }, { "DIV64 by 0, zero check", Loading @@ -135,7 +136,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .result = ACCEPT, .retval = 0, .retval = 42, }, { "MOD32 by 0, zero check 1", Loading @@ -147,7 +148,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .result = ACCEPT, .retval = 0, .retval = 42, }, { "MOD32 by 0, zero check 2", Loading @@ -159,7 +160,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .result = ACCEPT, .retval = 0, .retval = 42, }, { "MOD64 by 0, zero check", Loading @@ -171,13 +172,245 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .result = ACCEPT, .retval = 42, }, { "DIV32 by 0, zero check ok, cls", .insns = { BPF_MOV32_IMM(BPF_REG_0, 42), BPF_MOV32_IMM(BPF_REG_1, 2), BPF_MOV32_IMM(BPF_REG_2, 16), BPF_ALU32_REG(BPF_DIV, BPF_REG_2, BPF_REG_1), BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 8, }, { "DIV32 by 0, zero check 1, cls", .insns = { BPF_MOV32_IMM(BPF_REG_1, 0), BPF_MOV32_IMM(BPF_REG_0, 1), BPF_ALU32_REG(BPF_DIV, BPF_REG_0, BPF_REG_1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 0, }, { "DIV32 by 0, zero check 2, cls", .insns = { BPF_LD_IMM64(BPF_REG_1, 0xffffffff00000000LL), BPF_MOV32_IMM(BPF_REG_0, 1), BPF_ALU32_REG(BPF_DIV, BPF_REG_0, BPF_REG_1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 0, }, { "DIV64 by 0, zero check, cls", .insns = { BPF_MOV32_IMM(BPF_REG_1, 0), BPF_MOV32_IMM(BPF_REG_0, 1), BPF_ALU64_REG(BPF_DIV, BPF_REG_0, BPF_REG_1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 0, }, { "MOD32 by 0, zero check ok, cls", .insns = { BPF_MOV32_IMM(BPF_REG_0, 42), BPF_MOV32_IMM(BPF_REG_1, 3), BPF_MOV32_IMM(BPF_REG_2, 5), BPF_ALU32_REG(BPF_MOD, BPF_REG_2, BPF_REG_1), BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 2, }, { "MOD32 by 0, zero check 1, cls", .insns = { BPF_MOV32_IMM(BPF_REG_1, 0), BPF_MOV32_IMM(BPF_REG_0, 1), BPF_ALU32_REG(BPF_MOD, BPF_REG_0, BPF_REG_1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 1, }, { "MOD32 by 0, zero check 2, cls", .insns = { BPF_LD_IMM64(BPF_REG_1, 0xffffffff00000000LL), BPF_MOV32_IMM(BPF_REG_0, 1), BPF_ALU32_REG(BPF_MOD, BPF_REG_0, BPF_REG_1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 1, }, { "MOD64 by 0, zero check 1, cls", .insns = { BPF_MOV32_IMM(BPF_REG_1, 0), BPF_MOV32_IMM(BPF_REG_0, 2), BPF_ALU64_REG(BPF_MOD, BPF_REG_0, BPF_REG_1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 2, }, { "MOD64 by 0, zero check 2, cls", .insns = { BPF_MOV32_IMM(BPF_REG_1, 0), BPF_MOV32_IMM(BPF_REG_0, -1), BPF_ALU64_REG(BPF_MOD, BPF_REG_0, BPF_REG_1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = -1, }, /* Just make sure that JITs used udiv/umod as otherwise we get * an exception from INT_MIN/-1 overflow similarly as with div * by zero. */ { "DIV32 overflow, check 1", .insns = { BPF_MOV32_IMM(BPF_REG_1, -1), BPF_MOV32_IMM(BPF_REG_0, INT_MIN), BPF_ALU32_REG(BPF_DIV, BPF_REG_0, BPF_REG_1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 0, }, { "DIV32 overflow, check 2", .insns = { BPF_MOV32_IMM(BPF_REG_0, INT_MIN), BPF_ALU32_IMM(BPF_DIV, BPF_REG_0, -1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 0, }, { "DIV64 overflow, check 1", .insns = { BPF_MOV64_IMM(BPF_REG_1, -1), BPF_LD_IMM64(BPF_REG_0, LLONG_MIN), BPF_ALU64_REG(BPF_DIV, BPF_REG_0, BPF_REG_1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 0, }, { "DIV64 overflow, check 2", .insns = { BPF_LD_IMM64(BPF_REG_0, LLONG_MIN), BPF_ALU64_IMM(BPF_DIV, BPF_REG_0, -1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 0, }, { "MOD32 overflow, check 1", .insns = { BPF_MOV32_IMM(BPF_REG_1, -1), BPF_MOV32_IMM(BPF_REG_0, INT_MIN), BPF_ALU32_REG(BPF_MOD, BPF_REG_0, BPF_REG_1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = INT_MIN, }, { "MOD32 overflow, check 2", .insns = { BPF_MOV32_IMM(BPF_REG_0, INT_MIN), BPF_ALU32_IMM(BPF_MOD, BPF_REG_0, -1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = INT_MIN, }, { "MOD64 overflow, check 1", .insns = { BPF_MOV64_IMM(BPF_REG_1, -1), BPF_LD_IMM64(BPF_REG_2, LLONG_MIN), BPF_MOV64_REG(BPF_REG_3, BPF_REG_2), BPF_ALU64_REG(BPF_MOD, BPF_REG_2, BPF_REG_1), BPF_MOV32_IMM(BPF_REG_0, 0), BPF_JMP_REG(BPF_JNE, BPF_REG_3, BPF_REG_2, 1), BPF_MOV32_IMM(BPF_REG_0, 1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 1, }, { "MOD64 overflow, check 2", .insns = { BPF_LD_IMM64(BPF_REG_2, LLONG_MIN), BPF_MOV64_REG(BPF_REG_3, BPF_REG_2), BPF_ALU64_IMM(BPF_MOD, BPF_REG_2, -1), BPF_MOV32_IMM(BPF_REG_0, 0), BPF_JMP_REG(BPF_JNE, BPF_REG_3, BPF_REG_2, 1), BPF_MOV32_IMM(BPF_REG_0, 1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 1, }, { "xor32 zero extend check", .insns = { BPF_MOV32_IMM(BPF_REG_2, -1), BPF_ALU64_IMM(BPF_LSH, BPF_REG_2, 32), BPF_ALU64_IMM(BPF_OR, BPF_REG_2, 0xffff), BPF_ALU32_REG(BPF_XOR, BPF_REG_2, BPF_REG_2), BPF_MOV32_IMM(BPF_REG_0, 2), BPF_JMP_IMM(BPF_JNE, BPF_REG_2, 0, 1), BPF_MOV32_IMM(BPF_REG_0, 1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 1, }, { "empty prog", .insns = { }, .errstr = "last insn is not an exit or jmp", .errstr = "unknown opcode 00", .result = REJECT, }, { Loading Loading @@ -374,7 +607,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .result = REJECT, .errstr = "BPF_ARSH not supported for 32 bit ALU", .errstr = "unknown opcode c4", }, { "arsh32 on reg", Loading @@ -385,7 +618,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .result = REJECT, .errstr = "BPF_ARSH not supported for 32 bit ALU", .errstr = "unknown opcode cc", }, { "arsh64 on imm", Loading Loading @@ -501,7 +734,7 @@ static struct bpf_test tests[] = { BPF_RAW_INSN(BPF_JMP | BPF_CALL | BPF_X, 0, 0, 0, 0), BPF_EXIT_INSN(), }, .errstr = "BPF_CALL uses reserved", .errstr = "unknown opcode 8d", .result = REJECT, }, { Loading Loading @@ -691,7 +924,7 @@ static struct bpf_test tests[] = { BPF_RAW_INSN(0, 0, 0, 0, 0), BPF_EXIT_INSN(), }, .errstr = "invalid BPF_LD_IMM", .errstr = "unknown opcode 00", .result = REJECT, }, { Loading @@ -709,7 +942,7 @@ static struct bpf_test tests[] = { BPF_RAW_INSN(-1, 0, 0, 0, 0), BPF_EXIT_INSN(), }, .errstr = "invalid BPF_ALU opcode f0", .errstr = "unknown opcode ff", .result = REJECT, }, { Loading @@ -718,7 +951,7 @@ static struct bpf_test tests[] = { BPF_RAW_INSN(-1, -1, -1, -1, -1), BPF_EXIT_INSN(), }, .errstr = "invalid BPF_ALU opcode f0", .errstr = "unknown opcode ff", .result = REJECT, }, { Loading Loading @@ -7543,7 +7776,7 @@ static struct bpf_test tests[] = { }, BPF_EXIT_INSN(), }, .errstr = "BPF_END uses reserved fields", .errstr = "unknown opcode d7", .result = REJECT, }, { Loading Loading @@ -8963,6 +9196,90 @@ static struct bpf_test tests[] = { .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_map1 = { 16 }, .result = REJECT, .errstr = "R0 min value is outside of the array range", }, { "calls: overlapping caller/callee", .insns = { Loading Loading
lib/test_bpf.c +6 −2 Original line number Diff line number Diff line Loading @@ -2003,10 +2003,14 @@ static struct bpf_test tests[] = { { { 4, 0 }, { 5, 10 } } }, { "INT: DIV by zero", /* This one doesn't go through verifier, but is just raw insn * as opposed to cBPF tests from here. Thus div by 0 tests are * done in test_verifier in BPF kselftests. */ "INT: DIV by -1", .u.insns_int = { BPF_ALU64_REG(BPF_MOV, R6, R1), BPF_ALU64_IMM(BPF_MOV, R7, 0), BPF_ALU64_IMM(BPF_MOV, R7, -1), BPF_LD_ABS(BPF_B, 3), BPF_ALU32_REG(BPF_DIV, R0, R7), BPF_EXIT_INSN(), Loading
tools/testing/selftests/bpf/test_verifier.c +330 −13 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <stddef.h> #include <stdbool.h> #include <sched.h> #include <limits.h> #include <sys/capability.h> #include <sys/resource.h> Loading Loading @@ -111,7 +112,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .result = ACCEPT, .retval = 0, .retval = 42, }, { "DIV32 by 0, zero check 2", Loading @@ -123,7 +124,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .result = ACCEPT, .retval = 0, .retval = 42, }, { "DIV64 by 0, zero check", Loading @@ -135,7 +136,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .result = ACCEPT, .retval = 0, .retval = 42, }, { "MOD32 by 0, zero check 1", Loading @@ -147,7 +148,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .result = ACCEPT, .retval = 0, .retval = 42, }, { "MOD32 by 0, zero check 2", Loading @@ -159,7 +160,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .result = ACCEPT, .retval = 0, .retval = 42, }, { "MOD64 by 0, zero check", Loading @@ -171,13 +172,245 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .result = ACCEPT, .retval = 42, }, { "DIV32 by 0, zero check ok, cls", .insns = { BPF_MOV32_IMM(BPF_REG_0, 42), BPF_MOV32_IMM(BPF_REG_1, 2), BPF_MOV32_IMM(BPF_REG_2, 16), BPF_ALU32_REG(BPF_DIV, BPF_REG_2, BPF_REG_1), BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 8, }, { "DIV32 by 0, zero check 1, cls", .insns = { BPF_MOV32_IMM(BPF_REG_1, 0), BPF_MOV32_IMM(BPF_REG_0, 1), BPF_ALU32_REG(BPF_DIV, BPF_REG_0, BPF_REG_1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 0, }, { "DIV32 by 0, zero check 2, cls", .insns = { BPF_LD_IMM64(BPF_REG_1, 0xffffffff00000000LL), BPF_MOV32_IMM(BPF_REG_0, 1), BPF_ALU32_REG(BPF_DIV, BPF_REG_0, BPF_REG_1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 0, }, { "DIV64 by 0, zero check, cls", .insns = { BPF_MOV32_IMM(BPF_REG_1, 0), BPF_MOV32_IMM(BPF_REG_0, 1), BPF_ALU64_REG(BPF_DIV, BPF_REG_0, BPF_REG_1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 0, }, { "MOD32 by 0, zero check ok, cls", .insns = { BPF_MOV32_IMM(BPF_REG_0, 42), BPF_MOV32_IMM(BPF_REG_1, 3), BPF_MOV32_IMM(BPF_REG_2, 5), BPF_ALU32_REG(BPF_MOD, BPF_REG_2, BPF_REG_1), BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 2, }, { "MOD32 by 0, zero check 1, cls", .insns = { BPF_MOV32_IMM(BPF_REG_1, 0), BPF_MOV32_IMM(BPF_REG_0, 1), BPF_ALU32_REG(BPF_MOD, BPF_REG_0, BPF_REG_1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 1, }, { "MOD32 by 0, zero check 2, cls", .insns = { BPF_LD_IMM64(BPF_REG_1, 0xffffffff00000000LL), BPF_MOV32_IMM(BPF_REG_0, 1), BPF_ALU32_REG(BPF_MOD, BPF_REG_0, BPF_REG_1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 1, }, { "MOD64 by 0, zero check 1, cls", .insns = { BPF_MOV32_IMM(BPF_REG_1, 0), BPF_MOV32_IMM(BPF_REG_0, 2), BPF_ALU64_REG(BPF_MOD, BPF_REG_0, BPF_REG_1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 2, }, { "MOD64 by 0, zero check 2, cls", .insns = { BPF_MOV32_IMM(BPF_REG_1, 0), BPF_MOV32_IMM(BPF_REG_0, -1), BPF_ALU64_REG(BPF_MOD, BPF_REG_0, BPF_REG_1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = -1, }, /* Just make sure that JITs used udiv/umod as otherwise we get * an exception from INT_MIN/-1 overflow similarly as with div * by zero. */ { "DIV32 overflow, check 1", .insns = { BPF_MOV32_IMM(BPF_REG_1, -1), BPF_MOV32_IMM(BPF_REG_0, INT_MIN), BPF_ALU32_REG(BPF_DIV, BPF_REG_0, BPF_REG_1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 0, }, { "DIV32 overflow, check 2", .insns = { BPF_MOV32_IMM(BPF_REG_0, INT_MIN), BPF_ALU32_IMM(BPF_DIV, BPF_REG_0, -1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 0, }, { "DIV64 overflow, check 1", .insns = { BPF_MOV64_IMM(BPF_REG_1, -1), BPF_LD_IMM64(BPF_REG_0, LLONG_MIN), BPF_ALU64_REG(BPF_DIV, BPF_REG_0, BPF_REG_1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 0, }, { "DIV64 overflow, check 2", .insns = { BPF_LD_IMM64(BPF_REG_0, LLONG_MIN), BPF_ALU64_IMM(BPF_DIV, BPF_REG_0, -1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 0, }, { "MOD32 overflow, check 1", .insns = { BPF_MOV32_IMM(BPF_REG_1, -1), BPF_MOV32_IMM(BPF_REG_0, INT_MIN), BPF_ALU32_REG(BPF_MOD, BPF_REG_0, BPF_REG_1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = INT_MIN, }, { "MOD32 overflow, check 2", .insns = { BPF_MOV32_IMM(BPF_REG_0, INT_MIN), BPF_ALU32_IMM(BPF_MOD, BPF_REG_0, -1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = INT_MIN, }, { "MOD64 overflow, check 1", .insns = { BPF_MOV64_IMM(BPF_REG_1, -1), BPF_LD_IMM64(BPF_REG_2, LLONG_MIN), BPF_MOV64_REG(BPF_REG_3, BPF_REG_2), BPF_ALU64_REG(BPF_MOD, BPF_REG_2, BPF_REG_1), BPF_MOV32_IMM(BPF_REG_0, 0), BPF_JMP_REG(BPF_JNE, BPF_REG_3, BPF_REG_2, 1), BPF_MOV32_IMM(BPF_REG_0, 1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 1, }, { "MOD64 overflow, check 2", .insns = { BPF_LD_IMM64(BPF_REG_2, LLONG_MIN), BPF_MOV64_REG(BPF_REG_3, BPF_REG_2), BPF_ALU64_IMM(BPF_MOD, BPF_REG_2, -1), BPF_MOV32_IMM(BPF_REG_0, 0), BPF_JMP_REG(BPF_JNE, BPF_REG_3, BPF_REG_2, 1), BPF_MOV32_IMM(BPF_REG_0, 1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 1, }, { "xor32 zero extend check", .insns = { BPF_MOV32_IMM(BPF_REG_2, -1), BPF_ALU64_IMM(BPF_LSH, BPF_REG_2, 32), BPF_ALU64_IMM(BPF_OR, BPF_REG_2, 0xffff), BPF_ALU32_REG(BPF_XOR, BPF_REG_2, BPF_REG_2), BPF_MOV32_IMM(BPF_REG_0, 2), BPF_JMP_IMM(BPF_JNE, BPF_REG_2, 0, 1), BPF_MOV32_IMM(BPF_REG_0, 1), BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, .retval = 1, }, { "empty prog", .insns = { }, .errstr = "last insn is not an exit or jmp", .errstr = "unknown opcode 00", .result = REJECT, }, { Loading Loading @@ -374,7 +607,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .result = REJECT, .errstr = "BPF_ARSH not supported for 32 bit ALU", .errstr = "unknown opcode c4", }, { "arsh32 on reg", Loading @@ -385,7 +618,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .result = REJECT, .errstr = "BPF_ARSH not supported for 32 bit ALU", .errstr = "unknown opcode cc", }, { "arsh64 on imm", Loading Loading @@ -501,7 +734,7 @@ static struct bpf_test tests[] = { BPF_RAW_INSN(BPF_JMP | BPF_CALL | BPF_X, 0, 0, 0, 0), BPF_EXIT_INSN(), }, .errstr = "BPF_CALL uses reserved", .errstr = "unknown opcode 8d", .result = REJECT, }, { Loading Loading @@ -691,7 +924,7 @@ static struct bpf_test tests[] = { BPF_RAW_INSN(0, 0, 0, 0, 0), BPF_EXIT_INSN(), }, .errstr = "invalid BPF_LD_IMM", .errstr = "unknown opcode 00", .result = REJECT, }, { Loading @@ -709,7 +942,7 @@ static struct bpf_test tests[] = { BPF_RAW_INSN(-1, 0, 0, 0, 0), BPF_EXIT_INSN(), }, .errstr = "invalid BPF_ALU opcode f0", .errstr = "unknown opcode ff", .result = REJECT, }, { Loading @@ -718,7 +951,7 @@ static struct bpf_test tests[] = { BPF_RAW_INSN(-1, -1, -1, -1, -1), BPF_EXIT_INSN(), }, .errstr = "invalid BPF_ALU opcode f0", .errstr = "unknown opcode ff", .result = REJECT, }, { Loading Loading @@ -7543,7 +7776,7 @@ static struct bpf_test tests[] = { }, BPF_EXIT_INSN(), }, .errstr = "BPF_END uses reserved fields", .errstr = "unknown opcode d7", .result = REJECT, }, { Loading Loading @@ -8963,6 +9196,90 @@ static struct bpf_test tests[] = { .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_map1 = { 16 }, .result = REJECT, .errstr = "R0 min value is outside of the array range", }, { "calls: overlapping caller/callee", .insns = { Loading