[PATCH v5 10/10] ipe: Add BPF program load policy enforcement via Hornet integration

Fan Wu wufan at kernel.org
Tue Apr 21 00:27:34 UTC 2026


On Mon, Apr 20, 2026 at 2:27 PM Blaise Boscaccy
<bboscaccy at linux.microsoft.com> wrote:
>
> Add support for the bpf_prog_load_post_integrity LSM hook, enabling IPE
> to make policy decisions about BPF program loading based on integrity
> verdicts provided by the Hornet LSM.
>
> New policy operation:
>   op=BPF_PROG_LOAD - Matches BPF program load events
>
> New policy properties:
>   bpf_signature=NONE      - No Verdict
>   bpf_signature=OK        - Program signature and map hashes verified
>   bpf_signature=UNSIGNED  - No signature provided
>   bpf_signature=PARTIALSIG - Signature OK but no map hash data
>   bpf_signature=UNKNOWNKEY - Cert not trusted
>   bpf_signature=UNEXPECTED - An unexpected hash value was encountered
>   bpf_signature=FAULT      - System error during verification
>   bpf_signature=BADSIG    - Signature or map hash verification failed
>   bpf_keyring=BUILTIN     - Program was signed using a builtin keyring
>   bpf_keyring=SECONDARY   - Program was signed using the secondary keyring
>   bpf_keyring=PLATFORM    - Program was signed using the platform keyring
>   bpf_kernel=TRUE         - Program originated from kernelspace
>   bpf_kernel=FALSE        - Program originated from userspace
>
> These properties map directly to the lsm_integrity_verdict enum values
> provided by the Hornet LSM through security_bpf_prog_load_post_integrity.
>
> The feature is gated on CONFIG_IPE_PROP_BPF_SIGNATURE which depends on
> CONFIG_SECURITY_HORNET.
>
> Signed-off-by: Blaise Boscaccy <bboscaccy at linux.microsoft.com>
> ---

...

> diff --git a/security/ipe/hooks.c b/security/ipe/hooks.c
> index 0ae54a880405a..03541e5bb7f60 100644
> --- a/security/ipe/hooks.c
> +++ b/security/ipe/hooks.c
> @@ -340,3 +340,40 @@ int ipe_inode_setintegrity(const struct inode *inode,
>         return -EINVAL;
>  }
>  #endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
> +
> +#ifdef CONFIG_IPE_PROP_BPF_SIGNATURE
> +/**
> + * ipe_bpf_prog_load_post_integrity() - ipe security hook for BPF program load.
> + * @prog: Supplies the BPF program being loaded.
> + * @attr: Supplies the bpf syscall attributes.
> + * @token: Supplies the BPF token, if any.
> + * @kernel: Whether the call originated from the kernel.
> + * @lsmid: Supplies the LSM ID of the integrity provider.
> + * @verdict: Supplies the integrity verdict from the provider (e.g. Hornet).
> + *
> + * This LSM hook is called after an integrity verification LSM (such as Hornet)
> + * has evaluated a BPF program's cryptographic signature. IPE uses the verdict
> + * to make a policy-based allow/deny decision.
> + *
> + * Return:
> + * * %0                - Success
> + * * %-EACCES  - Did not pass IPE policy
> + */
> +int ipe_bpf_prog_load_post_integrity(struct bpf_prog *prog,
> +                                    union bpf_attr *attr,
> +                                    struct bpf_token *token,
> +                                    bool kernel,
> +                                    const struct lsm_id *lsmid,
> +                                    enum lsm_integrity_verdict verdict)
> +{
> +       struct ipe_eval_ctx ctx = IPE_EVAL_CTX_INIT;
> +
> +       ctx.op = IPE_OP_BPF_PROG_LOAD;
> +       ctx.hook = IPE_HOOK_BPF_PROG_LOAD;
> +       ctx.bpf_verdict = verdict;
> +       ctx.bpf_keyring_id = attr->keyring_id;
> +       ctx.bpf_kernel = kernel;
> +
> +       return ipe_evaluate_event(&ctx);
> +}
> +#endif /* CONFIG_IPE_PROP_BPF_SIGNATURE */
> diff --git a/security/ipe/hooks.h b/security/ipe/hooks.h
> index 07db373327402..95b74f7899750 100644
> --- a/security/ipe/hooks.h
> +++ b/security/ipe/hooks.h
> @@ -10,6 +10,7 @@
>  #include <linux/security.h>
>  #include <linux/blk_types.h>
>  #include <linux/fsverity.h>
> +#include <linux/bpf.h>
>
>  enum ipe_hook_type {
>         IPE_HOOK_BPRM_CHECK = 0,
> @@ -18,6 +19,7 @@ enum ipe_hook_type {
>         IPE_HOOK_MPROTECT,
>         IPE_HOOK_KERNEL_READ,
>         IPE_HOOK_KERNEL_LOAD,
> +       IPE_HOOK_BPF_PROG_LOAD,
>         __IPE_HOOK_MAX
>  };
>
> @@ -52,4 +54,13 @@ int ipe_inode_setintegrity(const struct inode *inode, enum lsm_integrity_type ty
>                            const void *value, size_t size);
>  #endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
>
> +#ifdef CONFIG_IPE_PROP_BPF_SIGNATURE
> +int ipe_bpf_prog_load_post_integrity(struct bpf_prog *prog,
> +                                    union bpf_attr *attr,
> +                                    struct bpf_token *token,
> +                                    bool kernel,
> +                                    const struct lsm_id *lsmid,
> +                                    enum lsm_integrity_verdict verdict);
> +#endif /* CONFIG_IPE_PROP_BPF_SIGNATURE */
> +
>  #endif /* _IPE_HOOKS_H */
> diff --git a/security/ipe/ipe.c b/security/ipe/ipe.c
> index 495bb765de1b8..6502d4ddc641c 100644
> --- a/security/ipe/ipe.c
> +++ b/security/ipe/ipe.c
> @@ -60,6 +60,9 @@ static struct security_hook_list ipe_hooks[] __ro_after_init = {
>  #ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG
>         LSM_HOOK_INIT(inode_setintegrity, ipe_inode_setintegrity),
>  #endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
> +#ifdef CONFIG_IPE_PROP_BPF_SIGNATURE
> +       LSM_HOOK_INIT(bpf_prog_load_post_integrity, ipe_bpf_prog_load_post_integrity),
> +#endif /* CONFIG_IPE_PROP_BPF_SIGNATURE */
>  };
>

IPE only registers bpf_prog_load_post_integrity(), which fires only
when Hornet calls security_bpf_prog_load_post_integrity. If Hornet
isn't enabled via lsm=, this hook never triggers, and an IPE policy
like "DEFAULT op=BPF_PROG_LOAD action=DENY" silently allows every
load.

I think IPE should register bpf_prog_load() as well, post_integrity()
should only store the verdict to a per-prog blob, and bpf_prog_load
reads it and evaluates policy.

-Fan



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