[PATCH bpf-next v2 1/5] bpf: Verify signed loader metadata at load time

Paul Moore paul at paul-moore.com
Wed Jun 24 18:42:23 UTC 2026


On Wed, Jun 24, 2026 at 11:37 AM Daniel Borkmann <daniel at iogearbox.net> wrote:
> On 6/24/26 5:12 PM, Paul Moore wrote:
> > On Wed, Jun 24, 2026 at 10:03 AM Daniel Borkmann <daniel at iogearbox.net> wrote:
> [...]
> >>   include/linux/bpf_verifier.h |   1 +
> >>   kernel/bpf/syscall.c         |  76 +---------------
> >>   kernel/bpf/verifier.c        | 163 ++++++++++++++++++++++++++++++++++-
> >>   3 files changed, 165 insertions(+), 75 deletions(-)
> >
> > ...
> >
> >> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
> >> index b44106c8ea75..026b61d78bdb 100644
> >> --- a/kernel/bpf/syscall.c
> >> +++ b/kernel/bpf/syscall.c
> >> @@ -3189,10 +3121,6 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, struct bpf_log_at
> >>          if (err < 0)
> >>                  goto free_prog;
> >>
> >> -       err = security_bpf_prog_load(prog, attr, token, uattr.is_kernel);
> >> -       if (err)
> >> -               goto free_prog;
> >> -
> >>          /* run eBPF verifier */
> >>          err = bpf_check(&prog, attr, uattr, attr_log);
> >>          if (err < 0)
> >
> > We must preserve the existing location of the call into the
> > security_bpf_prog_load() hook as some users rely on this hook being
> > called *before* the verifier runs.
>
> Keep in mind that the verifier /at this point/ of the new location did
> _not_ verify anything. So there is no heavy-duty work happening yet at
> security_bpf_prog_load. The work that is done before security_bpf_prog_load
> is basically setting up the env, initializing the verifier log, and doing
> the process_fd_array which is resolving the map/BTF objects. But it did
> not walk any instructions etc, so semantics of the security_bpf_prog_load
> hook did not change from a user PoV.

There is still a reasonable amount of work between the existing and
new call sites, and the existing location outside of bpf_check()
offers an additional robustness benefit that future verifier changes
are less likely to impact the hook.  If I'm completely honest, I also
need to consider the events of the past year and a half; I'm now much
less inclined to support LSM hook changes in the BPF subsystem because
I'm very concerned about our ability to revert/modify those changes in
the future if needed.  That doesn't mean I won't support LSM hook
changes in BPF, but such changes are going to need to have a *very*
strong advantage from a LSM perspective to offset the risk associated
with the current BPF subsystem.

Based on what I see in this patchset, the security_bpf_prog_load()
call should remain in the current location.  If you need an additional
hook after the bpf_prog_verify_signature() call I'm happy to work with
you on that.

I also have to bring up the same question I asked back in your v1
posting: have you discussed this signature approach with Alexei?  Your
patches abandon and remove KP's signature scheme in favor of what is
effectively Blaise's signature scheme from last fall; Alexei argued
very strongly against these changes in the past.  I'd hate to spend a
lot more time reviewing and discussing patches that Alexei is simply
going to NACK once again.

> >> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> >> index 2abc79dbf281..9cd2b62da380 100644
> >> --- a/kernel/bpf/verifier.c
> >> +++ b/kernel/bpf/verifier.c
> >> @@ -19758,11 +19895,28 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr,
> >>          ret = bpf_vlog_init(&env->log, attr_log->level, attr_log->ubuf, attr_log->size);
> >>          if (ret)
> >>                  goto err_unlock;
> >> +       if (env->check_signature) {
> >> +               ret = bpf_prog_calc_tag(env->prog);
> >> +               if (ret < 0)
> >> +                       goto skip_full_check;
> >> +       }
> >>
> >>          ret = process_fd_array(env, attr, uattr);
> >>          if (ret)
> >>                  goto skip_full_check;
> >>
> >> +       if (env->check_signature) {
> >> +               ret = bpf_prog_verify_signature(env, attr, uattr.is_kernel);
> >> +               if (ret)
> >> +                       goto skip_full_check;
> >> +               signed_map_cnt = env->used_map_cnt;
> >> +       }
> >> +
> >> +       ret = security_bpf_prog_load(env->prog, attr, env->prog->aux->token,
> >> +                                    uattr.is_kernel);
> >> +       if (ret)
> >> +               goto skip_full_check;
> >
> > We can always create a new LSM hook for this call site, e.g.
> > security_bpf_prog_verify_signature(...).
> >
> >>          mark_verifier_state_clean(env);
> >>
> >>          if (IS_ERR(btf_vmlinux)) {

-- 
paul-moore.com



More information about the Linux-security-module-archive mailing list