[PATCH bpf-next v4 0/9] Verify BPF signed loader at load time

Paul Moore paul at paul-moore.com
Mon Jul 6 19:20:50 UTC 2026


On Mon, Jul 6, 2026 at 1:47 PM Daniel Borkmann <daniel at iogearbox.net> wrote:
> On 7/6/26 7:13 PM, Paul Moore wrote:
> > On Mon, Jul 6, 2026 at 9:56 AM Daniel Borkmann <daniel at iogearbox.net> wrote:
> >>
> >> The BPF signing scheme signs a light skeleton's loader program and lets
> >> the loader vouch for everything else: bpftool bakes the SHA256 of the
> >> metadata map into the loader's instructions, signs the instructions, and
> >> the loader compares the (frozen, exclusive) map against that hash from
> >> within BPF once it runs. The construction is sound as a trusted hash
> >> chain, but the kernel itself never attests the metadata, and that split
> >> has been the recurring objection from the LSM / integrity side since the
> >> scheme was proposed.
> >>
> >> This proposal closes both gaps by having the kernel verify the metadata
> >> at BPF_PROG_LOAD time, before the LSM admission hook and before the
> >> verifier, /without/ growing the UAPI. A signed loader binds its metadata
> >> map(s) through the existing fd_array/fd_array_cnt, and exclusive maps
> >> are already bound to the loader's digest via excl_prog_hash. When a
> >> signature is present, the kernel collects the exclusive maps from the
> >> fd_array and appends their frozen contents to the instructions before
> >> PKCS#7 verification, so the signature covers ...
> >>
> >>      insns || metadata_0 || metadata_1 || [...]
> >>
> >> ... in fd_array order. The in-loader hash check is dropped from the
> >> gen_loader entirely: generated loaders carry no verification logic
> >> anymore, and signing or verifying a skeleton becomes an ordinary CMS
> >> operation over bytes that sit verbatim in the skeleton, reproducible
> >> offline. A signed program is either BPF_SIG_UNSIGNED or BPF_SIG_VERIFIED
> >> with nothing in between.
> >>
> >> There is no new UAPI, we now have a single signature scheme, no LSM
> >> code reaching into BPF internals, no new LSM hook, and unsigned loads
> >> are completely unaffected. It is also less complex since the loader
> >> does not need to deal with BTF, an extra kfunc, etc, as proposed in
> >> an earlier series [0]. Tested against full BPF CI which came back
> >> green. For more details and examples, see the documentation patch in
> >> this series.
> >>
> >>    [0] https://lore.kernel.org/bpf/20260522023234.3778588-1-kpsingh@kernel.org/
> >>
> >> v3 -> v4:
> >>    - Fix upper limit in MAX_FD_ARRAY_CNT (Anton)
> >>    - Reject !fd_array && attr->fd_array_cnt (Anton)
> >>    - Add bpftool patch wrt ignored return value of EVP_Digest() (sashiko)
> >>    - Fix setting of gen_loader_fixture_init (sashiko)
> >>    - Fix unused map_fd cleanup branch in selftest (bot+bpf-ci)
> >>    - Remove now unused map->excl member and adjust selftests
> >>    - Added more BPF signed_loader corner case selftest coverage
> >>    - Added Paul's Nack wrt bpf_prog_load LSM hook dispute
> >>    - Added patch 2 to move bigger allocations below fd_array
> >>      resolution (Paul)
> >
> > If you want to squash patch 2/9 and 3/9 together so that one can't
> > easily merge 3/9 without the vzalloc(program) relocation I'll gladly
> > drop my NACK on patch 3/9.
>
> Okay, I can do that and send a v5.

Great, thanks.

> Btw, I saw one sashiko complaint
> about the security_bpf_prog_load() internally not needing the:
>
>    [...]
>          if (unlikely(rc))
>                  security_bpf_prog_free(prog);
>    [...]
>
> since the security_bpf_prog_free() is already called via the regular
> teardown path now. While there are no in-tree LSM users that are
> affected by this, I'll include this as well into the squashed patch,
> so its really only called once and not twice.

I'd prefer to handle it like it was handled in commit 868d43cf8f97
("bpf: Fix security_bpf_prog_load() error handling").  Since
security_bpf_prog_load() acts not only as an access control point, but
potentially an allocation function as well, I think it is more
consistent in the error case to have the hook do whatever cleanup is
necessary before returning to the caller.

-- 
paul-moore.com



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