Linux Security Modules development
 help / color / mirror / Atom feed
From: KP Singh <kpsingh@kernel.org>
To: linux-security-module@vger.kernel.org, bpf@vger.kernel.org
Cc: ast@kernel.org, daniel@iogearbox.net, memxor@gmail.com,
	James.Bottomley@HansenPartnership.com, paul@paul-moore.com,
	KP Singh <kpsingh@kernel.org>
Subject: [PATCH bpf-next 11/13] ipe: add BPF program signature properties
Date: Fri, 22 May 2026 04:32:31 +0200	[thread overview]
Message-ID: <20260522023234.3778588-12-kpsingh@kernel.org> (raw)
In-Reply-To: <20260522023234.3778588-1-kpsingh@kernel.org>

Wire IPE to the BPF signing verdict stored in prog->aux->sig before
security_bpf_prog_load fires. Add three properties on a new IPE op
BPF_PROG_LOAD:

  bpf_signature= UNSIGNED | OK | METADATA_VERIFIED
  bpf_keyring=   BUILTIN | SECONDARY | PLATFORM | USER
  bpf_kernel=    TRUE | FALSE

Example policy:

  op=BPF_PROG_LOAD bpf_signature=UNSIGNED action=DENY
  op=BPF_PROG_LOAD bpf_signature=OK action=ALLOW

Gated by CONFIG_IPE_PROP_BPF_SIGNATURE (depends on BPF_SYSCALL).

Signed-off-by: KP Singh <kpsingh@kernel.org>
---
 security/ipe/Kconfig         | 14 +++++++++
 security/ipe/audit.c         | 11 +++++++
 security/ipe/eval.c          | 57 ++++++++++++++++++++++++++++++++++++
 security/ipe/eval.h          |  5 ++++
 security/ipe/hooks.c         | 36 +++++++++++++++++++++++
 security/ipe/hooks.h         |  7 +++++
 security/ipe/ipe.c           |  3 ++
 security/ipe/policy.h        | 10 +++++++
 security/ipe/policy_parser.c | 19 ++++++++++++
 9 files changed, 162 insertions(+)

diff --git a/security/ipe/Kconfig b/security/ipe/Kconfig
index a110a6cd848b..204517c60a34 100644
--- a/security/ipe/Kconfig
+++ b/security/ipe/Kconfig
@@ -13,6 +13,7 @@ menuconfig SECURITY_IPE
 	select IPE_PROP_DM_VERITY_SIGNATURE if DM_VERITY && DM_VERITY_VERIFY_ROOTHASH_SIG
 	select IPE_PROP_FS_VERITY if FS_VERITY
 	select IPE_PROP_FS_VERITY_BUILTIN_SIG if FS_VERITY && FS_VERITY_BUILTIN_SIGNATURES
+	select IPE_PROP_BPF_SIGNATURE if BPF_SYSCALL
 	help
 	  This option enables the Integrity Policy Enforcement LSM
 	  allowing users to define a policy to enforce a trust-based access
@@ -95,6 +96,19 @@ config IPE_PROP_FS_VERITY_BUILTIN_SIG
 
 	  if unsure, answer Y.
 
+config IPE_PROP_BPF_SIGNATURE
+	bool "Enable support for BPF program signature verdicts"
+	depends on BPF_SYSCALL
+	help
+	  This option enables the 'bpf_signature', 'bpf_keyring' and
+	  'bpf_kernel' properties within IPE policies. The properties
+	  These allow
+	  policy rules to gate BPF program loads based on the loader's
+	  signature verdict, the keyring used for verification, and
+	  whether the load originated in kernel mode.
+
+	  if unsure, answer Y.
+
 endmenu
 
 config SECURITY_IPE_KUNIT_TEST
