On Mon, 2026-07-13 at 06:16 +0000, Yiyang Chen wrote:
> check_stack_range_initialized() validates helper ranges byte by byte, but
> bpf_is_spilled_reg() only checks the slot-wide spill marker. For a CAP_BPF
> load, a narrow scalar spill marks only the covered bytes as STACK_SPILL. An
> untouched sibling remains STACK_INVALID, but the helper still accepts the
> read when the slot contains a spilled scalar.
>
> Require the byte being checked to be STACK_SPILL before accepting the
> slot-wide scalar spill state.
>
> Fixes: 354e8f1970f8 ("bpf: Support <8-byte scalar spill and refill")
> Signed-off-by: Yiyang Chen <[email protected]>
> ---
> kernel/bpf/verifier.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 03e2202cca13d..c971cf34c760b 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -6785,7 +6785,8 @@ static int check_stack_range_initialized(
> goto mark;
> }
>
> - if (bpf_is_spilled_reg(&state->stack[spi]) &&
> + if (*stype == STACK_SPILL &&
> + bpf_is_spilled_reg(&state->stack[spi]) &&
Sorry, could you please explain again what's wrong with the original check?
Here it is:
if (bpf_is_spilled_reg(&state->stack[spi]) &&
(state->stack[spi].spilled_ptr.type == SCALAR_VALUE ||
env->allow_ptr_leaks)) {
... accepted ...
}
And it says: if there is a register spill at 'spi':
- always allow access if the spilled register is scalar
- when allow_ptr_leaks is true, allow access when spilled
register is either scalar or pointer.
The goal here is to avoid leaking pointers, and pointers are always 8-bytes.
> (state->stack[spi].spilled_ptr.type == SCALAR_VALUE ||
> env->allow_ptr_leaks)) {
> if (clobber) {
pw-bot: cr.