On Wed, May 27, 2026 at 12:59:43PM +0000, [email protected] wrote:
> > diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
> > index 435ae6efe961..27ad0c265c95 100644
> > --- a/kernel/bpf/syscall.c
> > +++ b/kernel/bpf/syscall.c
> > @@ -41,6 +41,7 @@
> >  #include <linux/overflow.h>
> >  #include <linux/cookie.h>
> >  #include <linux/verification.h>
> > +#include <linux/btf_ids.h>
> >
> >  #include <net/netfilter/nf_bpf_link.h>
> >  #include <net/netkit.h>
> 
> [ ... ]
> 
> > @@ -2904,6 +2914,11 @@ static int bpf_prog_mark_insn_arrays_ready(struct 
> > bpf_prog *prog)
> >     return 0;
> >  }
> >
> > +extern int bpf_multi_func(void);
> > +int __init __used bpf_multi_func(void) { return 0; }
> 
> The signature change from v5 to v6 creates a potential issue. In v5,
> bpf_multi_func had 6 arguments (matching the initial verifier setup):
> 
>   int __init __used bpf_multi_func(u64 r1, u64 r2, u64 r3,
>                                    u64 r4, u64 r5, u64 r6)
> 
> Now it has no arguments. The Sashiko AI review in v5 identified that
> context array bounds checking could fail when bpf_multi_func's argument
> count doesn't match the attached function's argument count, and the
> author acknowledged the need to disable direct context access.
> 
> Since the initial verification happens against bpf_multi_func (which now
> has 0 arguments), but the verifier previously allowed direct ctx[0-5]
> accesses based on the 6-argument version, is there still a path where
> direct context accesses could be allowed? If so, would accessing ctx[0]
> on a function with 0 arguments lead to out-of-bounds kernel stack reads?
> 
> The earlier review suggested either:
>   (a) explicitly disabling direct memory accesses to the ctx array for
>       FENTRY_MULTI and FEXIT_MULTI, or
>   (b) enforcing the use of bounds-checked helpers like bpf_get_func_arg()
> 
> Was this implemented somewhere in the patch series?

it's implemented through bpf_multi_func without any arguments,
then verifier won't allow any access to any argument,
including ctx[0], which is 1st argument

jirka

> 
> > +
> > +BTF_ID_LIST_GLOBAL_SINGLE(bpf_multi_func_btf_id, func, bpf_multi_func)
> 
> [ ... ]
> 
> > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> > index c8d980fdd709..58450cb88beb 100644
> > --- a/kernel/bpf/verifier.c
> > +++ b/kernel/bpf/verifier.c
> 
> [ ... ]
> 
> > @@ -18837,6 +18839,11 @@ static int check_attach_modify_return(unsigned 
> > long addr, const char *func_name)
> >
> >  #endif /* CONFIG_FUNCTION_ERROR_INJECTION */
> >
> > +static bool is_tracing_multi_id(const struct bpf_prog *prog, u32 btf_id)
> > +{
> > +   return is_tracing_multi(prog->expected_attach_type) && 
> > bpf_multi_func_btf_id[0] == btf_id;
> > +}
> > +
> >  int bpf_check_attach_target(struct bpf_verifier_log *log,
> >                         const struct bpf_prog *prog,
> >                         const struct bpf_prog *tgt_prog,
> 
> [ ... ]
> 
> > @@ -19094,7 +19105,18 @@ int bpf_check_attach_target(struct 
> > bpf_verifier_log *log,
> >             if (ret < 0)
> >                     return ret;
> >
> > -           if (tgt_prog) {
> > +           /*
> > +            * *.multi programs don't need an address during program
> > +            * verification, we just take the module ref if needed.
> > +            */
> > +           if (is_tracing_multi_id(prog, btf_id)) {
> > +                   if (btf_is_module(btf)) {
> > +                           mod = btf_try_get_module(btf);
> > +                           if (!mod)
> > +                                   return -ENOENT;
> > +                   }
> > +                   addr = 0;
> > +           } else if (tgt_prog) {
> >                     if (subprog == 0)
> >                             addr = (long) tgt_prog->bpf_func;
> >                     else
> 
> [ ... ]
> 
> > @@ -19122,6 +19144,12 @@ int bpf_check_attach_target(struct 
> > bpf_verifier_log *log,
> >                     ret = -EINVAL;
> >                     switch (prog->type) {
> >                     case BPF_PROG_TYPE_TRACING:
> > +                           /* *.multi sleepable programs will pass initial 
> > sleepable check,
> > +                            * the actual attached btf ids are checked 
> > later during the link
> > +                            * attachment.
> > +                            */
> > +                           if (is_tracing_multi_id(prog, btf_id))
> > +                                   ret = 0;
> >                             if (!check_attach_sleepable(btf_id, addr, 
> > tname))
> >                                     ret = 0;
> 
> The multi types are not included in btf_validate_prog_ctx_type() in
> kernel/bpf/btf.c. That function validates which attach types allow u64*
> as their ctx parameter:
> 
> kernel/bpf/btf.c:btf_validate_prog_ctx_type() {
>     case BPF_TRACE_FENTRY:
>     case BPF_TRACE_FEXIT:
>     case BPF_MODIFY_RETURN:
>         ...
> }
> 
> Since BPF_TRACE_FENTRY_MULTI and BPF_TRACE_FEXIT_MULTI also use u64*
> context, do they need to be added to that validation list? Or if direct
> context access should be disabled for multi types (per the earlier
> review concern), should they be handled with special rejection logic?
> 
> 
> ---
> 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/26509800686


Reply via email to