On Fri, May 2, 2025 at 2:44 PM Blaise Boscaccy
<bbosca...@linux.microsoft.com> wrote:
>
> This adds the Hornet Linux Security Module which provides signature
> verification of eBPF programs. This allows users to continue to
> maintain an invariant that all code running inside of the kernel has
> been signed.
>
> The primary target for signature verification is light-skeleton based
> eBPF programs which was introduced here:
> https://lore.kernel.org/bpf/20220209054315.73833-1-alexei.starovoi...@gmail.com/
>
> eBPF programs, before loading, undergo a complex set of operations
> which transform pseudo-values within the immediate operands of
> instructions into concrete values based on the running
> system. Typically, this is done by libbpf in
> userspace. Light-skeletons were introduced in order to support
> preloading of bpf programs and user-mode-drivers by removing the
> dependency on libbpf and userspace-based operations.
>
> Userpace modifications, which may change every time a program gets
> loaded or runs on a slightly different kernel, break known signature
> verification algorithms. A method is needed for passing unadulterated
> binary buffers into the kernel in-order to use existing signature
> verification algorithms. Light-skeleton loaders with their support of
> only in-kernel relocations fit that constraint.
>
> Hornet employs a signature verification scheme similar to that of
> kernel modules. A signature is appended to the end of an
> executable file. During an invocation of the BPF_PROG_LOAD subcommand,
> a signature is extracted from the current task's executable file. That
> signature is used to verify the integrity of the bpf instructions and
> maps which were passed into the kernel. Additionally, Hornet
> implicitly trusts any programs which were loaded from inside kernel
> rather than userspace, which allows BPF_PRELOAD programs along with
> outputs for BPF_SYSCALL programs to run.
>
> The validation check consists of checking a PKCS#7 formatted signature
> against a data buffer containing the raw instructions of an eBPF
> program, followed by the initial values of any maps used by the
> program. Maps are verified to be frozen before signature verification
> checking to stop TOCTOU attacks.
>
> Signed-off-by: Blaise Boscaccy <bbosca...@linux.microsoft.com>
> ---
>  Documentation/admin-guide/LSM/Hornet.rst |  65 ++++++
>  Documentation/admin-guide/LSM/index.rst  |   1 +
>  MAINTAINERS                              |   9 +
>  crypto/asymmetric_keys/pkcs7_verify.c    |  10 +
>  include/linux/kernel_read_file.h         |   1 +
>  include/linux/verification.h             |   1 +
>  include/uapi/linux/lsm.h                 |   1 +
>  security/Kconfig                         |   3 +-
>  security/Makefile                        |   1 +
>  security/hornet/Kconfig                  |  24 +++
>  security/hornet/Makefile                 |   4 +
>  security/hornet/hornet_lsm.c             | 250 +++++++++++++++++++++++
>  security/selinux/hooks.c                 |  12 +-
>  security/selinux/include/classmap.h      |   2 +-
>  14 files changed, 380 insertions(+), 4 deletions(-)
>  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_lsm.c

...

> +Configuration Options
> +=====================
> +
> +Hornet provides a kconfig knob
> +CONFIG_SECURITY_HORNET_WHITELIST_PID_ONE.  Enabling this will allow
> +bpf programs to be loaded from pid 1 without undergoing a signature
> +verification check. This option is not recommened for production
> +systems.

...

> +config SECURITY_HORNET_WHITELIST_PID_ONE
> +       bool "Whiltelist unsigned eBPF programs from PID 1"
> +       depends on SECURITY_HORNET
> +       default n
> +       help
> +         Selecting this will configure Hornet to allow eBPF loaded from pid 1
> +         to load without a verification check.
> +         Further information can be found in
> +         Documentation/admin-guide/LSM/Hornet.rst.
> +
> +         If you are unsure how to answer this question, answer N.

...

> +static int hornet_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr,
> +                               struct bpf_token *token, bool is_kernel)
> +{
> +       if (is_kernel)
> +               return 0;
> +#ifdef CONFIG_SECURITY_HORNET_WHITELIST_PID_ONE
> +       if (current->pid == 1)
> +               return 0;
> +#endif

Two quick comments on the build-time conditional above.  First, unless
there is some subtle reason why you only want the exception above to
apply to a single thread in the init process, I would suggest using
task_tgid_nr() instead of current->pid as I believe you want the init
exception to apply to all threads running within the init process.
Second, I think it would be helpful to rename the Kconfig knob to
CONFIG_SECURITY_HORNET_PIDONE_TRANSITION, or similar, to help indicate
that this is a transitional configuration option designed to make it
easier for developers to move to a system with signed BPF programs
without excessive warnings/errors from systemd in the beginning.  I
would highlight the transitory intent of this Kconfig knob both in the
Kconfig description as well as the Hornet.rst doc, a brief explanation
of the drawback for enabling this long term or on "production" systems
in the Hornet.rst section would also be a good idea.

-- 
paul-moore.com

Reply via email to