diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 8139e41ace00..02b2915f0014 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -17289,11 +17289,14 @@ static bool is_safe_to_compute_dst_reg_range(struct bpf_insn *insn, } } +static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, struct bpf_insn *insn, + struct bpf_reg_state *dst_reg, struct bpf_reg_state src_reg); + static int maybe_fork_scalars(struct bpf_verifier_env *env, struct bpf_insn *insn, - struct bpf_reg_state *dst_reg) + struct bpf_reg_state *dst_reg, const struct bpf_reg_state *src_reg) { struct bpf_verifier_state *branch; - struct bpf_reg_state *regs; + struct bpf_reg_state *reg; bool alu32; if (reg_smin(dst_reg) == -1 && reg_smax(dst_reg) == 0) @@ -17303,19 +17306,25 @@ static int maybe_fork_scalars(struct bpf_verifier_env *env, struct bpf_insn *ins else return 0; - branch = push_stack(env, env->insn_idx, env->insn_idx, false); + branch = push_stack(env, env->insn_idx + 1, env->insn_idx, false); if (IS_ERR(branch)) return PTR_ERR(branch); - regs = branch->frame[branch->curframe]->regs; + reg = &branch->frame[branch->curframe]->regs[insn->dst_reg]; if (alu32) { - __mark_reg32_known(®s[insn->dst_reg], 0); + __mark_reg32_known(reg, 0); __mark_reg32_known(dst_reg, -1ull); } else { - __mark_reg_known(®s[insn->dst_reg], 0); + __mark_reg_known(reg, 0); __mark_reg_known(dst_reg, -1ull); } - return 0; + /* + * The insn is done with in the branch too, and what gets to the next insn is a state + * like any other. At this insn the branch is a part of the state that is looked at: + * it must not be compared with it. + */ + clear_scalar_id(reg); + return adjust_scalar_min_max_vals(env, insn, reg, *src_reg); } /* WARNING: This function does calculations on 64-bit values, but the actual @@ -17420,7 +17429,7 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, break; case BPF_AND: if (tnum_is_const(src_reg.var_off)) { - ret = maybe_fork_scalars(env, insn, dst_reg); + ret = maybe_fork_scalars(env, insn, dst_reg, &src_reg); if (ret) return ret; } @@ -17431,7 +17440,7 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, break; case BPF_OR: if (tnum_is_const(src_reg.var_off)) { - ret = maybe_fork_scalars(env, insn, dst_reg); + ret = maybe_fork_scalars(env, insn, dst_reg, &src_reg); if (ret) return ret; }