From: Yonghong Song <yonghong.song@linux.dev>
To: bot+bpf-ci@kernel.org, bpf@vger.kernel.org
Cc: ast@kernel.org, andrii@kernel.org, daniel@iogearbox.net,
jose.marchesi@oracle.com, kernel-team@fb.com,
martin.lau@kernel.org, eddyz87@gmail.com, clm@meta.com,
ihor.solodrai@linux.dev
Subject: Re: [PATCH bpf-next v5 08/16] bpf: Support stack arguments for bpf functions
Date: Sat, 18 Apr 2026 10:11:48 -0700 [thread overview]
Message-ID: <5950f60d-2820-4032-8063-bd759221783a@linux.dev> (raw)
In-Reply-To: <c0706191c8a93441ee218ba6e6f277e4172f2dd8e4e44c6ff722640ed3a45bbe@mail.kernel.org>
On 4/16/26 9:43 PM, bot+bpf-ci@kernel.org wrote:
>> diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
>> index 7bbd62c51bb5c..e0341fa0b0f7c 100644
>> --- a/include/linux/bpf_verifier.h
>> +++ b/include/linux/bpf_verifier.h
> [ ... ]
>
>> @@ -508,6 +513,17 @@ struct bpf_func_state {
>> u32 callback_depth;
>> u32 async_entry_cnt;
>>
>> + /* Stack argument tracking for current function. */
>> + struct bpf_reg_state *stack_arg_regs; /* Stack arg register states */
>> + u32 stack_arg_depth; /* Depth of stack_arg_regs array */
>> + u32 incoming_stack_arg_depth; /* Incoming stack arg count (callee) */
>> + u64 out_stack_arg_mask; /* Outgoing stack arg mask (caller) */
>> +};
>> +
>> +#define bpf_get_spilled_stack_arg(slot, frame, mask) \
>> + (((slot < frame->stack_arg_depth / BPF_REG_SIZE) && \
>> + ((1 << frame->stack_arg_regs[slot].type) & (mask))) \
>> + ? &frame->stack_arg_regs[slot] : NULL)
> Does this macro work correctly? The existing bpf_get_spilled_reg macro
> filters on frame->stack[slot].slot_type[], which is drawn from the
> STACK_* enum (STACK_SPILL, STACK_ITER, etc.) and callers pass masks
> like (1 << STACK_SPILL) | (1 << STACK_ITER).
>
> This new macro filters on bpf_reg_state.type which is from a completely
> different enum bpf_reg_type (SCALAR_VALUE, PTR_TO_BTF_ID, etc.) with
> type modifier bits (PTR_MAYBE_NULL = BIT(8), PTR_TRUSTED = BIT(20),
> etc.).
>
> For example, check_kfunc_call() in the rcu_unlock path uses:
>
> u32 clear_mask = (1 << STACK_SPILL) | (1 << STACK_ITER);
> ...
> bpf_for_each_reg_in_vstate_mask(env->cur_state, state, reg,
> clear_mask, ...);
>
> A stack-arg slot holding a MEM_RCU-tagged register would have
> reg->type including MEM_RCU (BIT(13)). Then (1 << 13) = 0x2000, and
> 0x2000 & clear_mask (0x22) = 0, so the slot is skipped and MEM_RCU is
> not cleared on rcu_unlock.
>
> Additionally, when n >= 32 (for modifier bits like PTR_TRUSTED at
> BIT(20)), the shift (1 << n) invokes undefined behavior in C.
>
> Should this use a different approach to filter stack arg slots, perhaps
> based on initialization status (type != NOT_INIT)?
>
>> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
>> index 32cc59810e14d..30f2d1f06a988 100644
>> --- a/kernel/bpf/verifier.c
>> +++ b/kernel/bpf/verifier.c
> [ ... ]
>
>> @@ -1340,6 +1340,20 @@ static int copy_stack_state(struct bpf_func_state *dst,
>> goto out_free_stack;
>> }
>>
>> + n = src->stack_arg_depth / BPF_REG_SIZE;
>> + if (n) {
>> + dst->stack_arg_regs = copy_array(dst->stack_arg_regs, src->stack_arg_regs, n,
>> + sizeof(struct bpf_reg_state),
>> + GFP_KERNEL_ACCOUNT);
>> + if (!dst->stack_arg_regs)
>> + return -ENOMEM;
>> +
>> + dst->stack_arg_depth = src->stack_arg_depth;
>> + dst->incoming_stack_arg_depth = src->incoming_stack_arg_depth;
>> + dst->out_stack_arg_mask = src->out_stack_arg_mask;
>> + }
>> +
>> + return 0;
> What happens when src->stack_arg_depth == 0 but dst has non-zero
> values from prior work?
>
> The stack_arg_depth, incoming_stack_arg_depth, out_stack_arg_mask, and
> stack_arg_regs fields come after the 'stack' field in struct
> bpf_func_state, so the preceding memcpy(dst, src, offsetof(..., stack))
> in copy_func_state does not overwrite them.
>
> When n == 0, the assignments to dst->stack_arg_depth,
> dst->incoming_stack_arg_depth, and dst->out_stack_arg_mask are skipped,
> leaving stale values in dst.
>
> This can be triggered via:
>
> 1. Frame starts with stack_arg_depth = 0, out_stack_arg_mask = 0
> 2. check_cond_jmp_op calls push_stack which saves this state
> 3. Verifier continues on one branch; BPF_ST/BPF_STX writes to r11-8,
> r11-16 cause check_stack_arg_write to call grow_stack_arg_slots,
> setting stack_arg_depth = 16 and out_stack_arg_mask = BIT(0)|BIT(1)
> 4. Branch ends; pop_stack calls bpf_copy_verifier_state which calls
> copy_stack_state with src->stack_arg_depth == 0
> 5. Because n == 0, the assignment block is skipped, and dst retains
> stack_arg_depth = 16 and out_stack_arg_mask = BIT(0)|BIT(1)
> 6. The other branch never writes r11-8 or r11-16, but when it calls a
> subprog, set_callee_state checks:
> if ((caller->out_stack_arg_mask & req_mask) != req_mask)
> The stale mask makes this check pass incorrectly
>
> Would the verifier accept a call with uninitialized stack args on that
> second branch? Should these fields be assigned unconditionally, similar
> to how allocated_stack is handled earlier in this function?
The same issue as in the previous comment. Will fix.
>
>
> ---
> AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
> See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
>
> CI run summary: https://github.com/kernel-patches/bpf/actions/runs/24546989054
next prev parent reply other threads:[~2026-04-18 17:12 UTC|newest]
Thread overview: 73+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-17 3:46 [PATCH bpf-next v5 00/16] bpf: Support stack arguments for BPF functions and kfuncs Yonghong Song
2026-04-17 3:47 ` [PATCH bpf-next v5 01/16] bpf: Remove unused parameter from check_map_kptr_access() Yonghong Song
2026-04-17 3:47 ` [PATCH bpf-next v5 02/16] bpf: Refactor to avoid redundant calculation of bpf_reg_state Yonghong Song
2026-04-17 3:47 ` [PATCH bpf-next v5 03/16] bpf: Refactor to handle memory and size together Yonghong Song
2026-04-17 4:49 ` sashiko-bot
2026-04-18 16:40 ` Yonghong Song
2026-04-18 0:52 ` bot+bpf-ci
2026-04-18 16:47 ` Yonghong Song
2026-04-17 3:47 ` [PATCH bpf-next v5 04/16] bpf: Prepare verifier logs for upcoming kfunc stack arguments Yonghong Song
2026-04-17 3:47 ` [PATCH bpf-next v5 05/16] bpf: Introduce bpf register BPF_REG_PARAMS Yonghong Song
2026-04-17 3:47 ` [PATCH bpf-next v5 06/16] bpf: Limit the scope of BPF_REG_PARAMS usage Yonghong Song
2026-04-17 4:30 ` bot+bpf-ci
2026-04-18 16:48 ` Yonghong Song
2026-04-17 4:50 ` sashiko-bot
2026-04-18 16:50 ` Yonghong Song
2026-04-18 1:04 ` bot+bpf-ci
2026-04-18 16:54 ` Yonghong Song
2026-04-17 3:47 ` [PATCH bpf-next v5 07/16] bpf: Reuse MAX_BPF_FUNC_ARGS for maximum number of arguments Yonghong Song
2026-04-17 4:30 ` bot+bpf-ci
2026-04-18 17:00 ` Yonghong Song
2026-04-18 0:52 ` bot+bpf-ci
2026-04-18 17:03 ` Yonghong Song
2026-04-17 3:47 ` [PATCH bpf-next v5 08/16] bpf: Support stack arguments for bpf functions Yonghong Song
2026-04-17 4:35 ` sashiko-bot
2026-04-18 17:10 ` Yonghong Song
2026-04-17 4:43 ` bot+bpf-ci
2026-04-18 17:11 ` Yonghong Song [this message]
2026-04-18 1:04 ` bot+bpf-ci
2026-04-17 3:47 ` [PATCH bpf-next v5 09/16] bpf: Reject stack arguments in non-JITed programs Yonghong Song
2026-04-17 4:30 ` bot+bpf-ci
2026-04-18 17:17 ` Yonghong Song
2026-04-18 0:52 ` bot+bpf-ci
2026-04-17 3:47 ` [PATCH bpf-next v5 10/16] bpf: Reject stack arguments if tail call reachable Yonghong Song
2026-04-17 4:08 ` sashiko-bot
2026-04-18 17:18 ` Yonghong Song
2026-04-18 17:37 ` Yonghong Song
2026-04-17 4:30 ` bot+bpf-ci
2026-04-18 1:04 ` bot+bpf-ci
2026-04-18 17:24 ` Yonghong Song
2026-04-17 3:47 ` [PATCH bpf-next v5 11/16] bpf: Support stack arguments for kfunc calls Yonghong Song
2026-04-17 4:40 ` sashiko-bot
2026-04-18 17:46 ` Yonghong Song
2026-04-17 4:43 ` bot+bpf-ci
2026-04-18 17:57 ` Yonghong Song
2026-04-18 1:04 ` bot+bpf-ci
2026-04-18 18:04 ` Yonghong Song
2026-04-17 3:47 ` [PATCH bpf-next v5 12/16] bpf: Enable stack argument support for x86_64 Yonghong Song
2026-04-17 4:30 ` bot+bpf-ci
2026-04-17 5:03 ` sashiko-bot
2026-04-18 18:07 ` Yonghong Song
2026-04-18 1:04 ` bot+bpf-ci
2026-04-17 3:48 ` [PATCH bpf-next v5 13/16] bpf,x86: Implement JIT support for stack arguments Yonghong Song
2026-04-17 4:44 ` sashiko-bot
2026-04-18 16:43 ` Puranjay Mohan
2026-04-18 18:15 ` Yonghong Song
2026-04-18 1:20 ` bot+bpf-ci
2026-04-18 18:23 ` Yonghong Song
2026-04-17 3:48 ` [PATCH bpf-next v5 14/16] selftests/bpf: Add tests for BPF function " Yonghong Song
2026-04-17 4:20 ` sashiko-bot
2026-04-18 0:52 ` bot+bpf-ci
2026-04-18 18:26 ` Yonghong Song
2026-04-17 3:48 ` [PATCH bpf-next v5 15/16] selftests/bpf: Add negative test for greater-than-8-byte kfunc stack argument Yonghong Song
2026-04-17 4:28 ` sashiko-bot
2026-04-18 18:29 ` Yonghong Song
2026-04-18 0:52 ` bot+bpf-ci
2026-04-17 3:48 ` [PATCH bpf-next v5 16/16] selftests/bpf: Add verifier tests for stack argument validation Yonghong Song
2026-04-17 4:38 ` sashiko-bot
2026-04-18 18:36 ` Yonghong Song
2026-04-18 0:52 ` bot+bpf-ci
2026-04-18 16:39 ` [PATCH bpf-next v5 00/16] bpf: Support stack arguments for BPF functions and kfuncs Puranjay Mohan
2026-04-18 18:47 ` Alexei Starovoitov
2026-04-18 18:54 ` Yonghong Song
2026-04-18 17:06 ` Puranjay Mohan
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=5950f60d-2820-4032-8063-bd759221783a@linux.dev \
--to=yonghong.song@linux.dev \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bot+bpf-ci@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=clm@meta.com \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=ihor.solodrai@linux.dev \
--cc=jose.marchesi@oracle.com \
--cc=kernel-team@fb.com \
--cc=martin.lau@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox