[PATCH v2 05/15] lsm: Add the bpf_lsm_policy_from_fd kfunc
From: Justin Suess
Date: Mon Aug 31 2026 - 18:11:42 EST
Add the kfunc translating a file descriptor into a referenced policy
object:
bpf_lsm_policy_from_fd(fd, flags)
KF_ACQUIRE|KF_RET_NULL|KF_SLEEPABLE
No argument names an LSM: a policy object fd refers to a file set up
through the owning LSM's own userspace interface so the fd itself
identifies the LSM asked to translate it. The kfunc offers the fd to
every policy_object_from_fd implementation in turn until one claims it.
Following the convention of the lsm_*(2) syscalls, @flags belongs to
the framework and is reserved: the kfunc returns NULL for @flags != 0.
A policy object fd is only meaningful in the fd table of the process
that set the object up, while an LSM program runs in the context of
the task it mediates, so the filter makes this kfunc exclusive to
syscall programs (BPF_PROG_TYPE_SYSCALL), which run in the context of
the task invoking them. The acquired object may be released with
bpf_lsm_policy_release().
Cc: Paul Moore <paul@xxxxxxxxxxxxxx>
Cc: KP Singh <kpsingh@xxxxxxxxxx>
Signed-off-by: Justin Suess <utilityemal77@xxxxxxxxx>
---
security/bpf_lsm_kfuncs.c | 53 +++++++++++++++++++++++++++++++++++++--
1 file changed, 51 insertions(+), 2 deletions(-)
diff --git a/security/bpf_lsm_kfuncs.c b/security/bpf_lsm_kfuncs.c
index e1190215d477..988dcd6f4dd9 100644
--- a/security/bpf_lsm_kfuncs.c
+++ b/security/bpf_lsm_kfuncs.c
@@ -14,11 +14,50 @@
__bpf_kfunc_start_defs();
+/**
+ * bpf_lsm_policy_from_fd - Get an LSM policy object from a fd
+ * @fd: file descriptor referring to a policy object, resolved in the
+ * file descriptor table of the task running the program
+ * @flags: reserved for future use, must be 0
+ *
+ * Translate @fd, as set up through the owning LSM's own userspace
+ * interface, into a referenced policy object. The fd identifies the
+ * LSM asked to translate it: each LSM recognizes its own fds and
+ * declines every other. Only syscall programs may call this kfunc:
+ * they run in the context of the task invoking them, where the fd is
+ * meaningful. The reference must be released with
+ * bpf_lsm_policy_release().
+ *
+ * Return: A referenced policy object, or NULL if @flags is not 0, if
+ * no enabled LSM recognizes @fd as one of its policy objects, or if
+ * the recognizing LSM fails to translate it.
+ */
+__bpf_kfunc struct lsm_policy_object *bpf_lsm_policy_from_fd(int fd, u32 flags)
+{
+ struct lsm_static_call *scall;
+ struct lsm_policy_object *object;
+ int err;
+
+ if (flags)
+ return NULL;
+
+ lsm_for_each_hook(scall, policy_object_from_fd) {
+ err = scall->hl->hook.policy_object_from_fd(fd, &object);
+ if (err == -EOPNOTSUPP)
+ /* Not this LSM's fd: let another claim it. */
+ continue;
+ if (err)
+ return NULL;
+ return object;
+ }
+ return NULL;
+}
+
/**
* bpf_lsm_policy_release - Release a policy object reference
* @object: policy object to release
*
- * Release an acquired reference on a policy object.
+ * Release a reference acquired with bpf_lsm_policy_from_fd().
*/
__bpf_kfunc void bpf_lsm_policy_release(struct lsm_policy_object *object)
{
@@ -44,6 +83,8 @@ CFI_NOSEAL(bpf_lsm_policy_release_dtor);
__bpf_kfunc_end_defs();
BTF_KFUNCS_START(bpf_lsm_policy_kfunc_ids)
+BTF_ID_FLAGS(func, bpf_lsm_policy_from_fd,
+ KF_ACQUIRE | KF_RET_NULL | KF_SLEEPABLE)
BTF_ID_FLAGS(func, bpf_lsm_policy_release, KF_RELEASE)
BTF_KFUNCS_END(bpf_lsm_policy_kfunc_ids)
@@ -51,10 +92,14 @@ BTF_ID_LIST(bpf_lsm_policy_dtor_ids)
BTF_ID(struct, lsm_policy_object)
BTF_ID(func, bpf_lsm_policy_release_dtor)
+BTF_ID_LIST_SINGLE(bpf_lsm_policy_from_fd_ids, func, bpf_lsm_policy_from_fd)
+
/*
* BPF_PROG_TYPE_LSM and BPF_PROG_TYPE_SYSCALL share their kfunc
* lookup buckets with other program types, so restricting the policy
- * kfuncs requires a filter.
+ * kfuncs requires a filter. A policy object fd is only meaningful in
+ * the fd table of the task that set the object up: the fd kfunc is
+ * exclusive to syscall programs, which run in that task's context.
*/
static int bpf_lsm_policy_kfunc_filter(const struct bpf_prog *prog,
u32 kfunc_id)
@@ -64,7 +109,11 @@ static int bpf_lsm_policy_kfunc_filter(const struct bpf_prog *prog,
switch (prog->type) {
case BPF_PROG_TYPE_SYSCALL:
+ return 0;
case BPF_PROG_TYPE_LSM:
+ if (kfunc_id == bpf_lsm_policy_from_fd_ids[0])
+ return -EACCES;
+
return 0;
default:
return -EACCES;
--
2.55.0