aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@fb.com>2016-05-05 22:49:11 -0400
committerDavid S. Miller <davem@davemloft.net>2016-05-06 16:01:54 -0400
commit735b433397ea2f97d59240cbe4ea770aa7c88eef (patch)
treec2caeca835dc4a72ee04652e37274c98d4ad88eb /kernel
parent969bf05eb3cedd5a8d4b7c346a85c2ede87a6d6d (diff)
bpf: improve verifier state equivalence
since UNKNOWN_VALUE type is weaker than CONST_IMM we can un-teach verifier its recognition of constants in conditional branches without affecting safety. Ex: if (reg == 123) { .. here verifier was marking reg->type as CONST_IMM instead keep reg as UNKNOWN_VALUE } Two verifier states with UNKNOWN_VALUE are equivalent, whereas CONST_IMM_X != CONST_IMM_Y, since CONST_IMM is used for stack range verification and other cases. So help search pruning by marking registers as UNKNOWN_VALUE where possible instead of CONST_IMM. Signed-off-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/bpf/verifier.c23
1 files changed, 3 insertions, 20 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 6338c61fc2a1..84bff68cf80e 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -1704,12 +1704,11 @@ static int check_cond_jmp_op(struct verifier_env *env,
1704 */ 1704 */
1705 regs[insn->dst_reg].type = PTR_TO_MAP_VALUE; 1705 regs[insn->dst_reg].type = PTR_TO_MAP_VALUE;
1706 /* branch targer cannot access it, since reg == 0 */ 1706 /* branch targer cannot access it, since reg == 0 */
1707 other_branch->regs[insn->dst_reg].type = CONST_IMM; 1707 mark_reg_unknown_value(other_branch->regs,
1708 other_branch->regs[insn->dst_reg].imm = 0; 1708 insn->dst_reg);
1709 } else { 1709 } else {
1710 other_branch->regs[insn->dst_reg].type = PTR_TO_MAP_VALUE; 1710 other_branch->regs[insn->dst_reg].type = PTR_TO_MAP_VALUE;
1711 regs[insn->dst_reg].type = CONST_IMM; 1711 mark_reg_unknown_value(regs, insn->dst_reg);
1712 regs[insn->dst_reg].imm = 0;
1713 } 1712 }
1714 } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGT && 1713 } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGT &&
1715 dst_reg->type == PTR_TO_PACKET && 1714 dst_reg->type == PTR_TO_PACKET &&
@@ -1718,22 +1717,6 @@ static int check_cond_jmp_op(struct verifier_env *env,
1718 } else if (is_pointer_value(env, insn->dst_reg)) { 1717 } else if (is_pointer_value(env, insn->dst_reg)) {
1719 verbose("R%d pointer comparison prohibited\n", insn->dst_reg); 1718 verbose("R%d pointer comparison prohibited\n", insn->dst_reg);
1720 return -EACCES; 1719 return -EACCES;
1721 } else if (BPF_SRC(insn->code) == BPF_K &&
1722 (opcode == BPF_JEQ || opcode == BPF_JNE)) {
1723
1724 if (opcode == BPF_JEQ) {
1725 /* detect if (R == imm) goto
1726 * and in the target state recognize that R = imm
1727 */
1728 other_branch->regs[insn->dst_reg].type = CONST_IMM;
1729 other_branch->regs[insn->dst_reg].imm = insn->imm;
1730 } else {
1731 /* detect if (R != imm) goto
1732 * and in the fall-through state recognize that R = imm
1733 */
1734 regs[insn->dst_reg].type = CONST_IMM;
1735 regs[insn->dst_reg].imm = insn->imm;
1736 }
1737 } 1720 }
1738 if (log_level) 1721 if (log_level)
1739 print_verifier_state(&env->cur_state); 1722 print_verifier_state(&env->cur_state);