[PATCH bpf-next 0/5] bpf: Introduce LOADER_LOAD_FD

Thiébaud Weksteen posted 5 patches 1 month, 2 weeks ago
include/linux/kernel_read_file.h              |   1 +
include/uapi/linux/bpf.h                      |   7 +
kernel/bpf/syscall.c                          | 341 ++++++++++++++++-
security/selinux/hooks.c                      |  22 +-
security/selinux/include/classmap.h           |   4 +-
tools/include/uapi/linux/bpf.h                |   7 +
tools/testing/selftests/bpf/Makefile          |   8 +-
tools/testing/selftests/bpf/loader_setup.sh   |  68 ++++
.../selftests/bpf/prog_tests/loader_load_fd.c | 361 ++++++++++++++++++
.../testing/selftests/bpf/progs/test_loader.c |  21 +
10 files changed, 824 insertions(+), 16 deletions(-)
create mode 100755 tools/testing/selftests/bpf/loader_setup.sh
create mode 100644 tools/testing/selftests/bpf/prog_tests/loader_load_fd.c
create mode 100644 tools/testing/selftests/bpf/progs/test_loader.c
[PATCH bpf-next 0/5] bpf: Introduce LOADER_LOAD_FD
Posted by Thiébaud Weksteen 1 month, 2 weeks ago
The bpf subsystem supports a signed-bpf infrastructure to guarantee the
authenticity of programs [1, 2]. While this infrastructure is ideal for
dynamic environments or enterprise deployments where untrusted binaries
are loaded post-boot, it introduces unnecessary complexity for static
platform use cases.

