]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bpf: allow states pruning for misc/invalid slots in iterator loops
authorEduard Zingerman <eddyz87@gmail.com>
Wed, 31 Dec 2025 05:36:03 +0000 (21:36 -0800)
committerAlexei Starovoitov <ast@kernel.org>
Wed, 31 Dec 2025 17:01:13 +0000 (09:01 -0800)
Within an iterator or callback based loop, it should be safe to prune
the current state if the old state stack slot is marked as
STACK_INVALID or STACK_MISC:
- either all branches of the old state lead to a program exit;
- or some branch of the old state leads the current state.

This is the same logic as applied in non-loop cases when
states_equal() is called in NOT_EXACT mode.

The test case that exercises stacksafe() and demonstrates the
difference in verification performance is included in the next patch.
I'm not sure if it is possible to prepare a test case that exercises
regsafe(); it appears that the compute_live_registers() pass makes
this impossible.

Nevertheless, for code readability reasons, I think that stacksafe()
and regsafe() should handle STACK_INVALID / NOT_INIT symmetrically.
Hence, this commit changes both functions.

Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20251230-loop-stack-misc-pruning-v1-1-585cfd6cec51@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
kernel/bpf/verifier.c

index 0baae7828af220accd4086b9bad270e745f4aff9..3d44c5d066239f1f86ec8d2f40d3a6abac222d66 100644 (file)
@@ -19086,11 +19086,9 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold,
        if (exact == EXACT)
                return regs_exact(rold, rcur, idmap);
 
-       if (rold->type == NOT_INIT) {
-               if (exact == NOT_EXACT || rcur->type == NOT_INIT)
-                       /* explored state can't have used this */
-                       return true;
-       }
+       if (rold->type == NOT_INIT)
+               /* explored state can't have used this */
+               return true;
 
        /* Enforce that register types have to match exactly, including their
         * modifiers (like PTR_MAYBE_NULL, MEM_RDONLY, etc), as a general
@@ -19259,7 +19257,7 @@ static bool stacksafe(struct bpf_verifier_env *env, struct bpf_func_state *old,
 
                spi = i / BPF_REG_SIZE;
 
-               if (exact != NOT_EXACT &&
+               if (exact == EXACT &&
                    (i >= cur->allocated_stack ||
                     old->stack[spi].slot_type[i % BPF_REG_SIZE] !=
                     cur->stack[spi].slot_type[i % BPF_REG_SIZE]))