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>
Subject: [PATCH v2 04/15] lsm: Add the bpf_lsm_policy_release kfunc and policy object destructor
Date: Mon, 31 Aug 2026 10:58:46 -0400 [thread overview]
Message-ID: <20260831145858.3869191-5-utilityemal77@gmail.com> (raw)
In-Reply-To: <20260831145858.3869191-1-utilityemal77@gmail.com>
Add security/bpf_lsm_kfuncs.c, the home of the kfuncs exposing LSM
policy objects to BPF programs, with the first of them:
bpf_lsm_policy_release(object) KF_RELEASE
The kfuncs are the LSM framework's own BPF interface: there is no
per-LSM kfunc and no intermediate security_*() layer. Each kfunc
walks the matching hook's implementation list and calls the one
registered by the LSM whose lsmid the policy object carries. Calling
a kfunc for an LSM that is not active or has no policy object support
fails at runtime rather than hiding the kfunc at verification time,
so BPF program loading is independent of the boot-time LSM
configuration.
A policy object reference is meant to be handed over through a map
kptr field, so also register a destructor for struct
lsm_policy_object: map-held references are dropped on map teardown,
possibly from a context that cannot sleep, which the
policy_object_put() hook contract accounts for. For the same reason
the kfunc is not KF_SLEEPABLE, and the filter adds no per-kfunc rule:
releasing a reference must be allowed wherever one can be held. The
filter itself is needed because BPF_PROG_TYPE_LSM and
BPF_PROG_TYPE_SYSCALL, the two registered program types, share their
kfunc lookup buckets with other program types.
Cc: Paul Moore <paul@paul-moore.com>
Cc: KP Singh <kpsingh@kernel.org>
Signed-off-by: Justin Suess <utilityemal77@gmail.com>
---
MAINTAINERS | 1 +
security/Makefile | 2 +-
security/bpf_lsm_kfuncs.c | 98 +++++++++++++++++++++++++++++++++++++++
3 files changed, 100 insertions(+), 1 deletion(-)
create mode 100644 security/bpf_lsm_kfuncs.c
diff --git a/MAINTAINERS b/MAINTAINERS
index f5301c30ea91..2af6a25a1399 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5037,6 +5037,7 @@ F: kernel/bpf/bpf_lsm.c
F: kernel/bpf/bpf_lsm_proto.c
F: kernel/trace/bpf_trace.c
F: security/bpf/
+F: security/bpf_lsm_kfuncs.c
BPF [SELFTESTS] (Test Runners & Infrastructure)
M: Andrii Nakryiko <andrii@kernel.org>
diff --git a/security/Makefile b/security/Makefile
index 4601230ba442..a9364ea9828b 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -23,7 +23,7 @@ obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/
obj-$(CONFIG_SECURITY_SAFESETID) += safesetid/
obj-$(CONFIG_SECURITY_LOCKDOWN_LSM) += lockdown/
obj-$(CONFIG_CGROUPS) += device_cgroup.o
-obj-$(CONFIG_BPF_LSM) += bpf/
+obj-$(CONFIG_BPF_LSM) += bpf/ bpf_lsm_kfuncs.o
obj-$(CONFIG_SECURITY_LANDLOCK) += landlock/
obj-$(CONFIG_SECURITY_IPE) += ipe/
diff --git a/security/bpf_lsm_kfuncs.c b/security/bpf_lsm_kfuncs.c
new file mode 100644
index 000000000000..e1190215d477
--- /dev/null
+++ b/security/bpf_lsm_kfuncs.c
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* BPF kfuncs exposing LSM policy objects. */
+
+#include <linux/bpf.h>
+#include <linux/btf.h>
+#include <linux/btf_ids.h>
+#include <linux/cfi.h>
+#include <linux/init.h>
+#include <linux/lsm_hooks.h>
+#include <linux/security.h>
+
+#include "lsm.h"
+
+__bpf_kfunc_start_defs();
+
+/**
+ * bpf_lsm_policy_release - Release a policy object reference
+ * @object: policy object to release
+ *
+ * Release an acquired reference on a policy object.
+ */
+__bpf_kfunc void bpf_lsm_policy_release(struct lsm_policy_object *object)
+{
+ struct lsm_static_call *scall;
+
+ lsm_for_each_hook(scall, policy_object_put) {
+ if (scall->hl->lsmid->id != object->lsmid)
+ continue;
+ scall->hl->hook.policy_object_put(object);
+ return;
+ }
+ /* A held reference implies the owning LSM implements the hook. */
+ WARN_ON_ONCE(1);
+}
+
+/* Destructor for referenced lsm_policy_object kptrs. */
+__bpf_kfunc void bpf_lsm_policy_release_dtor(void *object)
+{
+ bpf_lsm_policy_release(object);
+}
+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_release, KF_RELEASE)
+BTF_KFUNCS_END(bpf_lsm_policy_kfunc_ids)
+
+BTF_ID_LIST(bpf_lsm_policy_dtor_ids)
+BTF_ID(struct, lsm_policy_object)
+BTF_ID(func, bpf_lsm_policy_release_dtor)
+
+/*
+ * 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.
+ */
+static int bpf_lsm_policy_kfunc_filter(const struct bpf_prog *prog,
+ u32 kfunc_id)
+{
+ if (!btf_id_set8_contains(&bpf_lsm_policy_kfunc_ids, kfunc_id))
+ return 0;
+
+ switch (prog->type) {
+ case BPF_PROG_TYPE_SYSCALL:
+ case BPF_PROG_TYPE_LSM:
+ return 0;
+ default:
+ return -EACCES;
+ }
+}
+
+static const struct btf_kfunc_id_set bpf_lsm_policy_kfunc_set = {
+ .owner = THIS_MODULE,
+ .set = &bpf_lsm_policy_kfunc_ids,
+ .filter = bpf_lsm_policy_kfunc_filter,
+};
+
+static int __init bpf_lsm_policy_kfunc_init(void)
+{
+ const struct btf_id_dtor_kfunc bpf_lsm_policy_dtors[] = {
+ {
+ .btf_id = bpf_lsm_policy_dtor_ids[0],
+ .kfunc_btf_id = bpf_lsm_policy_dtor_ids[1],
+ },
+ };
+ int ret;
+
+ ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_LSM,
+ &bpf_lsm_policy_kfunc_set);
+ ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL,
+ &bpf_lsm_policy_kfunc_set);
+ return ret ?: register_btf_id_dtor_kfuncs(bpf_lsm_policy_dtors,
+ ARRAY_SIZE(bpf_lsm_policy_dtors),
+ THIS_MODULE);
+}
+late_initcall(bpf_lsm_policy_kfunc_init);
--
2.55.0
next prev parent reply other threads:[~2026-08-31 14:59 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-31 14:58 [PATCH v2 00/15] BPF interface for applying Landlock rulesets Justin Suess
2026-08-31 14:58 ` [PATCH v2 01/15] lsm: Add the LSM policy object lifetime hooks Justin Suess
2026-08-31 17:17 ` Casey Schaufler
2026-08-31 17:41 ` Justin Suess
2026-09-02 13:05 ` Justin Suess
2026-09-02 17:51 ` Casey Schaufler
2026-09-02 18:28 ` Justin Suess
2026-08-31 14:58 ` [PATCH v2 02/15] lsm: Add the bprm_apply_policy_object LSM hook Justin Suess
2026-08-31 14:58 ` [PATCH v2 03/15] lsm: Move the lsm_for_each_hook() macro to security/lsm.h Justin Suess
2026-08-31 14:58 ` Justin Suess [this message]
2026-08-31 14:58 ` [PATCH v2 05/15] lsm: Add the bpf_lsm_policy_from_fd kfunc Justin Suess
2026-08-31 14:58 ` [PATCH v2 06/15] lsm: Add the bpf_lsm_policy_acquire kfunc Justin Suess
2026-08-31 14:58 ` [PATCH v2 07/15] lsm: Add the bpf_lsm_policy_apply_bprm kfunc Justin Suess
2026-08-31 14:58 ` [PATCH v2 08/15] lsm: Document the LSM policy object interface Justin Suess
2026-08-31 14:58 ` [PATCH v2 09/15] selftests/bpf: Add tests for the LSM policy object kfuncs Justin Suess
2026-08-31 14:58 ` [PATCH v2 10/15] landlock: Expose the ruleset fd lookup to the rest of Landlock Justin Suess
2026-08-31 14:58 ` [PATCH v2 11/15] landlock: Factor the credential restriction out of landlock_restrict_self() Justin Suess
2026-08-31 14:58 ` [PATCH v2 12/15] landlock: Free rulesets after an RCU grace period Justin Suess
2026-08-31 14:58 ` [PATCH v2 13/15] landlock: Implement the LSM policy object hooks Justin Suess
2026-08-31 14:58 ` [PATCH v2 14/15] selftests/bpf: Test the LSM policy object kfuncs with Landlock Justin Suess
[not found] ` <20260831195327.1282C1F000E9@smtp.kernel.org>
2026-09-02 12:24 ` Justin Suess
2026-08-31 14:58 ` [PATCH v2 15/15] landlock: Document the BPF policy interface 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=20260831145858.3869191-5-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=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