[PATCH bpf-next v2 1/3] bpf: Update env->prev_insn_idx after do_check_insn()

From: Luis Gerhorst
Date: Sat Jun 28 2025 - 10:54:17 EST


To introduce prev_aux(env), env->prev_insn_idx must be up-to-date
directly after do_check_insn(). To achieve this, replace prev_insn_idx
with a tmp variable (to discourage use) and update env->prev_insn_idx
directly after do_check_insn().

A concern would be that some code relied on env->prev_insn_idx still
having the old value between do_check_insn() and the old
update-assignment. However, outside the do_check() function it is only
used through push_jmp_history()/do_check_insn()/is_state_visisted()
which are not called in-between the old and new assignment location.
This can also be seen from the -O0 call graph for push_jmp_history()
[1].

[1] https://sys.cs.fau.de/extern/person/gerhorst/25-06_d69baf_push_jmp_history_O0_callgraph.png

Signed-off-by: Luis Gerhorst <luis.gerhorst@xxxxxx>
---
kernel/bpf/verifier.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index f403524bd215..b33bc37d5372 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -19854,16 +19854,15 @@ static int do_check(struct bpf_verifier_env *env)
struct bpf_insn *insns = env->prog->insnsi;
int insn_cnt = env->prog->len;
bool do_print_state = false;
- int prev_insn_idx = -1;

+ env->prev_insn_idx = -1;
for (;;) {
struct bpf_insn *insn;
- int err;
+ int err, tmp;

/* reset current history entry on each new instruction */
env->cur_hist_ent = NULL;

- env->prev_insn_idx = prev_insn_idx;
if (env->insn_idx >= insn_cnt) {
verbose(env, "invalid insn idx %d insn_cnt %d\n",
env->insn_idx, insn_cnt);
@@ -19942,7 +19941,6 @@ static int do_check(struct bpf_verifier_env *env)
}

sanitize_mark_insn_seen(env);
- prev_insn_idx = env->insn_idx;

/* Reduce verification complexity by stopping speculative path
* verification when a nospec is encountered.
@@ -19950,7 +19948,9 @@ static int do_check(struct bpf_verifier_env *env)
if (state->speculative && cur_aux(env)->nospec)
goto process_bpf_exit;

+ tmp = env->insn_idx;
err = do_check_insn(env, &do_print_state);
+ env->prev_insn_idx = tmp;
if (error_recoverable_with_nospec(err) && state->speculative) {
/* Prevent this speculative path from ever reaching the
* insn that would have been unsafe to execute.
@@ -19978,13 +19978,13 @@ static int do_check(struct bpf_verifier_env *env)
* to document this in case nospec_result is used
* elsewhere in the future.
*/
- WARN_ON_ONCE(env->insn_idx != prev_insn_idx + 1);
+ WARN_ON_ONCE(env->insn_idx != env->prev_insn_idx + 1);
process_bpf_exit:
mark_verifier_state_scratched(env);
err = update_branch_counts(env, env->cur_state);
if (err)
return err;
- err = pop_stack(env, &prev_insn_idx, &env->insn_idx,
+ err = pop_stack(env, &env->prev_insn_idx, &env->insn_idx,
pop_log);
if (err < 0) {
if (err != -ENOENT)
--
2.49.0