]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bpf: Let the verifier assign ids on stack fills
authorPuranjay Mohan <puranjay@kernel.org>
Tue, 3 Feb 2026 16:50:57 +0000 (08:50 -0800)
committerAlexei Starovoitov <ast@kernel.org>
Tue, 3 Feb 2026 18:31:40 +0000 (10:31 -0800)
The next commit will allow clearing of scalar ids if no other
register/stack slot has that id. This is because if only one register
has a unique id, it can't participate in bounds propagation and is
equivalent to having no id.

But if the id of a stack slot is cleared by clear_singular_ids() in the
next commit, reading that stack slot into a register will not establish
a link because the stack slot's id is cleared.

This can happen in a situation where a register is spilled and later
loses its id due to a multiply operation (for example) and then the
stack slot's id becomes singular and can be cleared.

Make sure that scalar stack slots have an id before we read them into a
register.

Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
Link: https://lore.kernel.org/r/20260203165102.2302462-2-puranjay@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
kernel/bpf/verifier.c

index 6b62b6d57175ad9d3abfba9f7f4321d51b02bc34..17b4999561565ae26db26df216e6e6ae3d03b8a6 100644 (file)
@@ -5518,6 +5518,12 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env,
                                 */
                                s32 subreg_def = state->regs[dst_regno].subreg_def;
 
+                               if (env->bpf_capable && size == 4 && spill_size == 4 &&
+                                   get_reg_width(reg) <= 32)
+                                       /* Ensure stack slot has an ID to build a relation
+                                        * with the destination register on fill.
+                                        */
+                                       assign_scalar_id_before_mov(env, reg);
                                copy_register_state(&state->regs[dst_regno], reg);
                                state->regs[dst_regno].subreg_def = subreg_def;
 
@@ -5563,6 +5569,11 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env,
                        }
                } else if (dst_regno >= 0) {
                        /* restore register state from stack */
+                       if (env->bpf_capable)
+                               /* Ensure stack slot has an ID to build a relation
+                                * with the destination register on fill.
+                                */
+                               assign_scalar_id_before_mov(env, reg);
                        copy_register_state(&state->regs[dst_regno], reg);
                        /* mark reg as written since spilled pointer state likely
                         * has its liveness marks cleared by is_state_visited()