Re: [PATCH bpf-next v2 14/23] bpf: Reject stack arguments if tail call reachable
Yonghong Song <[email protected]> Sun, 10 May 2026 10:15:38 -0700
| Newsgroups | dev.linux.lists.sashiko,org.kernel.vger.bpf |
|---|---|
| Message-ID | <[email protected]> |
On 5/9/26 3:42 AM, [email protected] wrote: > Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: > - [High] Order-dependent DFS logic and incomplete fallback checks allow bypassing the stack arguments restriction and cause false rejections. > -- > > commit d6cf15a73bfea82a8d40934257b79e361027a9b1 > Author: Yonghong Song <[email protected]> > > bpf: Reject stack arguments if tail call reachable > > Tail calls are deprecated and will be replaced by indirect calls > in the future. Reject programs that combine tail calls with stack > arguments rather than adding complexity for a deprecated feature. > >> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c >> index b6d07f7a52cdf..95fe21d05c100 100644 >> --- a/kernel/bpf/verifier.c >> +++ b/kernel/bpf/verifier.c > [ ... ] >> @@ -5270,14 +5275,23 @@ static int check_max_stack_depth_subprog(struct bpf_verifier_env *env, int idx, >> * this info will be utilized by JIT so that we will be preserving the >> * tail call counter throughout bpf2bpf calls combined with tailcalls >> */ >> - if (tail_call_reachable) >> + if (tail_call_reachable) { >> for (tmp = idx; tmp >= 0; tmp = dinfo[tmp].caller) { >> if (subprog[tmp].is_exception_cb) { >> verbose(env, "cannot tail call within exception cb\n"); >> return -EINVAL; >> } >> + if (subprog_has_stack_args(&subprog[tmp])) { >> + verbose(env, "tail_calls are not allowed in programs with stack args\n"); >> + return -EINVAL; >> + } > Does this create an order dependence where the verifier might falsely reject > valid programs? > > If the main program calls a subprogram with a tail call, the > tail_call_reachable flag becomes true. If the main program subsequently calls > an independent subprogram that uses stack arguments, the flag can leak into > that branch, causing the program to be rejected. Would reversing the call > order cause the same program to pass? The requirement here is that if any subprog has both tail_call_reachable and > 5 arguments, we should reject this bpf program. So ordering issue does not really matter here. > >> subprog[tmp].tail_call_reachable = true; >> } >> + } else if (!idx && subprog[0].has_tail_call && subprog_has_stack_args(&subprog[0])) { >> + verbose(env, "tail_calls are not allowed in programs with stack args\n"); >> + return -EINVAL; >> + } > Does this fallback check miss nested stack arguments? > > If the main program directly contains a tail call, the tail_call_reachable > variable remains false. If it then calls a wrapper function that passes >5 > arguments to another subprogram, won't the nested stack arguments be missed > because the fallback only checks subprog[0]? > > Can this also bypass restrictions for callback roots? > > Since the fallback hardcodes !idx and subprog[0], if an exception callback > (which is verified with idx > 0) contains a direct tail call and uses outgoing > stack arguments, it bypasses the main check loop because tail_call_reachable > is false. Will it also bypass this fallback block because !idx is false? > > Could we decouple this restriction from the call graph traversal and globally > check env->subprog_info for the presence of both features in the program > instead? Again, see the above cretiria.