diff options
Diffstat (limited to 'kernel/bpf/verifier.c')
-rw-r--r-- | kernel/bpf/verifier.c | 70 |
1 files changed, 56 insertions, 14 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index b914fbe1383e..c48ca2a34b5e 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
@@ -653,6 +653,10 @@ static void mark_reg_read(const struct bpf_verifier_state *state, u32 regno) | |||
653 | { | 653 | { |
654 | struct bpf_verifier_state *parent = state->parent; | 654 | struct bpf_verifier_state *parent = state->parent; |
655 | 655 | ||
656 | if (regno == BPF_REG_FP) | ||
657 | /* We don't need to worry about FP liveness because it's read-only */ | ||
658 | return; | ||
659 | |||
656 | while (parent) { | 660 | while (parent) { |
657 | /* if read wasn't screened by an earlier write ... */ | 661 | /* if read wasn't screened by an earlier write ... */ |
658 | if (state->regs[regno].live & REG_LIVE_WRITTEN) | 662 | if (state->regs[regno].live & REG_LIVE_WRITTEN) |
@@ -1112,7 +1116,12 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn | |||
1112 | /* ctx accesses must be at a fixed offset, so that we can | 1116 | /* ctx accesses must be at a fixed offset, so that we can |
1113 | * determine what type of data were returned. | 1117 | * determine what type of data were returned. |
1114 | */ | 1118 | */ |
1115 | if (!tnum_is_const(reg->var_off)) { | 1119 | if (reg->off) { |
1120 | verbose("dereference of modified ctx ptr R%d off=%d+%d, ctx+const is allowed, ctx+const+const is not\n", | ||
1121 | regno, reg->off, off - reg->off); | ||
1122 | return -EACCES; | ||
1123 | } | ||
1124 | if (!tnum_is_const(reg->var_off) || reg->var_off.value) { | ||
1116 | char tn_buf[48]; | 1125 | char tn_buf[48]; |
1117 | 1126 | ||
1118 | tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off); | 1127 | tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off); |
@@ -1120,7 +1129,6 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn | |||
1120 | tn_buf, off, size); | 1129 | tn_buf, off, size); |
1121 | return -EACCES; | 1130 | return -EACCES; |
1122 | } | 1131 | } |
1123 | off += reg->var_off.value; | ||
1124 | err = check_ctx_access(env, insn_idx, off, size, t, ®_type); | 1132 | err = check_ctx_access(env, insn_idx, off, size, t, ®_type); |
1125 | if (!err && t == BPF_READ && value_regno >= 0) { | 1133 | if (!err && t == BPF_READ && value_regno >= 0) { |
1126 | /* ctx access returns either a scalar, or a | 1134 | /* ctx access returns either a scalar, or a |
@@ -2345,6 +2353,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn) | |||
2345 | * copy register state to dest reg | 2353 | * copy register state to dest reg |
2346 | */ | 2354 | */ |
2347 | regs[insn->dst_reg] = regs[insn->src_reg]; | 2355 | regs[insn->dst_reg] = regs[insn->src_reg]; |
2356 | regs[insn->dst_reg].live |= REG_LIVE_WRITTEN; | ||
2348 | } else { | 2357 | } else { |
2349 | /* R1 = (u32) R2 */ | 2358 | /* R1 = (u32) R2 */ |
2350 | if (is_pointer_value(env, insn->src_reg)) { | 2359 | if (is_pointer_value(env, insn->src_reg)) { |
@@ -2421,12 +2430,15 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn) | |||
2421 | } | 2430 | } |
2422 | 2431 | ||
2423 | static void find_good_pkt_pointers(struct bpf_verifier_state *state, | 2432 | static void find_good_pkt_pointers(struct bpf_verifier_state *state, |
2424 | struct bpf_reg_state *dst_reg) | 2433 | struct bpf_reg_state *dst_reg, |
2434 | bool range_right_open) | ||
2425 | { | 2435 | { |
2426 | struct bpf_reg_state *regs = state->regs, *reg; | 2436 | struct bpf_reg_state *regs = state->regs, *reg; |
2437 | u16 new_range; | ||
2427 | int i; | 2438 | int i; |
2428 | 2439 | ||
2429 | if (dst_reg->off < 0) | 2440 | if (dst_reg->off < 0 || |
2441 | (dst_reg->off == 0 && range_right_open)) | ||
2430 | /* This doesn't give us any range */ | 2442 | /* This doesn't give us any range */ |
2431 | return; | 2443 | return; |
2432 | 2444 | ||
@@ -2437,9 +2449,13 @@ static void find_good_pkt_pointers(struct bpf_verifier_state *state, | |||
2437 | */ | 2449 | */ |
2438 | return; | 2450 | return; |
2439 | 2451 | ||
2440 | /* LLVM can generate four kind of checks: | 2452 | new_range = dst_reg->off; |
2453 | if (range_right_open) | ||
2454 | new_range--; | ||
2455 | |||
2456 | /* Examples for register markings: | ||
2441 | * | 2457 | * |
2442 | * Type 1/2: | 2458 | * pkt_data in dst register: |
2443 | * | 2459 | * |
2444 | * r2 = r3; | 2460 | * r2 = r3; |
2445 | * r2 += 8; | 2461 | * r2 += 8; |
@@ -2456,7 +2472,7 @@ static void find_good_pkt_pointers(struct bpf_verifier_state *state, | |||
2456 | * r2=pkt(id=n,off=8,r=0) | 2472 | * r2=pkt(id=n,off=8,r=0) |
2457 | * r3=pkt(id=n,off=0,r=0) | 2473 | * r3=pkt(id=n,off=0,r=0) |
2458 | * | 2474 | * |
2459 | * Type 3/4: | 2475 | * pkt_data in src register: |
2460 | * | 2476 | * |
2461 | * r2 = r3; | 2477 | * r2 = r3; |
2462 | * r2 += 8; | 2478 | * r2 += 8; |
@@ -2474,7 +2490,9 @@ static void find_good_pkt_pointers(struct bpf_verifier_state *state, | |||
2474 | * r3=pkt(id=n,off=0,r=0) | 2490 | * r3=pkt(id=n,off=0,r=0) |
2475 | * | 2491 | * |
2476 | * Find register r3 and mark its range as r3=pkt(id=n,off=0,r=8) | 2492 | * Find register r3 and mark its range as r3=pkt(id=n,off=0,r=8) |
2477 | * so that range of bytes [r3, r3 + 8) is safe to access. | 2493 | * or r3=pkt(id=n,off=0,r=8-1), so that range of bytes [r3, r3 + 8) |
2494 | * and [r3, r3 + 8-1) respectively is safe to access depending on | ||
2495 | * the check. | ||
2478 | */ | 2496 | */ |
2479 | 2497 | ||
2480 | /* If our ids match, then we must have the same max_value. And we | 2498 | /* If our ids match, then we must have the same max_value. And we |
@@ -2485,14 +2503,14 @@ static void find_good_pkt_pointers(struct bpf_verifier_state *state, | |||
2485 | for (i = 0; i < MAX_BPF_REG; i++) | 2503 | for (i = 0; i < MAX_BPF_REG; i++) |
2486 | if (regs[i].type == PTR_TO_PACKET && regs[i].id == dst_reg->id) | 2504 | if (regs[i].type == PTR_TO_PACKET && regs[i].id == dst_reg->id) |
2487 | /* keep the maximum range already checked */ | 2505 | /* keep the maximum range already checked */ |
2488 | regs[i].range = max_t(u16, regs[i].range, dst_reg->off); | 2506 | regs[i].range = max(regs[i].range, new_range); |
2489 | 2507 | ||
2490 | for (i = 0; i < MAX_BPF_STACK; i += BPF_REG_SIZE) { | 2508 | for (i = 0; i < MAX_BPF_STACK; i += BPF_REG_SIZE) { |
2491 | if (state->stack_slot_type[i] != STACK_SPILL) | 2509 | if (state->stack_slot_type[i] != STACK_SPILL) |
2492 | continue; | 2510 | continue; |
2493 | reg = &state->spilled_regs[i / BPF_REG_SIZE]; | 2511 | reg = &state->spilled_regs[i / BPF_REG_SIZE]; |
2494 | if (reg->type == PTR_TO_PACKET && reg->id == dst_reg->id) | 2512 | if (reg->type == PTR_TO_PACKET && reg->id == dst_reg->id) |
2495 | reg->range = max_t(u16, reg->range, dst_reg->off); | 2513 | reg->range = max(reg->range, new_range); |
2496 | } | 2514 | } |
2497 | } | 2515 | } |
2498 | 2516 | ||
@@ -2856,19 +2874,43 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, | |||
2856 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGT && | 2874 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGT && |
2857 | dst_reg->type == PTR_TO_PACKET && | 2875 | dst_reg->type == PTR_TO_PACKET && |
2858 | regs[insn->src_reg].type == PTR_TO_PACKET_END) { | 2876 | regs[insn->src_reg].type == PTR_TO_PACKET_END) { |
2859 | find_good_pkt_pointers(this_branch, dst_reg); | 2877 | /* pkt_data' > pkt_end */ |
2878 | find_good_pkt_pointers(this_branch, dst_reg, false); | ||
2879 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGT && | ||
2880 | dst_reg->type == PTR_TO_PACKET_END && | ||
2881 | regs[insn->src_reg].type == PTR_TO_PACKET) { | ||
2882 | /* pkt_end > pkt_data' */ | ||
2883 | find_good_pkt_pointers(other_branch, ®s[insn->src_reg], true); | ||
2860 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JLT && | 2884 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JLT && |
2861 | dst_reg->type == PTR_TO_PACKET && | 2885 | dst_reg->type == PTR_TO_PACKET && |
2862 | regs[insn->src_reg].type == PTR_TO_PACKET_END) { | 2886 | regs[insn->src_reg].type == PTR_TO_PACKET_END) { |
2863 | find_good_pkt_pointers(other_branch, dst_reg); | 2887 | /* pkt_data' < pkt_end */ |
2888 | find_good_pkt_pointers(other_branch, dst_reg, true); | ||
2889 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JLT && | ||
2890 | dst_reg->type == PTR_TO_PACKET_END && | ||
2891 | regs[insn->src_reg].type == PTR_TO_PACKET) { | ||
2892 | /* pkt_end < pkt_data' */ | ||
2893 | find_good_pkt_pointers(this_branch, ®s[insn->src_reg], false); | ||
2894 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGE && | ||
2895 | dst_reg->type == PTR_TO_PACKET && | ||
2896 | regs[insn->src_reg].type == PTR_TO_PACKET_END) { | ||
2897 | /* pkt_data' >= pkt_end */ | ||
2898 | find_good_pkt_pointers(this_branch, dst_reg, true); | ||
2864 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGE && | 2899 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGE && |
2865 | dst_reg->type == PTR_TO_PACKET_END && | 2900 | dst_reg->type == PTR_TO_PACKET_END && |
2866 | regs[insn->src_reg].type == PTR_TO_PACKET) { | 2901 | regs[insn->src_reg].type == PTR_TO_PACKET) { |
2867 | find_good_pkt_pointers(other_branch, ®s[insn->src_reg]); | 2902 | /* pkt_end >= pkt_data' */ |
2903 | find_good_pkt_pointers(other_branch, ®s[insn->src_reg], false); | ||
2904 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JLE && | ||
2905 | dst_reg->type == PTR_TO_PACKET && | ||
2906 | regs[insn->src_reg].type == PTR_TO_PACKET_END) { | ||
2907 | /* pkt_data' <= pkt_end */ | ||
2908 | find_good_pkt_pointers(other_branch, dst_reg, false); | ||
2868 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JLE && | 2909 | } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JLE && |
2869 | dst_reg->type == PTR_TO_PACKET_END && | 2910 | dst_reg->type == PTR_TO_PACKET_END && |
2870 | regs[insn->src_reg].type == PTR_TO_PACKET) { | 2911 | regs[insn->src_reg].type == PTR_TO_PACKET) { |
2871 | find_good_pkt_pointers(this_branch, ®s[insn->src_reg]); | 2912 | /* pkt_end <= pkt_data' */ |
2913 | find_good_pkt_pointers(this_branch, ®s[insn->src_reg], true); | ||
2872 | } else if (is_pointer_value(env, insn->dst_reg)) { | 2914 | } else if (is_pointer_value(env, insn->dst_reg)) { |
2873 | verbose("R%d pointer comparison prohibited\n", insn->dst_reg); | 2915 | verbose("R%d pointer comparison prohibited\n", insn->dst_reg); |
2874 | return -EACCES; | 2916 | return -EACCES; |