bpf: improve verifier state equivalence
authorAlexei Starovoitov <ast@fb.com>
Fri, 6 May 2016 02:49:11 +0000 (19:49 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 6 May 2016 20:01:54 +0000 (16:01 -0400)
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>
kernel/bpf/verifier.c

index 6338c61fc2a13aad855baa1ec64cf72db81dab13..84bff68cf80e0c20baf44df53b203c4e3ddd6b8c 100644 (file)
@@ -1704,12 +1704,11 @@ static int check_cond_jmp_op(struct verifier_env *env,
                         */
                        regs[insn->dst_reg].type = PTR_TO_MAP_VALUE;
                        /* branch targer cannot access it, since reg == 0 */
-                       other_branch->regs[insn->dst_reg].type = CONST_IMM;
-                       other_branch->regs[insn->dst_reg].imm = 0;
+                       mark_reg_unknown_value(other_branch->regs,
+                                              insn->dst_reg);
                } else {
                        other_branch->regs[insn->dst_reg].type = PTR_TO_MAP_VALUE;
-                       regs[insn->dst_reg].type = CONST_IMM;
-                       regs[insn->dst_reg].imm = 0;
+                       mark_reg_unknown_value(regs, insn->dst_reg);
                }
        } else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGT &&
                   dst_reg->type == PTR_TO_PACKET &&
@@ -1718,22 +1717,6 @@ static int check_cond_jmp_op(struct verifier_env *env,
        } else if (is_pointer_value(env, insn->dst_reg)) {
                verbose("R%d pointer comparison prohibited\n", insn->dst_reg);
                return -EACCES;
-       } else if (BPF_SRC(insn->code) == BPF_K &&
-                  (opcode == BPF_JEQ || opcode == BPF_JNE)) {
-
-               if (opcode == BPF_JEQ) {
-                       /* detect if (R == imm) goto
-                        * and in the target state recognize that R = imm
-                        */
-                       other_branch->regs[insn->dst_reg].type = CONST_IMM;
-                       other_branch->regs[insn->dst_reg].imm = insn->imm;
-               } else {
-                       /* detect if (R != imm) goto
-                        * and in the fall-through state recognize that R = imm
-                        */
-                       regs[insn->dst_reg].type = CONST_IMM;
-                       regs[insn->dst_reg].imm = insn->imm;
-               }
        }
        if (log_level)
                print_verifier_state(&env->cur_state);