From: Justin Suess <utilityemal77@gmail.com>
To: ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org,
kpsingh@kernel.org, paul@paul-moore.com, mic@digikod.net,
viro@zeniv.linux.org.uk, brauner@kernel.org, kees@kernel.org
Cc: gnoack@google.com, jack@suse.cz, song@kernel.org,
yonghong.song@linux.dev, martin.lau@linux.dev, m@maowtm.org,
bpf@vger.kernel.org, linux-security-module@vger.kernel.org,
linux-kernel@vger.kernel.org,
Justin Suess <utilityemal77@gmail.com>,
Casey Schaufler <casey@schaufler-ca.com>
Subject: [PATCH bpf-next 01/13] lsm: Add LSM hook security_policy_kptr_from_fd
Date: Thu, 30 Jul 2026 22:20:34 -0400 [thread overview]
Message-ID: <20260731022047.189137-2-utilityemal77@gmail.com> (raw)
In-Reply-To: <20260731022047.189137-1-utilityemal77@gmail.com>
Add a generic LSM hook handing out a reference to an LSM policy
object on behalf of a kernel-internal caller:
security_policy_kptr_from_fd(lsmid, fd, &policy)
together with union lsm_policy_kptr, the tagged payload carrying such
a reference across the LSM boundary.
The union holds one per-LSM member; which member is valid is
determined by the lsmid the caller passes. The pointers the
members hold are the BTF-visible handles whose provenance the BPF
verifier guarantees, i.e. referenced kptrs, hence the hook naming:
the reference stays strongly typed from the BPF program through the
hook to the owning LSM, which resolves the handle to its internal
policy representation.
This hook backs BPF kfuncs: it lets an LSM hand out a reference to
one of its policy objects (identified by a file descriptor created
through the LSM's own userspace API) without exporting any symbol or
defining any BPF interface itself. The reference is released
through security_policy_kptr_put(), added by the next patch.
The hook uses targeted dispatch: the shim walks the hook list and only
calls the implementation registered by the LSM matching @lsmid,
following the security_getprocattr()/security_setprocattr() patterns
for generic hooks carrying LSM-specific payloads. When no active LSM
matches, the shim returns -EOPNOTSUPP: a kfunc call for an LSM that is
compiled out or not enabled fails at runtime rather than being hidden
from the BPF program at verification time. For the same reason the
union members are not guarded by the LSMs' CONFIG options: the
callers are built independently of any individual LSM.
The hook is excluded from the "bpf" LSM's attachment points. The
targeted dispatch would only reach a program attached there for calls
with LSM_ID_BPF, which no caller passes, so the attachment point would
be dead.
Cc: Paul Moore <paul@paul-moore.com>
Cc: Casey Schaufler <casey@schaufler-ca.com>
Signed-off-by: Justin Suess <utilityemal77@gmail.com>
---
Notes:
The hook naming choice of policy_kptr_from_fd and the other
hooks is up in the air for me. I decided to include the kptr
part in the name because it's relevant to the task being
performed: we are simply getting a pointer to a kernel policy
object from a file descriptor.
I'm open to better ideas for the name...
include/linux/lsm_hook_defs.h | 2 ++
include/linux/security.h | 25 +++++++++++++++++++++++
kernel/bpf/bpf_lsm.c | 1 +
security/security.c | 38 +++++++++++++++++++++++++++++++++++
4 files changed, 66 insertions(+)
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 65c9609ec207..afd5b3f932a9 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -452,6 +452,8 @@ LSM_HOOK(int, 0, bpf_token_create, struct bpf_token *token, union bpf_attr *attr
LSM_HOOK(void, LSM_RET_VOID, bpf_token_free, struct bpf_token *token)
LSM_HOOK(int, 0, bpf_token_cmd, const struct bpf_token *token, enum bpf_cmd cmd)
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)
#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 153e9043058f..db807e61d310 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -168,6 +168,23 @@ struct lsm_prop {
struct lsm_prop_bpf bpf;
};
+struct bpf_landlock_ruleset;
+
+struct lsm_policy_landlock {
+ struct bpf_landlock_ruleset *ruleset;
+};
+
+/*
+ * A reference to an LSM policy object, tagged by the LSM_ID_* value
+ * passed alongside: only the matching LSM's member is valid. The
+ * members are not guarded by the LSMs' CONFIG options: the callers
+ * are built independently of any individual LSM and a call for a
+ * missing LSM must fail at runtime, not at build time.
+ */
+union lsm_policy_kptr {
+ struct lsm_policy_landlock landlock;
+};
+
extern const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1];
/* These functions are in security/commoncap.c */
@@ -2312,6 +2329,8 @@ extern int security_bpf_token_create(struct bpf_token *token, union bpf_attr *at
extern void security_bpf_token_free(struct bpf_token *token);
extern int security_bpf_token_cmd(const struct bpf_token *token, enum bpf_cmd cmd);
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);
#else
static inline int security_bpf(int cmd, union bpf_attr *attr,
unsigned int size, bool kernel)
@@ -2365,6 +2384,12 @@ static inline int security_bpf_token_capable(const struct bpf_token *token, int
{
return 0;
}
+
+static inline int security_policy_kptr_from_fd(u64 lsmid, int fd,
+ union lsm_policy_kptr *policy)
+{
+ return -EOPNOTSUPP;
+}
#endif /* CONFIG_SECURITY */
#endif /* CONFIG_BPF_SYSCALL */
diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c
index 3983b4ce73c8..9fa514204fb5 100644
--- a/kernel/bpf/bpf_lsm.c
+++ b/kernel/bpf/bpf_lsm.c
@@ -56,6 +56,7 @@ BTF_ID(func, bpf_lsm_xfrm_decode_session)
#endif
BTF_ID(func, bpf_lsm_ismaclabel)
BTF_ID(func, bpf_lsm_file_alloc_security)
+BTF_ID(func, bpf_lsm_policy_kptr_from_fd)
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 71aea8fdf014..14fd8b878cd0 100644
--- a/security/security.c
+++ b/security/security.c
@@ -5441,6 +5441,44 @@ int security_bpf_token_capable(const struct bpf_token *token, int cap)
return call_int_hook(bpf_token_capable, token, cap);
}
+/**
+ * security_policy_kptr_from_fd() - Get an LSM policy object from a fd
+ * @lsmid: LSM_ID_* value of the LSM asked to interpret @fd
+ * @fd: file descriptor referring to a policy object, resolved in the
+ * calling task's file descriptor table
+ * @policy: receives the referenced policy object in the member of the
+ * LSM identified by @lsmid
+ *
+ * Ask the LSM identified by @lsmid to translate @fd into a reference
+ * counted policy object. The caller must not dereference the
+ * returned handle, must only hand it back to the same LSM, e.g.
+ * through security_bprm_enforce_policy_kptr(), and must release it
+ * with security_policy_kptr_put(). Only the hook implementation of
+ * the LSM identified by @lsmid is called. The hook is only called
+ * from a context that may sleep.
+ *
+ * An implementation must fill its own member of @policy with a
+ * reference that remains valid until it is released through the
+ * policy_kptr_put hook, and must not assume anything about @fd beyond
+ * what its own userspace API created it with.
+ *
+ * Return: Returns 0 if @policy holds a reference counted policy
+ * object, -EOPNOTSUPP if the LSM does not implement the hook, negative
+ * values on other failures.
+ */
+int security_policy_kptr_from_fd(u64 lsmid, int fd,
+ union lsm_policy_kptr *policy)
+{
+ struct lsm_static_call *scall;
+
+ lsm_for_each_hook(scall, policy_kptr_from_fd) {
+ if (scall->hl->lsmid->id != lsmid)
+ continue;
+ return scall->hl->hook.policy_kptr_from_fd(fd, policy);
+ }
+ return LSM_RET_DEFAULT(policy_kptr_from_fd);
+}
+
/**
* security_bpf_map_free() - Free a bpf map's LSM blob
* @map: bpf map
--
2.54.0
next prev parent reply other threads:[~2026-07-31 2:21 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-31 2:20 [PATCH bpf-next 00/13] BPF interface for applying Landlock rulesets Justin Suess
2026-07-31 2:20 ` Justin Suess [this message]
2026-07-31 2:20 ` [PATCH bpf-next 02/13] lsm: Add LSM hook security_policy_kptr_put Justin Suess
2026-07-31 2:44 ` sashiko-bot
2026-07-31 2:20 ` [PATCH bpf-next 03/13] lsm: Add LSM hook security_bprm_enforce_policy_kptr Justin Suess
2026-07-31 2:20 ` [PATCH bpf-next 04/13] landlock: Expose the ruleset fd lookup to the rest of Landlock Justin Suess
2026-07-31 2:20 ` [PATCH bpf-next 05/13] landlock: Factor the credential restriction out of landlock_restrict_self() Justin Suess
2026-07-31 2:20 ` [PATCH bpf-next 06/13] landlock: Implement the LSM policy kptr hooks Justin Suess
2026-07-31 2:20 ` [PATCH bpf-next 07/13] bpf: Add the LSM policy kfunc infrastructure Justin Suess
2026-07-31 2:20 ` [PATCH bpf-next 08/13] bpf: Add the bpf_landlock_put_ruleset kfunc and ruleset destructor Justin Suess
2026-07-31 2:46 ` sashiko-bot
2026-07-31 2:20 ` [PATCH bpf-next 09/13] bpf: Add the bpf_landlock_get_ruleset_from_fd kfunc Justin Suess
2026-07-31 2:20 ` [PATCH bpf-next 10/13] bpf: Add the bpf_landlock_restrict_binprm kfunc Justin Suess
2026-07-31 2:46 ` sashiko-bot
2026-07-31 2:20 ` [PATCH bpf-next 11/13] selftests/bpf: Add tests for the Landlock policy kfuncs Justin Suess
2026-07-31 2:20 ` [PATCH bpf-next 12/13] landlock: Document the BPF kfunc interface Justin Suess
2026-07-31 2:45 ` sashiko-bot
2026-07-31 2:20 ` [PATCH bpf-next 13/13] lsm: Document the LSM policy kptr hooks Justin Suess
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=20260731022047.189137-2-utilityemal77@gmail.com \
--to=utilityemal77@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=brauner@kernel.org \
--cc=casey@schaufler-ca.com \
--cc=daniel@iogearbox.net \
--cc=gnoack@google.com \
--cc=jack@suse.cz \
--cc=kees@kernel.org \
--cc=kpsingh@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=m@maowtm.org \
--cc=martin.lau@linux.dev \
--cc=mic@digikod.net \
--cc=paul@paul-moore.com \
--cc=song@kernel.org \
--cc=viro@zeniv.linux.org.uk \
--cc=yonghong.song@linux.dev \
/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