aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2016-05-20 19:53:09 -0400
committerDavid S. Miller <davem@davemloft.net>2016-05-20 19:53:09 -0400
commitcb543e80f43b2db9d3adcc80d522b27829e60d82 (patch)
tree1f5773cda4c0b535c4432f12a633ff304d11a004
parent238a9584e9e2c7b3ea23924e9183fee05d584789 (diff)
parent1b9b69ecb3a5236d4d3da0f0fa11af916371841e (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.c30
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 = &regs[regno]; 685 struct reg_state *reg = &regs[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 = &regs[insn->dst_reg]; 1246 struct reg_state *dst_reg = &regs[insn->dst_reg];
1251 struct reg_state *src_reg = &regs[insn->src_reg]; 1247 struct reg_state *src_reg = &regs[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 &&