aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/bpf/verifier.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/bpf/verifier.c')
-rw-r--r--kernel/bpf/verifier.c82
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, &reg_type); 1024 err = check_ctx_access(env, insn_idx, off, size, t, &reg_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
2342static void find_good_pkt_pointers(struct bpf_verifier_state *state, 2347static 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, &regs[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, &regs[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, &regs[insn->src_reg], 2824 find_good_pkt_pointers(other_branch, &regs[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, &regs[insn->src_reg], 2836 find_good_pkt_pointers(this_branch, &regs[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(&regs[insn->src_reg], PTR_TO_PACKET)) { 2840 reg_is_init_pkt_pointer(&regs[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(&regs[insn->src_reg], PTR_TO_PACKET)) { 2845 reg_is_init_pkt_pointer(&regs[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, &regs[insn->src_reg], 2851 find_good_pkt_pointers(other_branch, &regs[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, &regs[insn->src_reg], 2856 find_good_pkt_pointers(this_branch, &regs[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);