Re: [PATCH bpf-next v3 3/4] libbpf: Request verifier warnings for object loads

Kumar Kartikeya Dwivedi <[email protected]>
Newsgroups dev.linux.lists.sashiko,org.kernel.vger.bpf
Message-ID <CAP01T770m0vig=uxJw+GU3_km=dS6ShF2RM2XYrgSp90LxERew@mail.gmail.com>
On Sat, 18 Apr 2026 at 19:35, <[email protected]> wrote:
>
> Sashiko AI review found 3 potential issue(s):
> - [High] Valid BPF programs fail to load when a custom log buffer is too small to fit warnings.
> - [High] Massive performance and memory regression for valid programs generating warnings.
> - [Low] Empty debug logs are printed for every successful load without warnings.
> --
>
> commit ba31f1c82128deb94a4d629517c67a68ad69c567
> Author: Kumar Kartikeya Dwivedi <[email protected]>
>
>     libbpf: Request verifier warnings for object loads
>
>     On kernels supporting BPF_LOG_LEVEL_WARN, have libbpf request verifier
>     warnings for BPF object program loads by ORing in the warning bit.  This
>     keeps the existing log_level=0 retry semantics for verbose logs, while
>     still surfacing verifier warnings for successful loads.
>
>     When libbpf owns the log buffer, use a small buffer for warning-only
>     loads and flush captured warnings through the print callback. Detect
>     support by probing for BPF_FEAT_VERIFIER_WARNINGS in enum bpf_features,
>     and document the updated kernel_log_level behavior.
>
> > diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> > index 3a80a018fc7d5..c7b00c0976983 100644
> > --- a/tools/lib/bpf/libbpf.c
> > +++ b/tools/lib/bpf/libbpf.c
>
> [ ... ]
>
> > @@ -7936,7 +7940,9 @@ static int bpf_object_load_prog(struct bpf_object *obj, struct bpf_program *prog
> >                       log_buf_size = obj->log_size;
> >                       own_log_buf = false;
> >               } else {
> > -                     log_buf_size = max((size_t)BPF_LOG_BUF_SIZE, log_buf_size * 2);
> > +                     log_buf_size = max(log_level == 16 ? warn_log_buf_size :
> > +                                        (size_t)BPF_LOG_BUF_SIZE,
> > +                                        log_buf_size * 2);
> >                       tmp = realloc(log_buf, log_buf_size);
>
> If a valid program generates more than 4096 bytes (warn_log_buf_size) of
> warnings, won't the kernel's bpf_vlog_finalize() detect the log truncation
> and return -ENOSPC, causing bpf_prog_load() to fail?

Good point, will check this corner case.
That said, we only warn once for every kfunc, so it would require 4096
unique kfunc calls.
In any case, will take a look.

>
> [ ... ]
>
> >       ret = bpf_prog_load(prog->type, prog_name, license, insns, insns_cnt, &load_attr);
> >       if (ret >= 0) {
> > -             if (log_level && own_log_buf) {
> > +             if (log_level == 16 && load_attr.log_true_size && own_log_buf) {
> > +                     pr_warn("prog '%s': -- BEGIN PROG LOAD WARNINGS --\n%s-- END PROG LOAD WARNINGS --\n",
> > +                             prog->name, log_buf);
> > +             } else if (log_level && own_log_buf) {
>
> If the program loads successfully and generates no warnings, load_attr.log_true_size
> will be 0. Doesn't this skip the first check and fall through to the else-if,
> causing libbpf to unconditionally print an empty debug log for every successful load?

Hmm, good point, we should strip BPF_LOG_LEVEL_WARN for this test.
We will always set |= 16 on newer kernels, otherwise, we keep zero as
the default log level. Thus, the second branch is hit only if the log
level is non-zero.

>
> >                       pr_debug("prog '%s': -- BEGIN PROG LOAD LOG --\n%s-- END PROG LOAD LOG --\n",
> >                                prog->name, log_buf);
> >               }
>
> [ ... ]
>
> > @@ -7981,8 +7990,8 @@ static int bpf_object_load_prog(struct bpf_object *obj, struct bpf_program *prog
> >               goto out;
> >       }
> >
> > -     if (log_level == 0) {
> > -             log_level = 1;
> > +     if (log_level == (supports_verifier_warnings ? 16 : 0)) {
> > +             log_level = 1 | (supports_verifier_warnings ? 16 : 0);
> >               goto retry_load;
> >       }
>
> If the kernel returns -ENOSPC because the warnings did not fit in the buffer,
> we hit this retry logic and bump log_level to 17 (BPF_LOG_LEVEL1 | BPF_LOG_LEVEL_WARN).
>
> If the user provided a custom log buffer (own_log_buf == false), libbpf will not
> resize it before retrying. Won't the second attempt also fail with -ENOSPC,
> causing a valid program to fail to load simply because its warnings didn't fit
> the custom buffer?
>
> Additionally, if own_log_buf == true and we failed because the warnings exceeded
> the initial 4096-byte buffer, retrying with log_level = 17 will allocate a 16MB
> buffer and trigger a full instruction-by-instruction verification trace. Won't
> this cause a massive CPU and memory regression just to load a valid program?

Sounds similar to the case earlier, I will study it while addressing that.


>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.