aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Borkmann <daniel@iogearbox.net>2017-05-24 19:05:09 -0400
committerDavid S. Miller <davem@davemloft.net>2017-05-25 13:44:28 -0400
commit614d0d77b49a9b131e58b77473698ab5b2c525b7 (patch)
tree0dc8e1e5384df1cdadfb109bbd191eafe24a594d
parenta316338cb71a3260201490e615f2f6d5c0d8fb2c (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.h10
-rw-r--r--tools/include/linux/filter.h10
-rw-r--r--tools/testing/selftests/bpf/test_verifier.c239
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
53struct bpf_test { 54struct 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
4943static int probe_filter_length(const struct bpf_insn *fp) 5174static 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;