diff options
author | Daniel Borkmann <daniel@iogearbox.net> | 2017-05-24 19:05:09 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-05-25 13:44:28 -0400 |
commit | 614d0d77b49a9b131e58b77473698ab5b2c525b7 (patch) | |
tree | 0dc8e1e5384df1cdadfb109bbd191eafe24a594d | |
parent | a316338cb71a3260201490e615f2f6d5c0d8fb2c (diff) |
bpf: add various verifier test cases
This patch adds various verifier test cases:
1) A test case for the pruning issue when tracking alignment
is used.
2) Various PTR_TO_MAP_VALUE_OR_NULL tests to make sure pointer
arithmetic turns such register into UNKNOWN_VALUE type.
3) Test cases for the special treatment of LD_ABS/LD_IND to
make sure verifier doesn't break calling convention here.
Latter is needed, since f.e. arm64 JIT uses r1 - r5 for
storing temporary data, so they really must be marked as
NOT_INIT.
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/filter.h | 10 | ||||
-rw-r--r-- | tools/include/linux/filter.h | 10 | ||||
-rw-r--r-- | tools/testing/selftests/bpf/test_verifier.c | 239 |
3 files changed, 255 insertions, 4 deletions
diff --git a/include/linux/filter.h b/include/linux/filter.h index 56197f82af45..62d948f80730 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h | |||
@@ -272,6 +272,16 @@ struct bpf_prog_aux; | |||
272 | .off = OFF, \ | 272 | .off = OFF, \ |
273 | .imm = IMM }) | 273 | .imm = IMM }) |
274 | 274 | ||
275 | /* Unconditional jumps, goto pc + off16 */ | ||
276 | |||
277 | #define BPF_JMP_A(OFF) \ | ||
278 | ((struct bpf_insn) { \ | ||
279 | .code = BPF_JMP | BPF_JA, \ | ||
280 | .dst_reg = 0, \ | ||
281 | .src_reg = 0, \ | ||
282 | .off = OFF, \ | ||
283 | .imm = 0 }) | ||
284 | |||
275 | /* Function call */ | 285 | /* Function call */ |
276 | 286 | ||
277 | #define BPF_EMIT_CALL(FUNC) \ | 287 | #define BPF_EMIT_CALL(FUNC) \ |
diff --git a/tools/include/linux/filter.h b/tools/include/linux/filter.h index 390d7c9685fd..4ce25d43e8e3 100644 --- a/tools/include/linux/filter.h +++ b/tools/include/linux/filter.h | |||
@@ -208,6 +208,16 @@ | |||
208 | .off = OFF, \ | 208 | .off = OFF, \ |
209 | .imm = IMM }) | 209 | .imm = IMM }) |
210 | 210 | ||
211 | /* Unconditional jumps, goto pc + off16 */ | ||
212 | |||
213 | #define BPF_JMP_A(OFF) \ | ||
214 | ((struct bpf_insn) { \ | ||
215 | .code = BPF_JMP | BPF_JA, \ | ||
216 | .dst_reg = 0, \ | ||
217 | .src_reg = 0, \ | ||
218 | .off = OFF, \ | ||
219 | .imm = 0 }) | ||
220 | |||
211 | /* Function call */ | 221 | /* Function call */ |
212 | 222 | ||
213 | #define BPF_EMIT_CALL(FUNC) \ | 223 | #define BPF_EMIT_CALL(FUNC) \ |
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 3773562056da..cabb19b1e371 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c | |||
@@ -49,6 +49,7 @@ | |||
49 | #define MAX_NR_MAPS 4 | 49 | #define MAX_NR_MAPS 4 |
50 | 50 | ||
51 | #define F_NEEDS_EFFICIENT_UNALIGNED_ACCESS (1 << 0) | 51 | #define F_NEEDS_EFFICIENT_UNALIGNED_ACCESS (1 << 0) |
52 | #define F_LOAD_WITH_STRICT_ALIGNMENT (1 << 1) | ||
52 | 53 | ||
53 | struct bpf_test { | 54 | struct bpf_test { |
54 | const char *descr; | 55 | const char *descr; |
@@ -2615,6 +2616,30 @@ static struct bpf_test tests[] = { | |||
2615 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 2616 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
2616 | }, | 2617 | }, |
2617 | { | 2618 | { |
2619 | "direct packet access: test17 (pruning, alignment)", | ||
2620 | .insns = { | ||
2621 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
2622 | offsetof(struct __sk_buff, data)), | ||
2623 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
2624 | offsetof(struct __sk_buff, data_end)), | ||
2625 | BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_1, | ||
2626 | offsetof(struct __sk_buff, mark)), | ||
2627 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
2628 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 14), | ||
2629 | BPF_JMP_IMM(BPF_JGT, BPF_REG_7, 1, 4), | ||
2630 | BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1), | ||
2631 | BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_0, -4), | ||
2632 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
2633 | BPF_EXIT_INSN(), | ||
2634 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 1), | ||
2635 | BPF_JMP_A(-6), | ||
2636 | }, | ||
2637 | .errstr = "misaligned packet access off 2+15+-4 size 4", | ||
2638 | .result = REJECT, | ||
2639 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
2640 | .flags = F_LOAD_WITH_STRICT_ALIGNMENT, | ||
2641 | }, | ||
2642 | { | ||
2618 | "helper access to packet: test1, valid packet_ptr range", | 2643 | "helper access to packet: test1, valid packet_ptr range", |
2619 | .insns = { | 2644 | .insns = { |
2620 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | 2645 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, |
@@ -3341,6 +3366,70 @@ static struct bpf_test tests[] = { | |||
3341 | .prog_type = BPF_PROG_TYPE_SCHED_CLS | 3366 | .prog_type = BPF_PROG_TYPE_SCHED_CLS |
3342 | }, | 3367 | }, |
3343 | { | 3368 | { |
3369 | "alu ops on ptr_to_map_value_or_null, 1", | ||
3370 | .insns = { | ||
3371 | BPF_MOV64_IMM(BPF_REG_1, 10), | ||
3372 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, -8), | ||
3373 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
3374 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
3375 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
3376 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
3377 | BPF_FUNC_map_lookup_elem), | ||
3378 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_0), | ||
3379 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, -2), | ||
3380 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 2), | ||
3381 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), | ||
3382 | BPF_ST_MEM(BPF_DW, BPF_REG_4, 0, 0), | ||
3383 | BPF_EXIT_INSN(), | ||
3384 | }, | ||
3385 | .fixup_map1 = { 4 }, | ||
3386 | .errstr = "R4 invalid mem access", | ||
3387 | .result = REJECT, | ||
3388 | .prog_type = BPF_PROG_TYPE_SCHED_CLS | ||
3389 | }, | ||
3390 | { | ||
3391 | "alu ops on ptr_to_map_value_or_null, 2", | ||
3392 | .insns = { | ||
3393 | BPF_MOV64_IMM(BPF_REG_1, 10), | ||
3394 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, -8), | ||
3395 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
3396 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
3397 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
3398 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
3399 | BPF_FUNC_map_lookup_elem), | ||
3400 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_0), | ||
3401 | BPF_ALU64_IMM(BPF_AND, BPF_REG_4, -1), | ||
3402 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), | ||
3403 | BPF_ST_MEM(BPF_DW, BPF_REG_4, 0, 0), | ||
3404 | BPF_EXIT_INSN(), | ||
3405 | }, | ||
3406 | .fixup_map1 = { 4 }, | ||
3407 | .errstr = "R4 invalid mem access", | ||
3408 | .result = REJECT, | ||
3409 | .prog_type = BPF_PROG_TYPE_SCHED_CLS | ||
3410 | }, | ||
3411 | { | ||
3412 | "alu ops on ptr_to_map_value_or_null, 3", | ||
3413 | .insns = { | ||
3414 | BPF_MOV64_IMM(BPF_REG_1, 10), | ||
3415 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, -8), | ||
3416 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
3417 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
3418 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
3419 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
3420 | BPF_FUNC_map_lookup_elem), | ||
3421 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_0), | ||
3422 | BPF_ALU64_IMM(BPF_LSH, BPF_REG_4, 1), | ||
3423 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), | ||
3424 | BPF_ST_MEM(BPF_DW, BPF_REG_4, 0, 0), | ||
3425 | BPF_EXIT_INSN(), | ||
3426 | }, | ||
3427 | .fixup_map1 = { 4 }, | ||
3428 | .errstr = "R4 invalid mem access", | ||
3429 | .result = REJECT, | ||
3430 | .prog_type = BPF_PROG_TYPE_SCHED_CLS | ||
3431 | }, | ||
3432 | { | ||
3344 | "invalid memory access with multiple map_lookup_elem calls", | 3433 | "invalid memory access with multiple map_lookup_elem calls", |
3345 | .insns = { | 3434 | .insns = { |
3346 | BPF_MOV64_IMM(BPF_REG_1, 10), | 3435 | BPF_MOV64_IMM(BPF_REG_1, 10), |
@@ -4937,7 +5026,149 @@ static struct bpf_test tests[] = { | |||
4937 | .fixup_map_in_map = { 3 }, | 5026 | .fixup_map_in_map = { 3 }, |
4938 | .errstr = "R1 type=map_value_or_null expected=map_ptr", | 5027 | .errstr = "R1 type=map_value_or_null expected=map_ptr", |
4939 | .result = REJECT, | 5028 | .result = REJECT, |
4940 | } | 5029 | }, |
5030 | { | ||
5031 | "ld_abs: check calling conv, r1", | ||
5032 | .insns = { | ||
5033 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
5034 | BPF_MOV64_IMM(BPF_REG_1, 0), | ||
5035 | BPF_LD_ABS(BPF_W, -0x200000), | ||
5036 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), | ||
5037 | BPF_EXIT_INSN(), | ||
5038 | }, | ||
5039 | .errstr = "R1 !read_ok", | ||
5040 | .result = REJECT, | ||
5041 | }, | ||
5042 | { | ||
5043 | "ld_abs: check calling conv, r2", | ||
5044 | .insns = { | ||
5045 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
5046 | BPF_MOV64_IMM(BPF_REG_2, 0), | ||
5047 | BPF_LD_ABS(BPF_W, -0x200000), | ||
5048 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
5049 | BPF_EXIT_INSN(), | ||
5050 | }, | ||
5051 | .errstr = "R2 !read_ok", | ||
5052 | .result = REJECT, | ||
5053 | }, | ||
5054 | { | ||
5055 | "ld_abs: check calling conv, r3", | ||
5056 | .insns = { | ||
5057 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
5058 | BPF_MOV64_IMM(BPF_REG_3, 0), | ||
5059 | BPF_LD_ABS(BPF_W, -0x200000), | ||
5060 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_3), | ||
5061 | BPF_EXIT_INSN(), | ||
5062 | }, | ||
5063 | .errstr = "R3 !read_ok", | ||
5064 | .result = REJECT, | ||
5065 | }, | ||
5066 | { | ||
5067 | "ld_abs: check calling conv, r4", | ||
5068 | .insns = { | ||
5069 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
5070 | BPF_MOV64_IMM(BPF_REG_4, 0), | ||
5071 | BPF_LD_ABS(BPF_W, -0x200000), | ||
5072 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_4), | ||
5073 | BPF_EXIT_INSN(), | ||
5074 | }, | ||
5075 | .errstr = "R4 !read_ok", | ||
5076 | .result = REJECT, | ||
5077 | }, | ||
5078 | { | ||
5079 | "ld_abs: check calling conv, r5", | ||
5080 | .insns = { | ||
5081 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
5082 | BPF_MOV64_IMM(BPF_REG_5, 0), | ||
5083 | BPF_LD_ABS(BPF_W, -0x200000), | ||
5084 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_5), | ||
5085 | BPF_EXIT_INSN(), | ||
5086 | }, | ||
5087 | .errstr = "R5 !read_ok", | ||
5088 | .result = REJECT, | ||
5089 | }, | ||
5090 | { | ||
5091 | "ld_abs: check calling conv, r7", | ||
5092 | .insns = { | ||
5093 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
5094 | BPF_MOV64_IMM(BPF_REG_7, 0), | ||
5095 | BPF_LD_ABS(BPF_W, -0x200000), | ||
5096 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_7), | ||
5097 | BPF_EXIT_INSN(), | ||
5098 | }, | ||
5099 | .result = ACCEPT, | ||
5100 | }, | ||
5101 | { | ||
5102 | "ld_ind: check calling conv, r1", | ||
5103 | .insns = { | ||
5104 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
5105 | BPF_MOV64_IMM(BPF_REG_1, 1), | ||
5106 | BPF_LD_IND(BPF_W, BPF_REG_1, -0x200000), | ||
5107 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), | ||
5108 | BPF_EXIT_INSN(), | ||
5109 | }, | ||
5110 | .errstr = "R1 !read_ok", | ||
5111 | .result = REJECT, | ||
5112 | }, | ||
5113 | { | ||
5114 | "ld_ind: check calling conv, r2", | ||
5115 | .insns = { | ||
5116 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
5117 | BPF_MOV64_IMM(BPF_REG_2, 1), | ||
5118 | BPF_LD_IND(BPF_W, BPF_REG_2, -0x200000), | ||
5119 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
5120 | BPF_EXIT_INSN(), | ||
5121 | }, | ||
5122 | .errstr = "R2 !read_ok", | ||
5123 | .result = REJECT, | ||
5124 | }, | ||
5125 | { | ||
5126 | "ld_ind: check calling conv, r3", | ||
5127 | .insns = { | ||
5128 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
5129 | BPF_MOV64_IMM(BPF_REG_3, 1), | ||
5130 | BPF_LD_IND(BPF_W, BPF_REG_3, -0x200000), | ||
5131 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_3), | ||
5132 | BPF_EXIT_INSN(), | ||
5133 | }, | ||
5134 | .errstr = "R3 !read_ok", | ||
5135 | .result = REJECT, | ||
5136 | }, | ||
5137 | { | ||
5138 | "ld_ind: check calling conv, r4", | ||
5139 | .insns = { | ||
5140 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
5141 | BPF_MOV64_IMM(BPF_REG_4, 1), | ||
5142 | BPF_LD_IND(BPF_W, BPF_REG_4, -0x200000), | ||
5143 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_4), | ||
5144 | BPF_EXIT_INSN(), | ||
5145 | }, | ||
5146 | .errstr = "R4 !read_ok", | ||
5147 | .result = REJECT, | ||
5148 | }, | ||
5149 | { | ||
5150 | "ld_ind: check calling conv, r5", | ||
5151 | .insns = { | ||
5152 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
5153 | BPF_MOV64_IMM(BPF_REG_5, 1), | ||
5154 | BPF_LD_IND(BPF_W, BPF_REG_5, -0x200000), | ||
5155 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_5), | ||
5156 | BPF_EXIT_INSN(), | ||
5157 | }, | ||
5158 | .errstr = "R5 !read_ok", | ||
5159 | .result = REJECT, | ||
5160 | }, | ||
5161 | { | ||
5162 | "ld_ind: check calling conv, r7", | ||
5163 | .insns = { | ||
5164 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
5165 | BPF_MOV64_IMM(BPF_REG_7, 1), | ||
5166 | BPF_LD_IND(BPF_W, BPF_REG_7, -0x200000), | ||
5167 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_7), | ||
5168 | BPF_EXIT_INSN(), | ||
5169 | }, | ||
5170 | .result = ACCEPT, | ||
5171 | }, | ||
4941 | }; | 5172 | }; |
4942 | 5173 | ||
4943 | static int probe_filter_length(const struct bpf_insn *fp) | 5174 | static int probe_filter_length(const struct bpf_insn *fp) |
@@ -5059,9 +5290,9 @@ static void do_test_single(struct bpf_test *test, bool unpriv, | |||
5059 | 5290 | ||
5060 | do_test_fixup(test, prog, map_fds); | 5291 | do_test_fixup(test, prog, map_fds); |
5061 | 5292 | ||
5062 | fd_prog = bpf_load_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER, | 5293 | fd_prog = bpf_verify_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER, |
5063 | prog, prog_len, "GPL", 0, bpf_vlog, | 5294 | prog, prog_len, test->flags & F_LOAD_WITH_STRICT_ALIGNMENT, |
5064 | sizeof(bpf_vlog)); | 5295 | "GPL", 0, bpf_vlog, sizeof(bpf_vlog)); |
5065 | 5296 | ||
5066 | expected_ret = unpriv && test->result_unpriv != UNDEF ? | 5297 | expected_ret = unpriv && test->result_unpriv != UNDEF ? |
5067 | test->result_unpriv : test->result; | 5298 | test->result_unpriv : test->result; |