The fastcall spill/fill rewrite is only sound while the stack slots used by the pattern are not accessed outside the pattern. Direct stack loads and stores already call check_fastcall_stack_contract() to enforce this. Helper and kfunc memory-argument checks can validate PTR_TO_STACK reads through check_stack_range_initialized() without applying the same contract. When such a read overlaps a fastcall spill slot, bpf_remove_fastcall_spills_fills() can still remove the spill/fill pair. It can then shrink the subprogram stack depth even though a helper or kfunc reads that stack address. Apply check_fastcall_stack_contract() from check_stack_range_initialized() after the concrete stack range is known. Zero-sized accesses do not read or write memory, so leave the fastcall optimization unchanged for those. Fixes: 5b5f51bff1b66 ("bpf: no_caller_saved_registers attribute for helper calls") Signed-off-by: Nuoqi Gui --- kernel/bpf/verifier.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index ff9b1f68ceca4..d77332eeab359 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -6873,6 +6873,10 @@ static int check_stack_range_initialized( max_off = reg->smax_value + off; } + if (access_size) + check_fastcall_stack_contract(env, state, env->insn_idx, + min_off); + if (meta && meta->raw_mode) { /* Ensure we won't be overwriting dynptrs when simulating byte * by byte access in check_helper_call using meta.access_size. -- 2.34.1