]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bpf: Fix variable length stack write over spilled pointers
authorAlexei Starovoitov <ast@kernel.org>
Tue, 24 Mar 2026 21:59:36 +0000 (14:59 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Wed, 25 Mar 2026 00:00:11 +0000 (17:00 -0700)
Scrub slots if variable-offset stack write goes over spilled pointers.
Otherwise is_spilled_reg() may == true && spilled_ptr.type == NOT_INIT
and valid program is rejected by check_stack_read_fixed_off()
with obscure "invalid size of register fill" message.

Fixes: 01f810ace9ed ("bpf: Allow variable-offset stack access")
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/r/20260324215938.81733-1-alexei.starovoitov@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
kernel/bpf/verifier.c

index 70a100dd4d0c385abda4c61d3feb11a0589f1a85..11207e63c94eac52f07ab02f9a63569ecc618029 100644 (file)
@@ -5251,6 +5251,18 @@ static void check_fastcall_stack_contract(struct bpf_verifier_env *env,
        }
 }
 
+static void scrub_special_slot(struct bpf_func_state *state, int spi)
+{
+       int i;
+
+       /* regular write of data into stack destroys any spilled ptr */
+       state->stack[spi].spilled_ptr.type = NOT_INIT;
+       /* Mark slots as STACK_MISC if they belonged to spilled ptr/dynptr/iter. */
+       if (is_stack_slot_special(&state->stack[spi]))
+               for (i = 0; i < BPF_REG_SIZE; i++)
+                       scrub_spilled_slot(&state->stack[spi].slot_type[i]);
+}
+
 /* check_stack_{read,write}_fixed_off functions track spill/fill of registers,
  * stack boundary and alignment are checked in check_mem_access()
  */
@@ -5348,12 +5360,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env,
        } else {
                u8 type = STACK_MISC;
 
-               /* regular write of data into stack destroys any spilled ptr */
-               state->stack[spi].spilled_ptr.type = NOT_INIT;
-               /* Mark slots as STACK_MISC if they belonged to spilled ptr/dynptr/iter. */
-               if (is_stack_slot_special(&state->stack[spi]))
-                       for (i = 0; i < BPF_REG_SIZE; i++)
-                               scrub_spilled_slot(&state->stack[spi].slot_type[i]);
+               scrub_special_slot(state, spi);
 
                /* when we zero initialize stack slots mark them as such */
                if ((reg && register_is_null(reg)) ||
@@ -5476,8 +5483,13 @@ static int check_stack_write_var_off(struct bpf_verifier_env *env,
                        }
                }
 
-               /* Erase all other spilled pointers. */
-               state->stack[spi].spilled_ptr.type = NOT_INIT;
+               /*
+                * Scrub slots if variable-offset stack write goes over spilled pointers.
+                * Otherwise is_spilled_reg() may == true && spilled_ptr.type == NOT_INIT
+                * and valid program is rejected by check_stack_read_fixed_off()
+                * with obscure "invalid size of register fill" message.
+                */
+               scrub_special_slot(state, spi);
 
                /* Update the slot type. */
                new_type = STACK_MISC;