[PATCH bpf-next v2 0/3] BPF signature hash chains

James Bottomley James.Bottomley at HansenPartnership.com
Sat Oct 11 14:52:53 UTC 2025


On Fri, 2025-10-10 at 16:06 -0700, Alexei Starovoitov wrote:
> On Fri, Oct 10, 2025 at 8:53 AM James Bottomley
> <James.Bottomley at hansenpartnership.com> wrote:
> > 
> > On Thu, 2025-10-09 at 18:00 -0700, Alexei Starovoitov wrote:
> > [...]
> > > James's concern is valid though:
> > > 
> > > > However, the rub for LSM is that the verification of the
> > > > program map by the loader happens *after* the
> > > > security_bpf_prog_load() hook has been called.
> > > 
> > > I understand the discomfort, but that's what the kernel module
> > > loading process is doing as well, so you should be concerned with
> > > both. Since both are doing pretty much the same work.
> > 
> > OK, so let me push on this one point because I don't agree with
> > what you say here.  The way kernel modules and eBPF load is not
> > equivalent. The kernel module signatures go over a relocateable elf
> > binary which is subsequently relocated after signature verification
> > in the kernel by the ELF loader.  You can regard the ELF loader as
> > being equivalent to the eBPF loader in terms of function,
> > absolutely.  However for security purposes the ELF loader is a
> > trusted part of the kernel security envelope and its integrity is
> > part of the kernel integrity and we have a this single trusted
> > loader for every module.  In security terms verification of the ELF
> > object signature is sufficient to guarantee integrity of the module
> > because the integrity of the ELF loader is already checked.
> 
> "integrity of ELF loader" is _not_ checked. It's part of the kernel
> and you trust that the kernel is valid, because you trust the
> build tools that compiled that kernel.

No, I trust my kernel is valid because the bootloader checks its
signature on every boot (in case some tampering occurs after build). 
There are a variety of integrity mechanisms for the kernel itself, but
they all essentially run a check on boot meaning the ELF loader *is*
integrity checked.

[...]
> > Thus for eBPF, the integrity check must be over both the loader and
> > the program; integrity checking is not complete until the integrity
> > of both has been verified.
> 
> The signature covers all components: loader, the map that assists
> the loading and all progs and maps that are encoded inside that
> loader/map tuple.

The pkcs7 signature that is verified hashes over the loader only. 
Other mechanisms cover the rest.

> > If you sign only the loader and embed the hash  of the program into
> > the loader that is a different way of doing things,
> 
> That's simply not true. Please read the current code more carefully.
> There is cover letter that describes what's happening. There are no
> hashes of programs.

Is this a semantic quibble over the meaning of the word "sign"?  Fine,
I'll be more precise. Quoting from:

https://lore.kernel.org/bpf/20250921160120.9711-2-kpsingh@kernel.org/
> +	bpf_dynptr_init(&insns_ptr, prog->insnsi,
> BPF_DYNPTR_TYPE_LOCAL, 0,
> +			prog->len * sizeof(struct bpf_insn));
> +
> +	err = bpf_verify_pkcs7_signature((struct bpf_dynptr
> *)&insns_ptr,
> +					 (struct bpf_dynptr
> *)&sig_ptr, key);

for a light skeleton prog->insnsi points to the loader and the second
statement is verifying the pkcs7 signature of the loader only.

> > There are two potential solutions to this: complete the integrity
> > check before running the load hook (Blaise's patch)
> 
> That's not what it's doing! Read his patch. It's adding pointless
> signature to the loader/map tuple. It does nothing to progs, maps,
> relocations that will be created at the end when loader completes.

It doesn't need to, once we check both the loader and the map, the
integrity is verified and the loader can be trusted to run and relocate
the map into the bpf program (since you like the module parallel: we
have the integrity verification of the module object and the ELF
loader, so we can just let the relocation run: the output has integrity
because all inputs did).

> You need to realize that single loader plus single map is
> an implementation choice of tools/lib/bpf/gen_loader.c.
> It can do the same job with a single prog and no additional map.

Yes, and if the light skeleton scheme embedded the relocation and the
program itself into prog->insnsi then we wouldn't need the additional
map verification before the load hook because the pkcs7 signature check
would fully verify the integrity.

> Hence any kinda hard coded extra map signature makes no sense.
> We're not going to burden the kernel with one specific implementation
> detail of gen_loader.
> Tomorrow we might change the gen_loader to use a triple:
> prog+map+btf or any other form.
> The existing approach allows all that extensibility and freedom
> to change the gen_loader.

If we're whatiffing about the future: in the event that you need a
separate btf I assume it will come down as a map; bpftool gen -S -M
would compute a signature over the loader and both maps and the in-
kernel piece of Blaise's patch would just work.

Regards,

James




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