Re: [PATCH bpf 1/2] bpf: Validate stack arg reads against caller state

From: Alexei Starovoitov

Date: Tue Oct 20 2026 - 20:03:44 EST


On Wed, Oct 07, 2026 at 10:42 AM Weiming Shi <bestswngs@xxxxxxxxx> wrote:
> then read a slot that the caller never allocated or initialized. Async
> callback verification also starts at curframe zero, so subtracting one
> to find a caller can underflow the frame array.

Sync callbacks are broken too and this patch doesn't help:
*(u64 *)(r11 - 8) = r6;
r1 = 1;
r2 = cb ll;
...
call bpf_loop;
where cb() has 6 args in BTF and does r1 = *(u64 *)(r11 + 8).
The slot is written, so check_outgoing_stack_args() called from
push_callback_call() passes. push_stack() copies stack_arg_regs[]
of the caller and the load in cb() gets the state of r6.
set_loop_callback_state() marks R3-R5 as not init, but stack args
stay readable.
At run-time bpf_loop(), when not inlined, calls cb(i, ctx, 0, 0, 0).
x86 JIT reads arg6 from r9 and arg7 from the stack frame of bpf_loop().
The verifier thinks it's a map value, but it's garbage.

No helper or kfunc passes more than 5 args to a callback.
Reject callbacks with bpf_in_stack_arg_cnt() in push_callback_call().

> + if (!vstate->curframe) {
> + verbose(env, "invalid read from stack arg off %d without caller\n", off);
> + return -EACCES;
> + }
> +

Only async callback can get here with curframe == 0.
With the above it's rejected earlier. Drop this check.

Add sync and async callback tests to patch 2.

Also mention in the log that
commit 4286f5deee14 ("bpf: Validate outgoing stack args when btf_prepare_func_args fails")
closed this hole for the first call only.

pw-bot: cr