bpf: set 'changed' status if propagate_precision() did any updates

Add an out parameter to `propagate_precision()` to record whether any
new precision bits were set during its execution.

Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20250611200836.4135542-5-eddyz87@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
pull/1309/head
Eduard Zingerman 2025-06-11 13:08:30 -07:00 committed by Alexei Starovoitov
parent 9a2a0d7924
commit 23b37d6165
1 changed files with 23 additions and 12 deletions

View File

@ -4678,7 +4678,9 @@ static void mark_all_scalars_imprecise(struct bpf_verifier_env *env, struct bpf_
* finalized states which help in short circuiting more future states.
*/
static int __mark_chain_precision(struct bpf_verifier_env *env,
struct bpf_verifier_state *starting_state, int regno)
struct bpf_verifier_state *starting_state,
int regno,
bool *changed)
{
struct bpf_verifier_state *st = starting_state;
struct backtrack_state *bt = &env->bt;
@ -4686,13 +4688,14 @@ static int __mark_chain_precision(struct bpf_verifier_env *env,
int last_idx = starting_state->insn_idx;
int subseq_idx = -1;
struct bpf_func_state *func;
bool tmp, skip_first = true;
struct bpf_reg_state *reg;
bool skip_first = true;
int i, fr, err;
if (!env->bpf_capable)
return 0;
changed = changed ?: &tmp;
/* set frame number from which we are starting to backtrack */
bt_init(bt, starting_state->curframe);
@ -4738,8 +4741,10 @@ static int __mark_chain_precision(struct bpf_verifier_env *env,
for_each_set_bit(i, mask, 32) {
reg = &st->frame[0]->regs[i];
bt_clear_reg(bt, i);
if (reg->type == SCALAR_VALUE)
if (reg->type == SCALAR_VALUE) {
reg->precise = true;
*changed = true;
}
}
return 0;
}
@ -4798,10 +4803,12 @@ static int __mark_chain_precision(struct bpf_verifier_env *env,
bt_clear_frame_reg(bt, fr, i);
continue;
}
if (reg->precise)
if (reg->precise) {
bt_clear_frame_reg(bt, fr, i);
else
} else {
reg->precise = true;
*changed = true;
}
}
bitmap_from_u64(mask, bt_frame_stack_mask(bt, fr));
@ -4816,10 +4823,12 @@ static int __mark_chain_precision(struct bpf_verifier_env *env,
continue;
}
reg = &func->stack[i].spilled_ptr;
if (reg->precise)
if (reg->precise) {
bt_clear_frame_slot(bt, fr, i);
else
} else {
reg->precise = true;
*changed = true;
}
}
if (env->log.level & BPF_LOG_LEVEL2) {
fmt_reg_mask(env->tmp_str_buf, TMP_STR_BUF_LEN,
@ -4855,7 +4864,7 @@ static int __mark_chain_precision(struct bpf_verifier_env *env,
int mark_chain_precision(struct bpf_verifier_env *env, int regno)
{
return __mark_chain_precision(env, env->cur_state, regno);
return __mark_chain_precision(env, env->cur_state, regno, NULL);
}
/* mark_chain_precision_batch() assumes that env->bt is set in the caller to
@ -4864,7 +4873,7 @@ int mark_chain_precision(struct bpf_verifier_env *env, int regno)
static int mark_chain_precision_batch(struct bpf_verifier_env *env,
struct bpf_verifier_state *starting_state)
{
return __mark_chain_precision(env, starting_state, -1);
return __mark_chain_precision(env, starting_state, -1, NULL);
}
static bool is_spillable_regtype(enum bpf_reg_type type)
@ -18893,7 +18902,9 @@ static int propagate_liveness(struct bpf_verifier_env *env,
* propagate them into the current state
*/
static int propagate_precision(struct bpf_verifier_env *env,
const struct bpf_verifier_state *old)
const struct bpf_verifier_state *old,
struct bpf_verifier_state *cur,
bool *changed)
{
struct bpf_reg_state *state_reg;
struct bpf_func_state *state;
@ -18941,7 +18952,7 @@ static int propagate_precision(struct bpf_verifier_env *env,
verbose(env, "\n");
}
err = mark_chain_precision_batch(env, env->cur_state);
err = __mark_chain_precision(env, cur, -1, changed);
if (err < 0)
return err;
@ -19264,7 +19275,7 @@ hit:
*/
if (is_jmp_point(env, env->insn_idx))
err = err ? : push_jmp_history(env, cur, 0, 0);
err = err ? : propagate_precision(env, &sl->state);
err = err ? : propagate_precision(env, &sl->state, cur, NULL);
if (err)
return err;
return 1;