Skip to content

Commit fb8d251

Browse files
Alexei Starovoitovborkmann
Alexei Starovoitov
authored andcommitted
bpf: extend is_branch_taken to registers
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]>
1 parent fc559a7 commit fb8d251

File tree

1 file changed

+19
-15
lines changed

1 file changed

+19
-15
lines changed

kernel/bpf/verifier.c

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5266,9 +5266,10 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,
52665266
struct bpf_verifier_state *this_branch = env->cur_state;
52675267
struct bpf_verifier_state *other_branch;
52685268
struct bpf_reg_state *regs = this_branch->frame[this_branch->curframe]->regs;
5269-
struct bpf_reg_state *dst_reg, *other_branch_regs;
5269+
struct bpf_reg_state *dst_reg, *other_branch_regs, *src_reg = NULL;
52705270
u8 opcode = BPF_OP(insn->code);
52715271
bool is_jmp32;
5272+
int pred = -1;
52725273
int err;
52735274

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

5311-
if (BPF_SRC(insn->code) == BPF_K) {
5312-
int pred = is_branch_taken(dst_reg, insn->imm, opcode,
5313-
is_jmp32);
5314-
5315-
if (pred == 1) {
5316-
/* only follow the goto, ignore fall-through */
5317-
*insn_idx += insn->off;
5318-
return 0;
5319-
} else if (pred == 0) {
5320-
/* only follow fall-through branch, since
5321-
* that's where the program will go
5322-
*/
5323-
return 0;
5324-
}
5313+
if (BPF_SRC(insn->code) == BPF_K)
5314+
pred = is_branch_taken(dst_reg, insn->imm,
5315+
opcode, is_jmp32);
5316+
else if (src_reg->type == SCALAR_VALUE &&
5317+
tnum_is_const(src_reg->var_off))
5318+
pred = is_branch_taken(dst_reg, src_reg->var_off.value,
5319+
opcode, is_jmp32);
5320+
if (pred == 1) {
5321+
/* only follow the goto, ignore fall-through */
5322+
*insn_idx += insn->off;
5323+
return 0;
5324+
} else if (pred == 0) {
5325+
/* only follow fall-through branch, since
5326+
* that's where the program will go
5327+
*/
5328+
return 0;
53255329
}
53265330

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

0 commit comments

Comments
 (0)