]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bpf: account for current allocated stack depth in widen_imprecise_scalars()
authorEduard Zingerman <eddyz87@gmail.com>
Fri, 14 Nov 2025 02:57:29 +0000 (18:57 -0800)
committerAlexei Starovoitov <ast@kernel.org>
Fri, 14 Nov 2025 17:26:05 +0000 (09:26 -0800)
The usage pattern for widen_imprecise_scalars() looks as follows:

    prev_st = find_prev_entry(env, ...);
    queued_st = push_stack(...);
    widen_imprecise_scalars(env, prev_st, queued_st);

Where prev_st is an ancestor of the queued_st in the explored states
tree. This ancestor is not guaranteed to have same allocated stack
depth as queued_st. E.g. in the following case:

    def main():
      for i in 1..2:
        foo(i)        // same callsite, differnt param

    def foo(i):
      if i == 1:
        use 128 bytes of stack
      iterator based loop

Here, for a second 'foo' call prev_st->allocated_stack is 128,
while queued_st->allocated_stack is much smaller.
widen_imprecise_scalars() needs to take this into account and avoid
accessing bpf_verifier_state->frame[*]->stack out of bounds.

Fixes: 2793a8b015f7 ("bpf: exact states comparison for iterator convergence checks")
Reported-by: Emil Tsalapatis <emil@etsalapatis.com>
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20251114025730.772723-1-eddyz87@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
kernel/bpf/verifier.c

index 8314518c8d93ae16235e6f2fe6c5c28c45cb81d2..fbe4bb91c564ae36cc56ed4f121e59b718049ebf 100644 (file)
@@ -8866,7 +8866,7 @@ static int widen_imprecise_scalars(struct bpf_verifier_env *env,
                                   struct bpf_verifier_state *cur)
 {
        struct bpf_func_state *fold, *fcur;
-       int i, fr;
+       int i, fr, num_slots;
 
        reset_idmap_scratch(env);
        for (fr = old->curframe; fr >= 0; fr--) {
@@ -8879,7 +8879,9 @@ static int widen_imprecise_scalars(struct bpf_verifier_env *env,
                                        &fcur->regs[i],
                                        &env->idmap_scratch);
 
-               for (i = 0; i < fold->allocated_stack / BPF_REG_SIZE; i++) {
+               num_slots = min(fold->allocated_stack / BPF_REG_SIZE,
+                               fcur->allocated_stack / BPF_REG_SIZE);
+               for (i = 0; i < num_slots; i++) {
                        if (!is_spilled_reg(&fold->stack[i]) ||
                            !is_spilled_reg(&fcur->stack[i]))
                                continue;