diff --git a/security/ipe/audit.c b/security/ipe/audit.c
index 93fb59fbddd6..fec98c396d49 100644
--- a/security/ipe/audit.c
+++ b/security/ipe/audit.c
@@ -41,6 +41,7 @@ static const char *const audit_op_names[__IPE_OP_MAX + 1] = {
 	"KEXEC_INITRAMFS",
 	"POLICY",
 	"X509_CERT",
+	"BPF_PROG_LOAD",
 	"UNKNOWN",
 };
 
@@ -51,6 +52,7 @@ static const char *const audit_hook_names[__IPE_HOOK_MAX] = {
 	"MPROTECT",
 	"KERNEL_READ",
 	"KERNEL_LOAD",
+	"BPF_PROG_LOAD",
 };
 
 static const char *const audit_prop_names[__IPE_PROP_MAX] = {
@@ -62,6 +64,15 @@ static const char *const audit_prop_names[__IPE_PROP_MAX] = {
 	"fsverity_digest=",
 	"fsverity_signature=FALSE",
 	"fsverity_signature=TRUE",
+	"bpf_signature=UNSIGNED",
+	"bpf_signature=OK",
+	"bpf_signature=METADATA_VERIFIED",
+	"bpf_keyring=BUILTIN",
+	"bpf_keyring=SECONDARY",
+	"bpf_keyring=PLATFORM",
+	"bpf_keyring=USER",
+	"bpf_kernel=FALSE",
+	"bpf_kernel=TRUE",
 };
 
 /**
diff --git a/security/ipe/eval.c b/security/ipe/eval.c
index 21439c5be336..e4b4e3723fc8 100644
--- a/security/ipe/eval.c
+++ b/security/ipe/eval.c
@@ -11,6 +11,7 @@
 #include <linux/rcupdate.h>
 #include <linux/moduleparam.h>
 #include <linux/fsverity.h>
+#include <linux/bpf.h>
 
 #include "ipe.h"
 #include "eval.h"
@@ -265,6 +266,44 @@ static bool evaluate_fsv_sig_true(const struct ipe_eval_ctx *const ctx)
 }
 #endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
 
+#ifdef CONFIG_IPE_PROP_BPF_SIGNATURE
+static bool evaluate_bpf_verdict(const struct ipe_eval_ctx *const ctx,
+				 enum bpf_sig_verdict expected)
+{
+	return ctx->bpf_verdict == expected;
+}
+
+static bool evaluate_bpf_keyring(const struct ipe_eval_ctx *const ctx,
+				 enum bpf_sig_keyring expected)
+{
+	return ctx->bpf_keyring == expected;
+}
+
+static bool evaluate_bpf_kernel(const struct ipe_eval_ctx *const ctx,
+				bool expected)
+{
+	return ctx->bpf_kernel == expected;
+}
+#else
+static bool evaluate_bpf_verdict(const struct ipe_eval_ctx *const ctx,
+				 enum bpf_sig_verdict expected)
+{
+	return false;
+}
+
+static bool evaluate_bpf_keyring(const struct ipe_eval_ctx *const ctx,
+				 enum bpf_sig_keyring expected)
+{
+	return false;
+}
+
+static bool evaluate_bpf_kernel(const struct ipe_eval_ctx *const ctx,
+				bool expected)
+{
+	return false;
+}
+#endif /* CONFIG_IPE_PROP_BPF_SIGNATURE */
+
 /**
  * evaluate_property() - Analyze @ctx against a rule property.
  * @ctx: Supplies a pointer to the context to be evaluated.
@@ -297,6 +336,24 @@ static bool evaluate_property(const struct ipe_eval_ctx *const ctx,
 		return evaluate_fsv_sig_false(ctx);
 	case IPE_PROP_FSV_SIG_TRUE:
 		return evaluate_fsv_sig_true(ctx);
+	case IPE_PROP_BPF_SIG_UNSIGNED:
+		return evaluate_bpf_verdict(ctx, BPF_SIG_UNSIGNED);
+	case IPE_PROP_BPF_SIG_OK:
+		return evaluate_bpf_verdict(ctx, BPF_SIG_OK);
+	case IPE_PROP_BPF_SIG_METADATA_VERIFIED:
+		return evaluate_bpf_verdict(ctx, BPF_SIG_METADATA_VERIFIED);
+	case IPE_PROP_BPF_KEYRING_BUILTIN:
+		return evaluate_bpf_keyring(ctx, BPF_SIG_KEYRING_BUILTIN);
+	case IPE_PROP_BPF_KEYRING_SECONDARY:
+		return evaluate_bpf_keyring(ctx, BPF_SIG_KEYRING_SECONDARY);
+	case IPE_PROP_BPF_KEYRING_PLATFORM:
+		return evaluate_bpf_keyring(ctx, BPF_SIG_KEYRING_PLATFORM);
+	case IPE_PROP_BPF_KEYRING_USER:
+		return evaluate_bpf_keyring(ctx, BPF_SIG_KEYRING_USER);
+	case IPE_PROP_BPF_KERNEL_FALSE:
+		return evaluate_bpf_kernel(ctx, false);
+	case IPE_PROP_BPF_KERNEL_TRUE:
+		return evaluate_bpf_kernel(ctx, true);
 	default:
 		return false;
 	}
diff --git a/security/ipe/eval.h b/security/ipe/eval.h
index fef65a36468c..2ddf89695818 100644
--- a/security/ipe/eval.h
+++ b/security/ipe/eval.h
@@ -52,6 +52,11 @@ struct ipe_eval_ctx {
 #ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG
 	const struct ipe_inode *ipe_inode;
 #endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
+#ifdef CONFIG_IPE_PROP_BPF_SIGNATURE
+	u8 bpf_verdict;		/* enum bpf_sig_verdict */
+	u8 bpf_keyring;		/* enum bpf_sig_keyring */
+	bool bpf_kernel;
+#endif /* CONFIG_IPE_PROP_BPF_SIGNATURE */
 };
 
 enum ipe_match {
diff --git a/security/ipe/hooks.c b/security/ipe/hooks.c
index 0ae54a880405..bdc1b634bb08 100644
--- a/security/ipe/hooks.c
+++ b/security/ipe/hooks.c
@@ -312,6 +312,42 @@ int ipe_bdev_setintegrity(struct block_device *bdev, enum lsm_integrity_type typ
 }
 #endif /* CONFIG_IPE_PROP_DM_VERITY */
 
+#ifdef CONFIG_IPE_PROP_BPF_SIGNATURE
+/**
+ * ipe_bpf_prog_load() - IPE hook for BPF program load.
+ * @prog: The BPF program being loaded.
+ * @attr: BPF syscall attributes.
+ * @token: BPF token.
+ * @kernel: Whether the load originated in kernel mode.
+ *
+ * Return: %0 on success, %-EACCES if denied by policy.
+ */
+int ipe_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr,
+		      struct bpf_token *token, bool kernel)
+{
+	struct ipe_eval_ctx ctx = IPE_EVAL_CTX_INIT;
+
+	ipe_build_eval_ctx(&ctx, NULL, IPE_OP_BPF_PROG_LOAD,
+			   IPE_HOOK_BPF_PROG_LOAD);
+	ctx.bpf_verdict = prog->aux->sig.verdict;
+	ctx.bpf_keyring = prog->aux->sig.keyring;
+	ctx.bpf_kernel = kernel;
+	return ipe_evaluate_event(&ctx);
+}
+
+int ipe_bpf_prog_load_post_integrity(struct bpf_prog *prog)
+{
+	struct ipe_eval_ctx ctx = IPE_EVAL_CTX_INIT;
+
+	ipe_build_eval_ctx(&ctx, NULL, IPE_OP_BPF_PROG_LOAD_POST_INTEGRITY,
+			   IPE_HOOK_BPF_PROG_LOAD_POST_INTEGRITY);
+	ctx.bpf_verdict = BPF_SIG_METADATA_VERIFIED;
+	ctx.bpf_keyring = prog->aux->sig.keyring;
+	ctx.bpf_kernel = prog->aux->is_kernel;
+	return ipe_evaluate_event(&ctx);
+}
+#endif /* CONFIG_IPE_PROP_BPF_SIGNATURE */
+
 #ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG
 /**
  * ipe_inode_setintegrity() - save integrity data from a inode to IPE's LSM blob.
diff --git a/security/ipe/hooks.h b/security/ipe/hooks.h
index 07db37332740..abdedd436aa8 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,9 @@ 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(struct bpf_prog *prog, union bpf_attr *attr,
+		      struct bpf_token *token, bool kernel);
+#endif /* CONFIG_IPE_PROP_BPF_SIGNATURE */
+
 #endif /* _IPE_HOOKS_H */
