Re: [PATCH v5 6/10] security: Hornet LSM

Paul Moore
2026-04-23T18:37:48Z

On Apr 20, 2026 Blaise Boscaccy <bboscaccy@linux.microsoft.com> wrote:
>
> This adds the Hornet Linux Security Module which provides enhanced
> signature verification and data validation for eBPF programs. This
> allows users to continue to maintain an invariant that all code
> running inside of the kernel has actually been signed and verified, by
> the kernel.
>
> This effort builds upon the currently excepted upstream solution. It
> further hardens it by providing deterministic, in-kernel checking of
> map hashes to solidify auditing along with preventing TOCTOU attacks
> against lskel map hashes.
>
> Target map hashes are passed in via PKCS#7 signed attributes. Hornet
> determines the extent which the eBFP program is signed and defers to
> other LSMs for policy decisions.
>
> Signed-off-by: Blaise Boscaccy <bboscaccy@linux.microsoft.com>
> Nacked-by: Alexei Starovoitov <alexei.starovoitov@gmail.com>
> ---
> Documentation/admin-guide/LSM/Hornet.rst | 321 +++++++++++++++++++++
> Documentation/admin-guide/LSM/index.rst | 1 +
> MAINTAINERS | 9 +
> include/linux/oid_registry.h | 3 +
> include/uapi/linux/lsm.h | 1 +
> security/Kconfig | 3 +-
> security/Makefile | 1 +
> security/hornet/Kconfig | 11 +
> security/hornet/Makefile | 7 +
> security/hornet/hornet.asn1 | 13 +
> security/hornet/hornet_lsm.c | 346 +++++++++++++++++++++++
> 11 files changed, 715 insertions(+), 1 deletion(-)
> create mode 100644 Documentation/admin-guide/LSM/Hornet.rst
> create mode 100644 security/hornet/Kconfig
> create mode 100644 security/hornet/Makefile
> create mode 100644 security/hornet/hornet.asn1
> create mode 100644 security/hornet/hornet_lsm.c

While I think this is looking pretty reasonable, I think Fan had some
feedback which merits a reply. I also spotted some references to the
secondary keyring in the docs which need to be updated (below).

> diff --git a/Documentation/admin-guide/LSM/Hornet.rst b/Documentation/admin-guide/LSM/Hornet.rst
> new file mode 100644
> index 0000000000000..af5e9cd9d83a8
> --- /dev/null
> +++ b/Documentation/admin-guide/LSM/Hornet.rst
> @@ -0,0 +1,321 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +======
> +Hornet
> +======
> +
> +Hornet is a Linux Security Module that provides extensible signature
> +verification for eBPF programs. This is selectable at build-time with
> +``CONFIG_SECURITY_HORNET``.
> +
> +Overview
> +========
> +
> +Hornet addresses concerns from users who require strict audit trails and
> +verification guarantees for eBPF programs, especially in
> +security-sensitive environments. Many production systems need assurance
> +that only authorized, unmodified eBPF programs are loaded into the
> +kernel. Hornet provides this assurance through cryptographic signature
> +verification.
> +
> +When an eBPF program is loaded via the ``bpf()`` syscall, Hornet
> +verifies a PKCS#7 signature attached to the program instructions. The
> +signature is checked against the kernel's secondary keyring using the

This version now supports using the keyring specified in the bpf_attr
union (presumably for maximum compatibility with KP's signature scheme),
which is good, but the docs need to be updated.

See below, but I would probably make a note that LSMs providing
enforcement of BPF signatures will likely want to check what keyring was
used to verify the signature, e.g. a trusted keyring vs a user supplied
keyring.

> +existing kernel cryptographic infrastructure. In addition to signing the
> +program bytecode, Hornet supports signing SHA-256 hashes of associated
> +BPF maps, enabling integrity verification of map contents at load time
> +and at runtime.
> +
> +After verification, Hornet classifies the program into one of the
> +following integrity states and passes the result to a downstream LSM hook
> +(``bpf_prog_load_post_integrity``), allowing other security modules to
> +make policy decisions based on the verification outcome:
> +
> +``LSM_INT_VERDICT_OK``
> + The program signature and all map hashes verified successfully.
> +
> +``LSM_INT_VERDICT_UNSIGNED``
> + No signature was provided with the program.
> +
> +``LSM_INT_VERDICT_PARTIALSIG``
> + The program signature verified, but the signature did not contain
> + hornet map hash data.
> +
> +``LSM_INT_VERDICT_UNKNOWNKEY``
> + The signing certificate is not trusted in the secondary keyring,

Another secondary keyring mention.

> +``LSM_INT_VERDICT_FAULT``
> + A system error occured during verification.
> +
> +``LSM_INT_VERDICT_UNEXPECTED``
> + An unexpected map hash value was encountered.
> +
> +``LSM_INT_VERDICT_BADSIG``
> + The signature or a map hash failed verification.
> +
> +Hornet itself does not enforce a policy on whether unsigned or partially
> +signed programs should be rejected. It delegates that decision to
> +downstream LSMs via the ``bpf_prog_load_post_integrity`` hook, making it
> +a composable building block in a larger security architecture.

This might be a good place to document that in addition to the verdicts
described above, LSMs providing enforcement should also consider the
keyring used for verification.

> +Known Limitations
> +=================
> +
> +- Hornet requires programs to use :doc:`light skeletons
> + </bpf/libbpf/libbpf_naming_convention>` (lskels) for the signing
> + workflow, as the tooling operates on lskel-generated headers.
> +
> +- A maximum of 64 maps per program can be tracked for hash
> + verification.
> +
> +- Map hash verification requires the maps to be frozen before loading.
> + Maps that are not frozen at load time will cause verification to fail
> + when their hashes are included in the signature.
> +
> +- Hornet relies on the kernel's secondary keyring
> + (``VERIFY_USE_SECONDARY_KEYRING``) for certificate trust. Keys must
> + be provisioned into this keyring before programs can be verified.

... another spot.

> +- The only hashing algorithm available is SHA256 due to it be hardcoded
> + in the bpf subsystem.

...

> +Signature Verification Flow
> +---------------------------
> +
> +The following describes what happens when a userspace program calls
> +``bpf(BPF_PROG_LOAD, ...)`` with a signature attached:
> +
> +1. The ``bpf_prog_load_integrity`` LSM hook is invoked.
> +
> +2. Hornet reads the signature from the userspace buffer specified by
> + ``attr->signature`` (with length ``attr->signature_size``).
> +
> +3. The PKCS#7 signature is verified against the program instructions
> + using ``verify_pkcs7_signature()`` with the kernel's secondary
> + keyring.

I believe this is the last mention of the secondary keyring.

> +4. The PKCS#7 message is parsed and its trust chain is validated via
> + ``validate_pkcs7_trust()``.
> +
> +5. Hornet extracts the authenticated attribute identified by
> + ``OID_hornet_data`` (OID ``2.25.316487325684022475439036912669789383960``)
> + from the PKCS#7 message. This attribute contains an ASN.1-encoded set
> + of map index/hash pairs.
> +
> +6. For each map hash entry, Hornet retrieves the corresponding BPF map
> + via its file descriptor, confirms it is frozen, computes its SHA-256
> + hash, and compares it against the signed hash.
> +
> +7. The resulting integrity verdict is passed to the
> + ``bpf_prog_load_post_integrity`` hook so that downstream LSMs can
> + enforce policy.

--
paul-moore.com