diff options
| author | Alexei Starovoitov <ast@fb.com> | 2016-05-05 22:49:11 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2016-05-06 16:01:54 -0400 |
| commit | 735b433397ea2f97d59240cbe4ea770aa7c88eef (patch) | |
| tree | c2caeca835dc4a72ee04652e37274c98d4ad88eb /kernel | |
| parent | 969bf05eb3cedd5a8d4b7c346a85c2ede87a6d6d (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.c | 23 |
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); |
