Skip to content

Commit

Permalink
bpf: extend is_branch_taken to registers
Browse files Browse the repository at this point in the history
This patch extends is_branch_taken() logic from JMP+K instructions
to JMP+X instructions.
Conditional branches are often done when src and dst registers
contain known scalars. In such case the verifier can follow
the branch that is going to be taken when program executes.
That speeds up the verification and is essential feature to support
bounded loops.

Signed-off-by: Alexei Starovoitov <[email protected]>
Acked-by: Andrii Nakryiko <[email protected]>
Signed-off-by: Daniel Borkmann <[email protected]>
  • Loading branch information
Alexei Starovoitov authored and borkmann committed Jun 19, 2019
1 parent fc559a7 commit fb8d251
Showing 1 changed file with 19 additions and 15 deletions.
34 changes: 19 additions & 15 deletions kernel/bpf/verifier.c
Original file line number Diff line number Diff line change
Expand Up @@ -5266,9 +5266,10 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,
struct bpf_verifier_state *this_branch = env->cur_state;
struct bpf_verifier_state *other_branch;
struct bpf_reg_state *regs = this_branch->frame[this_branch->curframe]->regs;
struct bpf_reg_state *dst_reg, *other_branch_regs;
struct bpf_reg_state *dst_reg, *other_branch_regs, *src_reg = NULL;
u8 opcode = BPF_OP(insn->code);
bool is_jmp32;
int pred = -1;
int err;

/* Only conditional jumps are expected to reach here. */
Expand All @@ -5293,6 +5294,7 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,
insn->src_reg);
return -EACCES;
}
src_reg = &regs[insn->src_reg];
} else {
if (insn->src_reg != BPF_REG_0) {
verbose(env, "BPF_JMP/JMP32 uses reserved fields\n");
Expand All @@ -5308,20 +5310,22 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,
dst_reg = &regs[insn->dst_reg];
is_jmp32 = BPF_CLASS(insn->code) == BPF_JMP32;

if (BPF_SRC(insn->code) == BPF_K) {
int pred = is_branch_taken(dst_reg, insn->imm, opcode,
is_jmp32);

if (pred == 1) {
/* only follow the goto, ignore fall-through */
*insn_idx += insn->off;
return 0;
} else if (pred == 0) {
/* only follow fall-through branch, since
* that's where the program will go
*/
return 0;
}
if (BPF_SRC(insn->code) == BPF_K)
pred = is_branch_taken(dst_reg, insn->imm,
opcode, is_jmp32);
else if (src_reg->type == SCALAR_VALUE &&
tnum_is_const(src_reg->var_off))
pred = is_branch_taken(dst_reg, src_reg->var_off.value,
opcode, is_jmp32);
if (pred == 1) {
/* only follow the goto, ignore fall-through */
*insn_idx += insn->off;
return 0;
} else if (pred == 0) {
/* only follow fall-through branch, since
* that's where the program will go
*/
return 0;
}

other_branch = push_stack(env, *insn_idx + insn->off + 1, *insn_idx,
Expand Down

0 comments on commit fb8d251

Please sign in to comment.