[PATCH bpf-next 1/2] lsm: add bpf_security_locked_down() kfunc

Justin Suess <[email protected]>
Newsgroups gmane.linux.kernel.lsm,gmane.linux.kernel,gmane.linux.kernel.bpf
Message-ID <[email protected]>
Add a new kfunc bpf_security_locked_down, which calls
security_locked_down and returns the result.

Create a new file security/lsm_kfuncs.c for LSM framework kfuncs.

Reject reasons outside (LOCKDOWN_NONE, LOCKDOWN_CONFIDENTIALITY_MAX)
with -EINVAL before dispatching the hook. Limit the kfunc to
BPF_PROG_TYPE_LSM and BPF_PROG_TYPE_SYSCALL programs, and refuse it
to programs attached to the locked_down hook itself, which would
recurse into the dispatch.

Signed-off-by: Justin Suess <[email protected]>
---
 security/Makefile     |  1 +
 security/lsm_kfuncs.c | 84 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 85 insertions(+)
 create mode 100644 security/lsm_kfuncs.c

diff --git a/security/Makefile b/security/Makefile
index 4601230ba442..dee8ff218548 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_MMU)			+= min_addr.o
 
 # Object file lists
 obj-$(CONFIG_SECURITY)			+= security.o lsm_notifier.o lsm_init.o
+obj-$(CONFIG_BPF_SYSCALL)		+= lsm_kfuncs.o
 obj-$(CONFIG_SECURITYFS)		+= inode.o
 obj-$(CONFIG_SECURITY_SELINUX)		+= selinux/
 obj-$(CONFIG_SECURITY_SMACK)		+= smack/
diff --git a/security/lsm_kfuncs.c b/security/lsm_kfuncs.c
new file mode 100644
index 000000000000..a324e7d978ca
--- /dev/null
+++ b/security/lsm_kfuncs.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * kfuncs exposing LSM interfaces to BPF programs.
+ *
+ * Copyright (C) 2026 Justin Suess
+ */
+#include <linux/bpf.h>
+#include <linux/btf.h>
+#include <linux/btf_ids.h>
+#include <linux/init.h>
+#include <linux/security.h>
+
+__bpf_kfunc_start_defs();
+
+/**
+ * bpf_security_locked_down - Call the security_locked_down() LSM hook
+ * @what: lockdown reason to query
+ *
+ * Return: 0 if @what is not locked down, -EPERM if it is, or -EINVAL if
+ * @what is outside (LOCKDOWN_NONE, LOCKDOWN_CONFIDENTIALITY_MAX).
+ */
+__bpf_kfunc int bpf_security_locked_down(enum lockdown_reason what)
+{
+	if (what <= LOCKDOWN_NONE || what >= LOCKDOWN_CONFIDENTIALITY_MAX)
+		return -EINVAL;
+	return security_locked_down(what);
+}
+
+__bpf_kfunc_end_defs();
+
+BTF_KFUNCS_START(lsm_kfunc_ids)
+BTF_ID_FLAGS(func, bpf_security_locked_down)
+BTF_KFUNCS_END(lsm_kfunc_ids)
+
+#ifdef CONFIG_BPF_LSM
+BTF_ID_LIST_SINGLE(lsm_locked_down_hook_id, func, bpf_lsm_locked_down)
+#endif
+
+static int lsm_kfunc_filter(const struct bpf_prog *prog, u32 kfunc_id)
+{
+	/* Filters run for every kfunc resolved through the hook. */
+	if (!btf_id_set8_contains(&lsm_kfunc_ids, kfunc_id))
+		return 0;
+
+	/*
+	 * Raw prog->type: keep out the rest of the shared tracing kfunc
+	 * set (incl. perf/NMI) and extension programs.
+	 */
+	switch (prog->type) {
+	case BPF_PROG_TYPE_SYSCALL:
+		return 0;
+#ifdef CONFIG_BPF_LSM
+	case BPF_PROG_TYPE_LSM:
+		/*
+		 * A locked_down program calling this kfunc would recurse.
+		 * Match on attach_btf_id: attach_func_name is not yet set
+		 * when the filter runs from check_cfg.
+		 */
+		if (prog->aux->attach_btf_id == lsm_locked_down_hook_id[0])
+			return -EACCES;
+		return 0;
+#endif
+	default:
+		return -EACCES;
+	}
+}
+
+static const struct btf_kfunc_id_set lsm_kfunc_set = {
+	.owner  = THIS_MODULE,
+	.set    = &lsm_kfunc_ids,
+	.filter = lsm_kfunc_filter,
+};
+
+static int __init lsm_kfuncs_init(void)
+{
+	int err;
+
+	err = register_btf_kfunc_id_set(BPF_PROG_TYPE_LSM, &lsm_kfunc_set);
+	err = err ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &lsm_kfunc_set);
+	if (err)
+		pr_warn("lsm_kfuncs: kfunc registration failed: %d\n", err);
+	return err;
+}
+late_initcall(lsm_kfuncs_init);
-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.