diff options
Diffstat (limited to 'kernel/bpf/verifier.c')
-rw-r--r-- | kernel/bpf/verifier.c | 82 |
1 files changed, 64 insertions, 18 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 545b8c45a578..d906775e12c1 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
@@ -1006,7 +1006,13 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn | |||
1006 | /* ctx accesses must be at a fixed offset, so that we can | 1006 | /* ctx accesses must be at a fixed offset, so that we can |
1007 | * determine what type of data were returned. | 1007 | * determine what type of data were returned. |
1008 | */ | 1008 | */ |
1009 | if (!tnum_is_const(reg->var_off)) { | 1009 | if (reg->off) { |
1010 | verbose(env, | ||
1011 | "dereference of modified ctx ptr R%d off=%d+%d, ctx+const is allowed, ctx+const+const is not\n", | ||
1012 | regno, reg->off, off - reg->off); | ||
1013 | return -EACCES; | ||
1014 | } | ||
1015 | if (!tnum_is_const(reg->var_off) || reg->var_off.value) { | ||
1010 | char tn_buf[48]; | 1016 | char tn_buf[48]; |
1011 | 1017 | ||
1012 | tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off); | 1018 | tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off); |
@@ -1015,7 +1021,6 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn | |||
1015 | tn_buf, off, size); | 1021 | tn_buf, off, size); |
1016 | return -EACCES; | 1022 | return -EACCES; |
1017 | } | 1023 | } |
1018 | off += reg->var_off.value; | ||
1019 | err = check_ctx_access(env, insn_idx, off, size, t, ®_type); | 1024 | err = check_ctx_access(env, insn_idx, off, size, t, ®_type); |
1020 | if (!err && t == BPF_READ && value_regno >= 0) { | 1025 | if (!err && t == BPF_READ && value_regno >= 0) { |
1021 | /* ctx access returns either a scalar, or a | 1026 | /* ctx access returns either a scalar, or a |
@@ -2341,12 +2346,15 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn) | |||
2341 | 2346 | ||
2342 | static void find_good_pkt_pointers(struct bpf_verifier_state *state, | 2347 | static void find_good_pkt_pointers(struct bpf_verifier_state *state, |
2343 | struct bpf_reg_state *dst_reg, | 2348 | struct bpf_reg_state *dst_reg, |
2344 | enum bpf_reg_type type) | 2349 | enum bpf_reg_type type, |
2350 | bool range_right_open) | ||
2345 | { | 2351 | { |
2346 | struct bpf_reg_state *regs = state->regs, *reg; | 2352 | struct bpf_reg_state *regs = state->regs, *reg; |
2353 | u16 new_range; | ||
2347 | int i; | 2354 | int i; |
2348 | 2355 | ||
2349 | if (dst_reg->off < 0) | 2356 | if (dst_reg->off < 0 || |
2357 | (dst_reg->off == 0 && range_right_open)) | ||
2350 | /* This doesn't give us any range */ | 2358 | /* This doesn't give us any range */ |
2351 | return; | 2359 | return; |
2352 | 2360 | ||
@@ -2357,9 +2365,13 @@ static void find_good_pkt_pointers(struct bpf_verifier_state *state, | |||
2357 | */ | 2365 | */ |
2358 | return; | 2366 | return; |
2359 | 2367 | ||
2360 | /* LLVM can generate four kind of checks: | 2368 | new_range = dst_reg->off; |
2369 | if (range_right_open) | ||
2370 | new_range--; | ||
2371 | |||
2372 | /* Examples for register markings: | ||
2361 | * | 2373 | * |
2362 | * Type 1/2: | 2374 | * pkt_data in dst register: |
2363 | * | 2375 | * |
2364 | * r2 = r3; | 2376 | * r2 = r3; |
2365 | * r2 += 8; | 2377 | * r2 += 8; |
@@ -2376,7 +2388,7 @@ static void find_good_pkt_pointers(struct bpf_verifier_state *state, | |||
2376 | * r2=pkt(id=n,off=8,r=0) | 2388 | * r2=pkt(id=n,off=8,r=0) |
2377 | * r3=pkt(id=n,off=0,r=0) | 2389 | * r3=pkt(id=n,off=0,r=0) |
2378 | * | 2390 | * |
2379 | * Type 3/4: | 2391 | * pkt_data in src register: |
2380 | * | 2392 | * |
2381 | * r2 = r3; | 2393 | * r2 = r3; |
2382 | * r2 += 8; | 2394 | * r2 += 8; |
@@ -2394,7 +2406,9 @@ static void find_good_pkt_pointers(struct bpf_verifier_state *state, | |||
2394 | * r3=pkt(id=n,off=0,r=0) | 2406 | * r3=pkt(id=n,off=0,r=0) |
2395 | * | 2407 | * |
2396 | * Find register r3 and mark its range as r3=pkt(id=n,off=0,r=8) | 2408 | * Find register r3 and mark its range as r3=pkt(id=n,off=0,r=8) |
2397 | * so that range of bytes [r3, r3 + 8) is safe to access. | 2409 | * or r3=pkt(id=n,off=0,r=8-1), so that range of bytes [r3, r3 + 8) |
2410 | * and [r3, r3 + 8-1) respectively is safe to access depending on | ||
2411 | * the check. | ||
2398 | */ | 2412 | */ |
2399 | 2413 | ||
2400 | /* If our ids match, then we must have the same max_value. And we | 2414 | /* If our ids match, then we must have the same max_value. And we |
@@ -2405,14 +2419,14 @@ static void find_good_pkt_pointers(struct bpf_verifier_state *state, | |||
2405 | for (i = 0; i < MAX_BPF_REG; i++) | 2419 | for (i = 0; i < MAX_BPF_REG; i++) |
2406 | if (regs[i].type == type && regs[i].id == dst_reg->id) | 2420 | if (regs[i].type == type && regs[i].id == dst_reg->id) |
2407 | /* keep the maximum range already checked */ | 2421 | /* keep the maximum range already checked */ |
2408 | regs[i].range = max_t(u16, regs[i].range, dst_reg->off); | 2422 | regs[i].range = max(regs[i].range, new_range); |
2409 | 2423 | ||
2410 | for (i = 0; i < MAX_BPF_STACK; i += BPF_REG_SIZE) { | 2424 | for (i = 0; i < MAX_BPF_STACK; i += BPF_REG_SIZE) { |
2411 | if (state->stack_slot_type[i] != STACK_SPILL) | 2425 | if (state->stack_slot_type[i] != STACK_SPILL) |
2412 | continue; | 2426 | continue; |
2413 | reg = &state->spilled_regs[i / BPF_REG_SIZE]; | 2427 | reg = &state->spilled_regs[i / BPF_REG_SIZE]; |
2414 | if (reg->type == type && reg->id == dst_reg->id) | 2428 | if (reg->type == type && reg->id == dst_reg->id) |
2415 | reg->range = max_t(u16, reg->range, dst_reg->off); | 2429 | reg->range = max_t(u16, reg->range, new_range); |
2416 | } | 2430 | } |
2417 | } | 2431 | } |
2418 | 2432 | ||
@@ -2776,39 +2790,71 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, | |||
2776 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGT && | 2790 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGT && |
2777 | dst_reg->type == PTR_TO_PACKET && | 2791 | dst_reg->type == PTR_TO_PACKET && |
2778 | regs[insn->src_reg].type == PTR_TO_PACKET_END) { | 2792 | regs[insn->src_reg].type == PTR_TO_PACKET_END) { |
2779 | find_good_pkt_pointers(this_branch, dst_reg, PTR_TO_PACKET); | 2793 | /* pkt_data' > pkt_end */ |
2794 | find_good_pkt_pointers(this_branch, dst_reg, | ||
2795 | PTR_TO_PACKET, false); | ||
2796 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGT && | ||
2797 | dst_reg->type == PTR_TO_PACKET_END && | ||
2798 | regs[insn->src_reg].type == PTR_TO_PACKET) { | ||
2799 | /* pkt_end > pkt_data' */ | ||
2800 | find_good_pkt_pointers(other_branch, ®s[insn->src_reg], | ||
2801 | PTR_TO_PACKET, true); | ||
2802 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JLT && | ||
2803 | dst_reg->type == PTR_TO_PACKET && | ||
2804 | regs[insn->src_reg].type == PTR_TO_PACKET_END) { | ||
2805 | /* pkt_data' < pkt_end */ | ||
2806 | find_good_pkt_pointers(other_branch, dst_reg, PTR_TO_PACKET, | ||
2807 | true); | ||
2780 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JLT && | 2808 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JLT && |
2809 | dst_reg->type == PTR_TO_PACKET_END && | ||
2810 | regs[insn->src_reg].type == PTR_TO_PACKET) { | ||
2811 | /* pkt_end < pkt_data' */ | ||
2812 | find_good_pkt_pointers(this_branch, ®s[insn->src_reg], | ||
2813 | PTR_TO_PACKET, false); | ||
2814 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGE && | ||
2781 | dst_reg->type == PTR_TO_PACKET && | 2815 | dst_reg->type == PTR_TO_PACKET && |
2782 | regs[insn->src_reg].type == PTR_TO_PACKET_END) { | 2816 | regs[insn->src_reg].type == PTR_TO_PACKET_END) { |
2783 | find_good_pkt_pointers(other_branch, dst_reg, PTR_TO_PACKET); | 2817 | /* pkt_data' >= pkt_end */ |
2818 | find_good_pkt_pointers(this_branch, dst_reg, | ||
2819 | PTR_TO_PACKET, true); | ||
2784 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGE && | 2820 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGE && |
2785 | dst_reg->type == PTR_TO_PACKET_END && | 2821 | dst_reg->type == PTR_TO_PACKET_END && |
2786 | regs[insn->src_reg].type == PTR_TO_PACKET) { | 2822 | regs[insn->src_reg].type == PTR_TO_PACKET) { |
2823 | /* pkt_end >= pkt_data' */ | ||
2787 | find_good_pkt_pointers(other_branch, ®s[insn->src_reg], | 2824 | find_good_pkt_pointers(other_branch, ®s[insn->src_reg], |
2788 | PTR_TO_PACKET); | 2825 | PTR_TO_PACKET, false); |
2826 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JLE && | ||
2827 | dst_reg->type == PTR_TO_PACKET && | ||
2828 | regs[insn->src_reg].type == PTR_TO_PACKET_END) { | ||
2829 | /* pkt_data' <= pkt_end */ | ||
2830 | find_good_pkt_pointers(other_branch, dst_reg, | ||
2831 | PTR_TO_PACKET, false); | ||
2789 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JLE && | 2832 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JLE && |
2790 | dst_reg->type == PTR_TO_PACKET_END && | 2833 | dst_reg->type == PTR_TO_PACKET_END && |
2791 | regs[insn->src_reg].type == PTR_TO_PACKET) { | 2834 | regs[insn->src_reg].type == PTR_TO_PACKET) { |
2835 | /* pkt_end <= pkt_data' */ | ||
2792 | find_good_pkt_pointers(this_branch, ®s[insn->src_reg], | 2836 | find_good_pkt_pointers(this_branch, ®s[insn->src_reg], |
2793 | PTR_TO_PACKET); | 2837 | PTR_TO_PACKET, true); |
2794 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGT && | 2838 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGT && |
2795 | dst_reg->type == PTR_TO_PACKET_META && | 2839 | dst_reg->type == PTR_TO_PACKET_META && |
2796 | reg_is_init_pkt_pointer(®s[insn->src_reg], PTR_TO_PACKET)) { | 2840 | reg_is_init_pkt_pointer(®s[insn->src_reg], PTR_TO_PACKET)) { |
2797 | find_good_pkt_pointers(this_branch, dst_reg, PTR_TO_PACKET_META); | 2841 | find_good_pkt_pointers(this_branch, dst_reg, |
2842 | PTR_TO_PACKET_META, false); | ||
2798 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JLT && | 2843 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JLT && |
2799 | dst_reg->type == PTR_TO_PACKET_META && | 2844 | dst_reg->type == PTR_TO_PACKET_META && |
2800 | reg_is_init_pkt_pointer(®s[insn->src_reg], PTR_TO_PACKET)) { | 2845 | reg_is_init_pkt_pointer(®s[insn->src_reg], PTR_TO_PACKET)) { |
2801 | find_good_pkt_pointers(other_branch, dst_reg, PTR_TO_PACKET_META); | 2846 | find_good_pkt_pointers(other_branch, dst_reg, |
2847 | PTR_TO_PACKET_META, false); | ||
2802 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGE && | 2848 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGE && |
2803 | reg_is_init_pkt_pointer(dst_reg, PTR_TO_PACKET) && | 2849 | reg_is_init_pkt_pointer(dst_reg, PTR_TO_PACKET) && |
2804 | regs[insn->src_reg].type == PTR_TO_PACKET_META) { | 2850 | regs[insn->src_reg].type == PTR_TO_PACKET_META) { |
2805 | find_good_pkt_pointers(other_branch, ®s[insn->src_reg], | 2851 | find_good_pkt_pointers(other_branch, ®s[insn->src_reg], |
2806 | PTR_TO_PACKET_META); | 2852 | PTR_TO_PACKET_META, false); |
2807 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JLE && | 2853 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JLE && |
2808 | reg_is_init_pkt_pointer(dst_reg, PTR_TO_PACKET) && | 2854 | reg_is_init_pkt_pointer(dst_reg, PTR_TO_PACKET) && |
2809 | regs[insn->src_reg].type == PTR_TO_PACKET_META) { | 2855 | regs[insn->src_reg].type == PTR_TO_PACKET_META) { |
2810 | find_good_pkt_pointers(this_branch, ®s[insn->src_reg], | 2856 | find_good_pkt_pointers(this_branch, ®s[insn->src_reg], |
2811 | PTR_TO_PACKET_META); | 2857 | PTR_TO_PACKET_META, false); |
2812 | } else if (is_pointer_value(env, insn->dst_reg)) { | 2858 | } else if (is_pointer_value(env, insn->dst_reg)) { |
2813 | verbose(env, "R%d pointer comparison prohibited\n", | 2859 | verbose(env, "R%d pointer comparison prohibited\n", |
2814 | insn->dst_reg); | 2860 | insn->dst_reg); |