In the Android ecosystem, platform BPF programs reside exclusively on
read-only partitions that are strictly verified at the block level via
dm-verity. Because the kernel has already guaranteed the authenticity of
the underlying file, parsing and validating a secondary signature inside
the BPF subsystem is redundant, complex (because it requires X509 and
PKCS#7 parsing) and necessitates introducing additional signing flows
during build.

Furthermore, relying on signatures forces the kernel to manage a
dedicated public key keyring. In a decentralized ecosystem comprising
various OEMs and SoC vendors, managing these keys specifically for
infrastructure BPF programs presents an operational hurdle.

Thanks to light skeletons, it is possible to embed the loading steps
within a wrapping BPF program (also known as loader). In turns, the
loading of the loader only requires a limited, well-defined number of
steps. This series introduces the bpf command LOADER_LOAD_FD for the
kernel to directly load an ELF file which contains a loader with its
data. By moving the loading within the kernel, the authenticity of the
loader and its content can be guaranteed by existing kernel mechanisms.

Kernel Modules Precedent
------------------------

Verification of authenticity for kernel modules is supported through
multiple options. Deployments may implement PKCS#7 signature validation
or, alternatively, leverage the fact that finit_module(2) retrieves
module data via kernel_read_file().

Android utilizes this latter method for kernel module verification. By
integrating kernel_read_file() with LSM hooks, security policies can
ensure that any loaded module is sourced from a read-only partition
protected by dm-verity, and therefore trusted.

This patch series adopts a similar design for BPF by introducing the
READING_BPF_LOADER constant to the kernel_read_file() enumeration.

The availability of multiple verification paths for kernel modules
reflects the diverse requirements of different environments. Providing
analogous options for the BPF subsystem maintains consistency with this
established kernel precedent.

This proposal again?
--------------------

Similar approaches were proposed in the past [3, 4]. There are
differences that make this proposal worth sharing. Namely, the loading
relies on light skeletons for the heavy lifting. It means that the UAPI
exposed by the kernel is limited: one file descriptor of an ELF with 3
sections; and an opaque context. It also means that the processing done
by the kernel is limited: the majority of the code in this patchset is
doing basic ELF validation and calling the BPF interface that is already
exposed to the rest of the kernel (kern_sys_bpf). 

Design
------

The BPF_LOADER_LOAD_FD command provides a method for the kernel to load
and set up BPF programs and maps directly from an ELF file, guaranteeing
the authenticity of the loaded objects.

It builds upon the light skeleton approach which transfers the loading
logic (i.e., CO-RE, BTF parsing, etc) to a wrapping BPF program (called
loader), generated by libbpf. By relying on these, it is possible to
drastically reduce the expectations on the kernel interface that needs
to be declared and supported.

When loading a light skeleton, libbpf performs 4 actions:
  1. Create a map array.
  2. Populate the map array with the light skeleton’s data.
  3. Load the light skeleton program.
  4. Execute the light skeleton program.
These exact same steps are implemented in LOADER_LOAD_FD.

This new command takes a file descriptor and a context. The file
descriptor is expected to refer to an ELF file which contains 3
sections: __loader.prog, __loader.map and license. These sections are
used as-is in the steps above. The context is passed directly to
BPF_PROG_TEST_RUN. In the current libbpf implementation, that context
contains the file descriptors to the programs and maps that have been
created by the loader (for further processing by userland, such as
pinning). This context is opaque to the kernel in BPF_LOADER_LOAD_FD.

Compared to previous approaches [3] and because this approach relies on
light skeletons, only basic processing is done by the kernel when
loading the programs. CO-RE or BTF are explicitly not supported as these
are handled by the light skeleton loader.

This series also includes the corresponding SELinux changes. Namely, a
new loader_load_fd permission is added to gate the use of the syscall.
It can be used to guarantee that any userspace caller migrates to this
new command instead of the existing BPF_PROG_LOAD. Another permission,
named bpf_load is added to the system class. This permission can be used
to restrict the file allowed to be loaded. Effectively, these
permissions can be used to guarantee that the kernel loads BPF programs
originating from known locations only.

Notes
-----

- There are some limited duplications of the ELF validation between this
  patchset and the existing kernel module loading logic. This can be
  refactored.
- ELF was picked as a container for the loader’s instructions and map.
  There are very few expectations on the ELF, it is mainly a container
  for these opaque bytes.

References
----------

[1] https://lore.kernel.org/bpf/20250921160120.9711-1-kpsingh@kernel.org/
[2] https://lore.kernel.org/bpf/20260708075343.358712-1-daniel@iogearbox.net/
[3] https://lore.kernel.org/bpf/20250109214617.485144-1-bboscaccy@linux.microsoft.com/
[4] https://bpfconf.ebpf.io/bpfconf2024/bpfconf2024_material/LSFMMBPF24_kapron_verified_boot.pdf

Thiébaud Weksteen (5):
  fs/kernel_read_file,selinux: Add BPF_LOADER constant
  bpf: Introduce BPF_LOADER_LOAD_FD command
  selinux: use kernel sid in security_bpf_*
  selinux: Add BPF_LOADER_LOAD_FD syscall permission
  selftests/bpf: add loader_load_fd tests

 include/linux/kernel_read_file.h              |   1 +
 include/uapi/linux/bpf.h                      |   7 +
 kernel/bpf/syscall.c                          | 341 ++++++++++++++++-
 security/selinux/hooks.c                      |  22 +-
 security/selinux/include/classmap.h           |   4 +-
 tools/include/uapi/linux/bpf.h                |   7 +
 tools/testing/selftests/bpf/Makefile          |   8 +-
 tools/testing/selftests/bpf/loader_setup.sh   |  68 ++++
 .../selftests/bpf/prog_tests/loader_load_fd.c | 361 ++++++++++++++++++
 .../testing/selftests/bpf/progs/test_loader.c |  21 +
 10 files changed, 824 insertions(+), 16 deletions(-)
 create mode 100755 tools/testing/selftests/bpf/loader_setup.sh
 create mode 100644 tools/testing/selftests/bpf/prog_tests/loader_load_fd.c
 create mode 100644 tools/testing/selftests/bpf/progs/test_loader.c

-- 
2.55.0.691.gc56d675ccc-goog
Re: [PATCH bpf-next 0/5] bpf: Introduce LOADER_LOAD_FD
Posted by Daniel Borkmann 1 month, 1 week ago
On 8/13/26 2:26 AM, Thiébaud Weksteen wrote:
> The bpf subsystem supports a signed-bpf infrastructure to guarantee the
> authenticity of programs [1, 2]. While this infrastructure is ideal for
> dynamic environments or enterprise deployments where untrusted binaries
> are loaded post-boot, it introduces unnecessary complexity for static
> platform use cases.
> 
> In the Android ecosystem, platform BPF programs reside exclusively on
> read-only partitions that are strictly verified at the block level via
> dm-verity. Because the kernel has already guaranteed the authenticity of
> the underlying file, parsing and validating a secondary signature inside
> the BPF subsystem is redundant, complex (because it requires X509 and
> PKCS#7 parsing) and necessitates introducing additional signing flows
> during build.

Note that the BPF subsys doesn't implement any X.509 or PKCS#7 parsing,
rather we reuse the same mechanism as the module loader has been using.

> Furthermore, relying on signatures forces the kernel to manage a
> dedicated public key keyring. In a decentralized ecosystem comprising
> various OEMs and SoC vendors, managing these keys specifically for
> infrastructure BPF programs presents an operational hurdle.

There is no dedicated BPF keyring.. an OEM key built into a kernel image
has no additional runtime key management.

> Thanks to light skeletons, it is possible to embed the loading steps
> within a wrapping BPF program (also known as loader). In turns, the
> loading of the loader only requires a limited, well-defined number of
> steps. This series introduces the bpf command LOADER_LOAD_FD for the
> kernel to directly load an ELF file which contains a loader with its
> data. By moving the loading within the kernel, the authenticity of the
> loader and its content can be guaranteed by existing kernel mechanisms.

Same issue still holds as described in [0]. Also, this sounds more like
convenience for Android offloaded to the kernel.. (you stated redundant
given the signature validation and complexity wrt keyring.. so what?
don't you have the latter anyway for vendor kernel modules?) We're not
adding yet another scheme/alternative for addressing signed BPF via
separate loader mechanism. Also, if you don't want to use existing
signed BPF infra, then implement it as a policy via BPF LSM + xattr?

   [0] https://lore.kernel.org/bpf/CAADnVQLxgD_7GYWZZ49aY2LqVYOy4uGvK2ikm7MJ1Cj60VPNaw@mail.gmail.com/

Thanks,
Daniel
Re: [PATCH bpf-next 0/5] bpf: Introduce LOADER_LOAD_FD
Posted by Thiébaud Weksteen 3 weeks, 5 days ago
On Tue, Aug 18, 2026 at 2:11 AM Daniel Borkmann <daniel@iogearbox.net> wrote:
>
> On 8/13/26 2:26 AM, Thiébaud Weksteen wrote:
> > The bpf subsystem supports a signed-bpf infrastructure to guarantee the
> > authenticity of programs [1, 2]. While this infrastructure is ideal for
> > dynamic environments or enterprise deployments where untrusted binaries
> > are loaded post-boot, it introduces unnecessary complexity for static
> > platform use cases.
> >
> > In the Android ecosystem, platform BPF programs reside exclusively on
> > read-only partitions that are strictly verified at the block level via
> > dm-verity. Because the kernel has already guaranteed the authenticity of
> > the underlying file, parsing and validating a secondary signature inside
> > the BPF subsystem is redundant, complex (because it requires X509 and
> > PKCS#7 parsing) and necessitates introducing additional signing flows
> > during build.
>
> Note that the BPF subsys doesn't implement any X.509 or PKCS#7 parsing,
> rather we reuse the same mechanism as the module loader has been using.
>
> > Furthermore, relying on signatures forces the kernel to manage a
> > dedicated public key keyring. In a decentralized ecosystem comprising
> > various OEMs and SoC vendors, managing these keys specifically for
> > infrastructure BPF programs presents an operational hurdle.
>
> There is no dedicated BPF keyring.. an OEM key built into a kernel image
> has no additional runtime key management.
>
> > Thanks to light skeletons, it is possible to embed the loading steps
> > within a wrapping BPF program (also known as loader). In turns, the
> > loading of the loader only requires a limited, well-defined number of
> > steps. This series introduces the bpf command LOADER_LOAD_FD for the
> > kernel to directly load an ELF file which contains a loader with its
> > data. By moving the loading within the kernel, the authenticity of the
> > loader and its content can be guaranteed by existing kernel mechanisms.
>
> Same issue still holds as described in [0]. Also, this sounds more like
> convenience for Android offloaded to the kernel.. (you stated redundant
> given the signature validation and complexity wrt keyring.. so what?
> don't you have the latter anyway for vendor kernel modules?)

Thanks for the feedback Daniel.

Vendor kernel modules are verified as described in the 'precedent'
section: there are no signatures per module. Instead the combination
of dm-verity and SELinux policy ensures the modules' authenticity.

> We're not
> adding yet another scheme/alternative for addressing signed BPF via
> separate loader mechanism.

I understand your position. Thanks for taking the time to reply.
Re: [PATCH bpf-next 0/5] bpf: Introduce LOADER_LOAD_FD
Posted by Eric Biggers 1 month ago
On Mon, Aug 17, 2026 at 06:11:10PM +0200, Daniel Borkmann wrote:
> On 8/13/26 2:26 AM, Thiébaud Weksteen wrote:
> > The bpf subsystem supports a signed-bpf infrastructure to guarantee the
> > authenticity of programs [1, 2]. While this infrastructure is ideal for
> > dynamic environments or enterprise deployments where untrusted binaries
> > are loaded post-boot, it introduces unnecessary complexity for static
> > platform use cases.
> > 
> > In the Android ecosystem, platform BPF programs reside exclusively on
> > read-only partitions that are strictly verified at the block level via
> > dm-verity. Because the kernel has already guaranteed the authenticity of
> > the underlying file, parsing and validating a secondary signature inside
> > the BPF subsystem is redundant, complex (because it requires X509 and
> > PKCS#7 parsing) and necessitates introducing additional signing flows
> > during build.
> 
> Note that the BPF subsys doesn't implement any X.509 or PKCS#7 parsing,
> rather we reuse the same mechanism as the module loader has been using.

BPF made the mistake of using X.509 and PKCS#7 again, but that doesn't
mean it wasn't a mistake.  These formats are highly complex, with each
"signature" actually being an ASN.1 object containing multiple
certificates and signatures for arbitrary algorithms, and many other
unnecessary complexities.  The kernel's X.509, PKCS#7, and ASN.1 code
has had regular bugs ever since it was added to the kernel over a decade
ago.  Just in the last week two more vulnerabilities have gone by:
https://lore.kernel.org/all/20260821192502.3942767-2-Jeremy.Jean@oss.cyber.gouv.fr/
and
https://lore.kernel.org/all/20260822212703.1019792-2-Jeremy.Jean@oss.cyber.gouv.fr/

Just because it's not in the BPF subsystem doesn't mean it's not BPF's
responsibility for choosing to depend on this unsupportable code.

I've mostly given up even trying to review X.509 and PKCS#7 kernel
patches, as they are difficult to understand and have little to do with
actual cryptography.  And anyone building a secure system shouldn't be
using them anyway.  It's nearly impossible to implement these data
formats correctly; it's best left for userspace libraries that
absolutely *have* to support these formats and have better testing and
fuzzing tools available.

These formats are not necessary to do signatures either, as the
signature algorithms can just be used directly, e.g.
https://docs.kernel.org/crypto/libcrypto-signature.html#ml-dsa

But in most cases module authentication has never needed signatures in
the first place, as either hash-based authentication
(https://lore.kernel.org/linux-modules/20260505-module-hashes-v5-0-e174a5a49fce@weissschuh.net/)
could be used, or modules can be trusted based on being loaded from a
filesystem that is already authenticated itself.

We should start moving on from the mistake of building X.509 and PKCS#7
based systems in the kernel.  It's not working.

If there is a use case for authenticating BPF programs based on where
they are loaded from, that seems very reasonable to support directly
instead of forcing the use of unnecessary signatures and data formats.

- Eric