[PATCH bpf-next 03/13] lsm: Add LSM hook security_bprm_enforce_policy_kptr

Justin Suess utilityemal77 at gmail.com
Fri Jul 31 02:20:36 UTC 2026


Add a generic LSM hook enforcing an LSM policy object on the
credentials prepared for an execution:

  security_bprm_enforce_policy_kptr(lsmid, bprm, &policy, flags)

The policy object is obtained from the owning LSM through
security_policy_kptr_from_fd(), travels in that LSM's member of
union lsm_policy_kptr, and is handed back only to that same LSM: the
shim uses the same targeted dispatch by @lsmid as the policy kptr
lifetime hooks, and returns -EOPNOTSUPP when no active LSM matches.

This is the first policy operation backed by the BPF-owned LSM
kfuncs: it lets a sleepable LSM BPF program attached to
bprm_creds_for_exec() or bprm_creds_from_file() arrange for the
executed task to start confined by a policy created through the LSM's
own userspace API, e.g. a Landlock ruleset applied to a binprm.  The
BPF-facing kfunc keeps the policy pointer strongly BTF-typed all the
way to the union member the implementing LSM reads back.

The hook contract is LSM agnostic: any LSM with a notion of a
per-task policy object can implement it, with its own semantics for
how the policy composes with restrictions the credentials already
carry and for the meaning of @flags, unsupported values of which it
must reject with -EINVAL.  Implementations can rely on being called
only between the preparation and the commitment of the bprm's
credentials.

Like the policy kptr lifetime hooks, this hook is excluded from the
"bpf" LSM's attachment points, as the targeted dispatch makes an
attachment there unreachable.

Cc: Paul Moore <paul at paul-moore.com>
Cc: Casey Schaufler <casey at schaufler-ca.com>
Signed-off-by: Justin Suess <utilityemal77 at gmail.com>
---
 include/linux/lsm_hook_defs.h |  2 ++
 include/linux/security.h      | 12 ++++++++++
 kernel/bpf/bpf_lsm.c          |  1 +
 security/security.c           | 41 +++++++++++++++++++++++++++++++++++
 4 files changed, 56 insertions(+)

diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 0800622e317f..a70edbd7b761 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -455,6 +455,8 @@ LSM_HOOK(int, 0, bpf_token_capable, const struct bpf_token *token, int cap)
 LSM_HOOK(int, -EOPNOTSUPP, policy_kptr_from_fd, int fd,
 	 union lsm_policy_kptr *policy)
 LSM_HOOK(void, LSM_RET_VOID, policy_kptr_put, union lsm_policy_kptr *policy)
+LSM_HOOK(int, -EOPNOTSUPP, bprm_enforce_policy_kptr, struct linux_binprm *bprm,
+	 union lsm_policy_kptr *policy, u32 flags)
 #endif /* CONFIG_BPF_SYSCALL */
 
 LSM_HOOK(int, 0, locked_down, enum lockdown_reason what)
diff --git a/include/linux/security.h b/include/linux/security.h
index 5017a335918c..40dfa96b6a71 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -2332,6 +2332,10 @@ extern int security_bpf_token_capable(const struct bpf_token *token, int cap);
 extern int security_policy_kptr_from_fd(u64 lsmid, int fd,
 					union lsm_policy_kptr *policy);
 extern void security_policy_kptr_put(u64 lsmid, union lsm_policy_kptr *policy);
+extern int security_bprm_enforce_policy_kptr(u64 lsmid,
+					     struct linux_binprm *bprm,
+					     union lsm_policy_kptr *policy,
+					     u32 flags);
 #else
 static inline int security_bpf(int cmd, union bpf_attr *attr,
 			       unsigned int size, bool kernel)
@@ -2396,6 +2400,14 @@ static inline void security_policy_kptr_put(u64 lsmid,
 					    union lsm_policy_kptr *policy)
 {
 }
+
+static inline int security_bprm_enforce_policy_kptr(u64 lsmid,
+						    struct linux_binprm *bprm,
+						    union lsm_policy_kptr *policy,
+						    u32 flags)
+{
+	return -EOPNOTSUPP;
+}
 #endif /* CONFIG_SECURITY */
 #endif /* CONFIG_BPF_SYSCALL */
 
diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c
index e9059d43e92c..d847a180489f 100644
--- a/kernel/bpf/bpf_lsm.c
+++ b/kernel/bpf/bpf_lsm.c
@@ -58,6 +58,7 @@ BTF_ID(func, bpf_lsm_ismaclabel)
 BTF_ID(func, bpf_lsm_file_alloc_security)
 BTF_ID(func, bpf_lsm_policy_kptr_from_fd)
 BTF_ID(func, bpf_lsm_policy_kptr_put)
+BTF_ID(func, bpf_lsm_bprm_enforce_policy_kptr)
 BTF_SET_END(bpf_lsm_disabled_hooks)
 
 /* List of LSM hooks that should operate on 'current' cgroup regardless
diff --git a/security/security.c b/security/security.c
index fd535bd00c24..e9d8c9492bdb 100644
--- a/security/security.c
+++ b/security/security.c
@@ -5506,6 +5506,47 @@ void security_policy_kptr_put(u64 lsmid, union lsm_policy_kptr *policy)
 	WARN_ON_ONCE(1);
 }
 
+/**
+ * security_bprm_enforce_policy_kptr() - Enforce a policy on exec credentials
+ * @lsmid: LSM_ID_* value of the LSM owning @policy
+ * @bprm: execution context providing the prepared credentials to restrict
+ * @policy: the policy object to enforce, in the member of the LSM
+ *          identified by @lsmid
+ * @flags: LSM-specific enforcement flags
+ *
+ * Ask the LSM identified by @lsmid to restrict the credentials
+ * prepared in @bprm with @policy, so that the executed task starts
+ * confined by it.  @policy must have been obtained from the same LSM
+ * with security_policy_kptr_from_fd(); the hook borrows the
+ * reference and the caller remains responsible for releasing it.
+ * Only the hook implementation of the LSM identified by @lsmid is
+ * called: an LSM never receives a policy object meant for another LSM.
+ *
+ * This hook may only be called from an exec security context where
+ * @bprm's credentials are prepared but not yet committed, i.e. from a
+ * bprm_creds_for_exec() or bprm_creds_from_file() hook.
+ *
+ * How @policy composes with restrictions the credentials already
+ * carry is defined by the implementing LSM, as is the meaning of
+ * @flags, unsupported values of which it must reject with -EINVAL.
+ *
+ * Return: Returns 0 on success, -EOPNOTSUPP if the LSM does not
+ * implement the hook, negative values on other failures.
+ */
+int security_bprm_enforce_policy_kptr(u64 lsmid, struct linux_binprm *bprm,
+				      union lsm_policy_kptr *policy, u32 flags)
+{
+	struct lsm_static_call *scall;
+
+	lsm_for_each_hook(scall, bprm_enforce_policy_kptr) {
+		if (scall->hl->lsmid->id != lsmid)
+			continue;
+		return scall->hl->hook.bprm_enforce_policy_kptr(bprm, policy,
+								 flags);
+	}
+	return LSM_RET_DEFAULT(bprm_enforce_policy_kptr);
+}
+
 /**
  * security_bpf_map_free() - Free a bpf map's LSM blob
  * @map: bpf map
-- 
2.54.0




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