[RFC PATCH] ipe: support multiple BPF integrity verification LSMs

Paul Moore paul at paul-moore.com
Sat May 23 20:09:00 UTC 2026


Currently IPE always records the last BPF integrity verification verdict,
which is reasonable with only a single BPF verification LSM, but it
becomes problematic when multiple mechanisms end up submitting BPF
program integrity verdicts.

This patch updates IPE to record all of the received BPF program
integrity verdicts, along with their associated LSM IDs, ultimately using
the "worst" verdict in the policy enforcement engine.  Policy support for
selecting individual integrity verdicts was intentionally omitted from
this patch to keep things simple both from a code and policy developer
perspective, however future work to add selector support should be
trivial.

Signed-off-by: Paul Moore <paul at paul-moore.com>
---
 include/linux/security.h | 14 +++++++-------
 security/ipe/eval.h      |  7 ++++++-
 security/ipe/hooks.c     | 20 +++++++++++++++++---
 3 files changed, 30 insertions(+), 11 deletions(-)

diff --git a/include/linux/security.h b/include/linux/security.h
index 598cd2eb1dcd..6a987a0347a0 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -103,13 +103,13 @@ enum lsm_integrity_type {
 
 enum lsm_integrity_verdict {
 	LSM_INT_VERDICT_NONE = 0,
-	LSM_INT_VERDICT_OK,
-	LSM_INT_VERDICT_UNSIGNED,
-	LSM_INT_VERDICT_PARTIALSIG,
-	LSM_INT_VERDICT_UNKNOWNKEY,
-	LSM_INT_VERDICT_UNEXPECTED,
-	LSM_INT_VERDICT_FAULT,
-	LSM_INT_VERDICT_BADSIG,
+	LSM_INT_VERDICT_OK = 1,
+	LSM_INT_VERDICT_UNSIGNED = 2,
+	LSM_INT_VERDICT_PARTIALSIG = 3,
+	LSM_INT_VERDICT_UNKNOWNKEY = 4,
+	LSM_INT_VERDICT_UNEXPECTED = 5,
+	LSM_INT_VERDICT_FAULT = 6,
+	LSM_INT_VERDICT_BADSIG = 7,
 };
 
 /*
diff --git a/security/ipe/eval.h b/security/ipe/eval.h
index b061cb5ade27..90c7b66b9ca8 100644
--- a/security/ipe/eval.h
+++ b/security/ipe/eval.h
@@ -8,6 +8,7 @@
 
 #include <linux/file.h>
 #include <linux/types.h>
+#include <linux/lsm_count.h>
 
 #include "policy.h"
 #include "hooks.h"
@@ -39,7 +40,11 @@ struct ipe_inode {
 
 #ifdef CONFIG_IPE_PROP_BPF_SIGNATURE
 struct ipe_bpf_prog {
-	enum lsm_integrity_verdict verdict;
+	struct {
+		const struct lsm_id *lsmid;
+		enum lsm_integrity_verdict verdict;
+	} verdicts[MAX_LSM_COUNT];
+	unsigned int count;
 };
 #endif /* CONFIG_IPE_PROP_BPF_SIGNATURE */
 
diff --git a/security/ipe/hooks.c b/security/ipe/hooks.c
index 9271e129a2cf..143bb2ae2b12 100644
--- a/security/ipe/hooks.c
+++ b/security/ipe/hooks.c
@@ -9,6 +9,7 @@
 #include <linux/binfmts.h>
 #include <linux/mman.h>
 #include <linux/blk_types.h>
+#include <linux/lsm_count.h>
 
 #include "ipe.h"
 #include "hooks.h"
@@ -355,7 +356,8 @@ int ipe_inode_setintegrity(const struct inode *inode,
  * so that ipe_bpf_prog_load() can later read it for policy evaluation.
  *
  * Return:
- * * %0		- Always succeeds (policy is evaluated in bpf_prog_load)
+ * * %0		- Recorded the verdict (policy is evaluated in bpf_prog_load)
+ * * %-ENOMEM	- Exhausted room for recording verdicts
  */
 int ipe_bpf_prog_load_post_integrity(struct bpf_prog *prog,
 				     union bpf_attr *attr,
@@ -365,8 +367,14 @@ int ipe_bpf_prog_load_post_integrity(struct bpf_prog *prog,
 				     enum lsm_integrity_verdict verdict)
 {
 	struct ipe_bpf_prog *blob = ipe_bpf_prog(prog);
+	unsigned int count = blob->count;
 
-	blob->verdict = verdict;
+	if (count == MAX_LSM_COUNT)
+		return -ENOMEM;
+
+	blob->verdicts[count].lsmid = lsmid;
+	blob->verdicts[count].verdict = verdict;
+	blob->count++;
 
 	return 0;
 }
@@ -391,12 +399,18 @@ int ipe_bpf_prog_load(struct bpf_prog *prog,
 		      struct bpf_token *token,
 		      bool kernel)
 {
+	unsigned int iter;
 	struct ipe_bpf_prog *blob = ipe_bpf_prog(prog);
 	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 = blob->verdict;
+	ctx.bpf_verdict = LSM_INT_VERDICT_NONE;
+	for (iter = 0; iter < blob->count; iter++) {
+		/* pick the "wosrt" verdict */
+		if (blob->verdicts[iter].verdict > ctx.bpf_verdict)
+			ctx.bpf_verdict = blob->verdicts[iter].verdict;
+	}
 	ctx.bpf_keyring_id = attr->keyring_id;
 	ctx.bpf_kernel = kernel;
 
-- 
2.54.0




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