diff options
author | David S. Miller <davem@davemloft.net> | 2016-05-20 19:53:09 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-05-20 19:53:09 -0400 |
commit | cb543e80f43b2db9d3adcc80d522b27829e60d82 (patch) | |
tree | 1f5773cda4c0b535c4432f12a633ff304d11a004 | |
parent | 238a9584e9e2c7b3ea23924e9183fee05d584789 (diff) | |
parent | 1b9b69ecb3a5236d4d3da0f0fa11af916371841e (diff) |
Merge branch 'bpf-verifier-fixes'
Alexei Starovoitov says:
====================
bpf: verifier fixes
Further testing of 'direct packet access' uncovered
several usability issues. Fix them.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | kernel/bpf/verifier.c | 30 |
1 files changed, 21 insertions, 9 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index a08d66215245..668e07903c8f 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
@@ -683,15 +683,11 @@ static int check_packet_access(struct verifier_env *env, u32 regno, int off, | |||
683 | { | 683 | { |
684 | struct reg_state *regs = env->cur_state.regs; | 684 | struct reg_state *regs = env->cur_state.regs; |
685 | struct reg_state *reg = ®s[regno]; | 685 | struct reg_state *reg = ®s[regno]; |
686 | int linear_size = (int) reg->range - (int) reg->off; | ||
687 | 686 | ||
688 | if (linear_size < 0 || linear_size >= MAX_PACKET_OFF) { | 687 | off += reg->off; |
689 | verbose("verifier bug\n"); | 688 | if (off < 0 || off + size > reg->range) { |
690 | return -EFAULT; | 689 | verbose("invalid access to packet, off=%d size=%d, R%d(id=%d,off=%d,r=%d)\n", |
691 | } | 690 | off, size, regno, reg->id, reg->off, reg->range); |
692 | if (off < 0 || off + size > linear_size) { | ||
693 | verbose("invalid access to packet, off=%d size=%d, allowed=%d\n", | ||
694 | off, size, linear_size); | ||
695 | return -EACCES; | 691 | return -EACCES; |
696 | } | 692 | } |
697 | return 0; | 693 | return 0; |
@@ -1249,6 +1245,7 @@ static int check_packet_ptr_add(struct verifier_env *env, struct bpf_insn *insn) | |||
1249 | struct reg_state *regs = env->cur_state.regs; | 1245 | struct reg_state *regs = env->cur_state.regs; |
1250 | struct reg_state *dst_reg = ®s[insn->dst_reg]; | 1246 | struct reg_state *dst_reg = ®s[insn->dst_reg]; |
1251 | struct reg_state *src_reg = ®s[insn->src_reg]; | 1247 | struct reg_state *src_reg = ®s[insn->src_reg]; |
1248 | struct reg_state tmp_reg; | ||
1252 | s32 imm; | 1249 | s32 imm; |
1253 | 1250 | ||
1254 | if (BPF_SRC(insn->code) == BPF_K) { | 1251 | if (BPF_SRC(insn->code) == BPF_K) { |
@@ -1271,6 +1268,19 @@ add_imm: | |||
1271 | */ | 1268 | */ |
1272 | dst_reg->off += imm; | 1269 | dst_reg->off += imm; |
1273 | } else { | 1270 | } else { |
1271 | if (src_reg->type == PTR_TO_PACKET) { | ||
1272 | /* R6=pkt(id=0,off=0,r=62) R7=imm22; r7 += r6 */ | ||
1273 | tmp_reg = *dst_reg; /* save r7 state */ | ||
1274 | *dst_reg = *src_reg; /* copy pkt_ptr state r6 into r7 */ | ||
1275 | src_reg = &tmp_reg; /* pretend it's src_reg state */ | ||
1276 | /* if the checks below reject it, the copy won't matter, | ||
1277 | * since we're rejecting the whole program. If all ok, | ||
1278 | * then imm22 state will be added to r7 | ||
1279 | * and r7 will be pkt(id=0,off=22,r=62) while | ||
1280 | * r6 will stay as pkt(id=0,off=0,r=62) | ||
1281 | */ | ||
1282 | } | ||
1283 | |||
1274 | if (src_reg->type == CONST_IMM) { | 1284 | if (src_reg->type == CONST_IMM) { |
1275 | /* pkt_ptr += reg where reg is known constant */ | 1285 | /* pkt_ptr += reg where reg is known constant */ |
1276 | imm = src_reg->imm; | 1286 | imm = src_reg->imm; |
@@ -1569,7 +1579,9 @@ static int check_alu_op(struct verifier_env *env, struct bpf_insn *insn) | |||
1569 | return 0; | 1579 | return 0; |
1570 | } else if (opcode == BPF_ADD && | 1580 | } else if (opcode == BPF_ADD && |
1571 | BPF_CLASS(insn->code) == BPF_ALU64 && | 1581 | BPF_CLASS(insn->code) == BPF_ALU64 && |
1572 | dst_reg->type == PTR_TO_PACKET) { | 1582 | (dst_reg->type == PTR_TO_PACKET || |
1583 | (BPF_SRC(insn->code) == BPF_X && | ||
1584 | regs[insn->src_reg].type == PTR_TO_PACKET))) { | ||
1573 | /* ptr_to_packet += K|X */ | 1585 | /* ptr_to_packet += K|X */ |
1574 | return check_packet_ptr_add(env, insn); | 1586 | return check_packet_ptr_add(env, insn); |
1575 | } else if (BPF_CLASS(insn->code) == BPF_ALU64 && | 1587 | } else if (BPF_CLASS(insn->code) == BPF_ALU64 && |