diff --git a/security/ipe/ipe.c b/security/ipe/ipe.c
index 495bb765de1b..17ace9236253 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, ipe_bpf_prog_load),
+#endif /* CONFIG_IPE_PROP_BPF_SIGNATURE */
 };
 
 /**
diff --git a/security/ipe/policy.h b/security/ipe/policy.h
index 5bfbdbddeef8..eb066750a48b 100644
--- a/security/ipe/policy.h
+++ b/security/ipe/policy.h
@@ -17,6 +17,7 @@ enum ipe_op_type {
 	IPE_OP_KEXEC_INITRAMFS,
 	IPE_OP_POLICY,
 	IPE_OP_X509,
+	IPE_OP_BPF_PROG_LOAD,
 	__IPE_OP_MAX,
 };
 
@@ -39,6 +40,15 @@ enum ipe_prop_type {
 	IPE_PROP_FSV_DIGEST,
 	IPE_PROP_FSV_SIG_FALSE,
 	IPE_PROP_FSV_SIG_TRUE,
+	IPE_PROP_BPF_SIG_UNSIGNED,
+	IPE_PROP_BPF_SIG_OK,
+	IPE_PROP_BPF_SIG_METADATA_VERIFIED,
+	IPE_PROP_BPF_KEYRING_BUILTIN,
+	IPE_PROP_BPF_KEYRING_SECONDARY,
+	IPE_PROP_BPF_KEYRING_PLATFORM,
+	IPE_PROP_BPF_KEYRING_USER,
+	IPE_PROP_BPF_KERNEL_FALSE,
+	IPE_PROP_BPF_KERNEL_TRUE,
 	__IPE_PROP_MAX
 };
 
diff --git a/security/ipe/policy_parser.c b/security/ipe/policy_parser.c
index 6fa5bebf8471..c1e374d2ec34 100644
--- a/security/ipe/policy_parser.c
+++ b/security/ipe/policy_parser.c
@@ -237,6 +237,7 @@ static const match_table_t operation_tokens = {
 	{IPE_OP_KEXEC_INITRAMFS,	"op=KEXEC_INITRAMFS"},
 	{IPE_OP_POLICY,			"op=POLICY"},
 	{IPE_OP_X509,			"op=X509_CERT"},
+	{IPE_OP_BPF_PROG_LOAD,		"op=BPF_PROG_LOAD"},
 	{IPE_OP_INVALID,		NULL}
 };
 
@@ -281,6 +282,15 @@ static const match_table_t property_tokens = {
 	{IPE_PROP_FSV_DIGEST,		"fsverity_digest=%s"},
 	{IPE_PROP_FSV_SIG_FALSE,	"fsverity_signature=FALSE"},
 	{IPE_PROP_FSV_SIG_TRUE,		"fsverity_signature=TRUE"},
+	{IPE_PROP_BPF_SIG_UNSIGNED,	"bpf_signature=UNSIGNED"},
+	{IPE_PROP_BPF_SIG_OK,		"bpf_signature=OK"},
+	{IPE_PROP_BPF_SIG_METADATA_VERIFIED, "bpf_signature=METADATA_VERIFIED"},
+	{IPE_PROP_BPF_KEYRING_BUILTIN,	"bpf_keyring=BUILTIN"},
+	{IPE_PROP_BPF_KEYRING_SECONDARY, "bpf_keyring=SECONDARY"},
+	{IPE_PROP_BPF_KEYRING_PLATFORM,	"bpf_keyring=PLATFORM"},
+	{IPE_PROP_BPF_KEYRING_USER,	"bpf_keyring=USER"},
+	{IPE_PROP_BPF_KERNEL_FALSE,	"bpf_kernel=FALSE"},
+	{IPE_PROP_BPF_KERNEL_TRUE,	"bpf_kernel=TRUE"},
 	{IPE_PROP_INVALID,		NULL}
 };
 
@@ -331,6 +341,15 @@ static int parse_property(char *t, struct ipe_rule *r)
 	case IPE_PROP_DMV_SIG_TRUE:
 	case IPE_PROP_FSV_SIG_FALSE:
 	case IPE_PROP_FSV_SIG_TRUE:
+	case IPE_PROP_BPF_SIG_UNSIGNED:
+	case IPE_PROP_BPF_SIG_OK:
+	case IPE_PROP_BPF_SIG_METADATA_VERIFIED:
+	case IPE_PROP_BPF_KEYRING_BUILTIN:
+	case IPE_PROP_BPF_KEYRING_SECONDARY:
+	case IPE_PROP_BPF_KEYRING_PLATFORM:
+	case IPE_PROP_BPF_KEYRING_USER:
+	case IPE_PROP_BPF_KERNEL_FALSE:
+	case IPE_PROP_BPF_KERNEL_TRUE:
 		p->type = token;
 		break;
 	default:
-- 
2.53.0


  parent reply	other threads:[~2026-05-22  2:32 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-22  2:32 [PATCH bpf-next 00/13] Signed BPF + IPE Policies KP Singh
2026-05-22  2:32 ` [PATCH bpf-next 01/13] bpf: expose signature verdict to LSMs via bpf_prog_aux KP Singh
2026-05-22  2:32 ` [PATCH bpf-next 02/13] bpf: include prog BTF in the signed loader signature scope KP Singh
2026-05-22  2:32 ` [PATCH bpf-next 03/13] bpf, libbpf: load prog BTF in the skel_internal loader KP Singh
2026-05-22  2:32 ` [PATCH bpf-next 04/13] bpf: add bpf_loader_verify_metadata kfunc KP Singh
2026-05-22  2:32 ` [PATCH bpf-next 05/13] bpf: compute prog->digest at BPF_PROG_LOAD entry KP Singh
2026-05-22  2:32 ` [PATCH bpf-next 06/13] bpf: resolve loader-style kfunc CALLs against prog BTF KP Singh
2026-05-22  2:32 ` [PATCH bpf-next 07/13] libbpf: generate prog BTF for loader programs KP Singh
2026-05-22  2:32 ` [PATCH bpf-next 08/13] bpftool gen: embed loader prog BTF in the lskel header KP Singh
2026-05-22  2:32 ` [PATCH bpf-next 09/13] lsm: add bpf_prog_load_post_integrity hook KP Singh
2026-05-22  2:32 ` [PATCH bpf-next 10/13] bpf: invoke security_bpf_prog_load_post_integrity from the metadata kfunc KP Singh
2026-05-22  2:32 ` KP Singh [this message]
2026-05-22  2:32 ` [PATCH bpf-next 12/13] ipe: gate post-integrity BPF program loads KP Singh
2026-05-22  2:32 ` [PATCH bpf-next 13/13] selftests/bpf: add IPE BPF policy integration tests KP Singh

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260522023234.3778588-12-kpsingh@kernel.org \
    --to=kpsingh@kernel.org \
    --cc=James.Bottomley@HansenPartnership.com \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=linux-security-module@vger.kernel.org \
    --cc=memxor@gmail.com \
    --cc=paul@paul-moore.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox