linux-integrity.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 0/29] Rework the LSM initialization
@ 2025-04-09 18:49 Paul Moore
  2025-04-09 18:49 ` [RFC PATCH 01/29] lsm: split the notifier code out into lsm_notifier.c Paul Moore
                   ` (29 more replies)
  0 siblings, 30 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:49 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

This is one of those patchsets that started out small and then quickly
expanded to what you see here.  I will warn you that some of the
individual patches are a bit ugly to look at, but I believe the end
result is much cleaner than what we have now, fixes some odd/undesirable
behavior on boot, and enables some new functionality.

The most obvious changes are the extraction of the LSM notifier and
initialization code out of security/security.c and into their own files,
security/lsm_notifier.c and security/lsm_init.c.  While not strictly
necessary, I think we can all agree that security/security.c has grown
to be a bit of a mess, and these are two bits of functionality which
can be extracted out into their own files without too much fuss.  I
personally find this to be a nice quality-of-life improvement, and while
I'm open to keeping everything in security.c, the argument for doing so
is going to need to be *very* persuasive.

The other significant change is moving all of the LSM initcalls into the
LSM framework.  While I've always pushed to keep the LSM framework as
minimal as possible, there are some things that we really can't defer to
the individual LSMs and with the LSM framework responsible for enabling
or disabling the individual LSMs at boot, I believe management and
execution of the LSM initcalls needs to be handled in the framework as
well.  Not only does this move ensure that we aren't running initcalls
for LSMs which are disabled, it also provides us with a convenient spot
to signal when all of the LSMs have been actived (see the LSM_STARTED_ALL
patch towards the end of the patchset).  This is not a feature we
currently need, but I'm aware of some future work that does require this
so I thought it would be good to think about it now while doing this
work.

Related to the LSM_STARTED_ALL patch, the final patch in this series
adds support for LSMs to indicate if they provide lsm_prop values for
subjects and/or objects.  Casey needs this functionality for his recent
audit changes, and I personally find the counting approach presented
here to be ... less ugly I guess?

This patchset is marked as a RFC for a number of reasons: additional
testing is required, the commit descriptions could benefit from some
extra attention, and I still have hopes that some of the individual
patches could be cleaned up a bit (I still like the end result, but how
we get there could be improved).  I would really appreciate if the
individual LSM maintainers could give this a quick look, especially
the individual LSM patches that move the initcalls into the LSM
framework as some of those are non-trivial.  Mimi and Roberto, the
IMA/EVM work here was particularly "fun"; from what I've seen thus far
it appears to work correctly, but I have no idea if that code is good
or bad from you perspective.  It's perfectly okay if you want to
reject the approach taken in IMA/EVM, but we do need to move the
initcalls up to the LSM framework, so please suggest some code that
would allow us to do that for IMA/EVM.

--
Paul Moore (29):
      lsm: split the notifier code out into lsm_notifier.c
      lsm: split the init code out into lsm_init.c
      lsm: simplify prepare_lsm() and rename to lsm_prep_single()
      lsm: simplify ordered_lsm_init() and rename to lsm_init_ordered()
      lsm: replace the name field with a pointer to the lsm_id struct
      lsm: cleanup and normalize the LSM order symbols naming
      lsm: rework lsm_active_cnt and lsm_idlist[]
      lsm: get rid of the lsm_names list and do some cleanup
      lsm: cleanup and normalize the LSM enabled functions
      lsm: cleanup the LSM blob size code
      lsm: cleanup initialize_lsm() and rename to lsm_init_single()
      lsm: cleanup the LSM ordered parsing
      lsm: fold lsm_init_ordered() into security_init()
      lsm: add missing function header comment blocks in lsm_init.c
      lsm: cleanup the debug and console output in lsm_init.c
      lsm: output available LSMs when debugging
      lsm: introduce an initcall mechanism into the LSM framework
      loadpin: move initcalls to the LSM framework
      ipe: move initcalls to the LSM framework
      smack: move initcalls to the LSM framework
      tomoyo: move initcalls to the LSM framework
      safesetid: move initcalls to the LSM framework
      apparmor: move initcalls to the LSM framework
      lockdown: move initcalls to the LSM framework
      ima,evm: move initcalls to the LSM framework
      selinux: move initcalls to the LSM framework
      lsm: consolidate all of the LSM framework initcalls
      lsm: add a LSM_STARTED_ALL notification event
      lsm: add support for counting lsm_prop support among LSMs

 include/linux/lsm_hooks.h                            |   73 -
 include/linux/security.h                             |    3 
 security/Makefile                                    |    2 
 security/apparmor/apparmorfs.c                       |    4 
 security/apparmor/crypto.c                           |    4 
 security/apparmor/include/apparmorfs.h               |    2 
 security/apparmor/include/crypto.h                   |    1 
 security/apparmor/lsm.c                              |   12 
 security/bpf/hooks.c                                 |    3 
 security/commoncap.c                                 |    3 
 security/inode.c                                     |   29 
 security/integrity/Makefile                          |    2 
 security/integrity/evm/evm_main.c                    |   10 
 security/integrity/iint.c                            |    4 
 security/integrity/ima/ima_main.c                    |   10 
 security/integrity/ima/ima_mok.c                     |    4 
 security/integrity/initcalls.c                       |   97 +
 security/integrity/initcalls.h                       |   23 
 security/integrity/platform_certs/load_ipl_s390.c    |    4 
 security/integrity/platform_certs/load_powerpc.c     |    4 
 security/integrity/platform_certs/load_uefi.c        |    4 
 security/integrity/platform_certs/machine_keyring.c  |    4 
 security/integrity/platform_certs/platform_keyring.c |   14 
 security/ipe/fs.c                                    |    4 
 security/ipe/ipe.c                                   |    4 
 security/ipe/ipe.h                                   |    2 
 security/landlock/setup.c                            |    3 
 security/loadpin/loadpin.c                           |   16 
 security/lockdown/lockdown.c                         |    6 
 security/lsm.h                                       |   46 
 security/lsm_init.c                                  |  566 ++++++++++
 security/lsm_notifier.c                              |   31 
 security/lsm_syscalls.c                              |    8 
 security/min_addr.c                                  |    5 
 security/safesetid/lsm.c                             |    4 
 security/safesetid/lsm.h                             |    2 
 security/safesetid/securityfs.c                      |    3 
 security/security.c                                  |  620 -----------
 security/selinux/Makefile                            |    2 
 security/selinux/hooks.c                             |   12 
 security/selinux/ibpkey.c                            |    5 
 security/selinux/include/audit.h                     |    5 
 security/selinux/include/initcalls.h                 |   19 
 security/selinux/initcalls.c                         |   50 
 security/selinux/netif.c                             |    5 
 security/selinux/netlink.c                           |    5 
 security/selinux/netnode.c                           |    5 
 security/selinux/netport.c                           |    5 
 security/selinux/selinuxfs.c                         |    5 
 security/selinux/ss/services.c                       |   26 
 security/smack/smack.h                               |    6 
 security/smack/smack_lsm.c                           |   19 
 security/smack/smack_netfilter.c                     |    4 
 security/smack/smackfs.c                             |    4 
 security/tomoyo/common.h                             |    2 
 security/tomoyo/securityfs_if.c                      |    4 
 security/tomoyo/tomoyo.c                             |    4 
 security/yama/yama_lsm.c                             |    3 
 58 files changed, 1102 insertions(+), 724 deletions(-)


^ permalink raw reply	[flat|nested] 126+ messages in thread

* [RFC PATCH 01/29] lsm: split the notifier code out into lsm_notifier.c
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
@ 2025-04-09 18:49 ` Paul Moore
  2025-04-09 21:17   ` Kees Cook
  2025-04-15 12:14   ` John Johansen
  2025-04-09 18:49 ` [RFC PATCH 02/29] lsm: split the init code out into lsm_init.c Paul Moore
                   ` (28 subsequent siblings)
  29 siblings, 2 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:49 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

In an effort to decompose security/security.c somewhat to make it less
twisted and unwieldy, pull out the LSM notifier code into a new file
as it is fairly well self-contained.

No code changes.

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 security/Makefile       |  2 +-
 security/lsm_notifier.c | 31 +++++++++++++++++++++++++++++++
 security/security.c     | 23 -----------------------
 3 files changed, 32 insertions(+), 24 deletions(-)
 create mode 100644 security/lsm_notifier.c

diff --git a/security/Makefile b/security/Makefile
index 22ff4c8bd8ce..14d87847bce8 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -11,7 +11,7 @@ obj-$(CONFIG_SECURITY) 			+= lsm_syscalls.o
 obj-$(CONFIG_MMU)			+= min_addr.o
 
 # Object file lists
-obj-$(CONFIG_SECURITY)			+= security.o
+obj-$(CONFIG_SECURITY)			+= security.o lsm_notifier.o
 obj-$(CONFIG_SECURITYFS)		+= inode.o
 obj-$(CONFIG_SECURITY_SELINUX)		+= selinux/
 obj-$(CONFIG_SECURITY_SMACK)		+= smack/
diff --git a/security/lsm_notifier.c b/security/lsm_notifier.c
new file mode 100644
index 000000000000..c92fad5d57d4
--- /dev/null
+++ b/security/lsm_notifier.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * LSM notifier functions
+ *
+ */
+
+#include <linux/notifier.h>
+#include <linux/security.h>
+
+static BLOCKING_NOTIFIER_HEAD(blocking_lsm_notifier_chain);
+
+int call_blocking_lsm_notifier(enum lsm_event event, void *data)
+{
+	return blocking_notifier_call_chain(&blocking_lsm_notifier_chain,
+					    event, data);
+}
+EXPORT_SYMBOL(call_blocking_lsm_notifier);
+
+int register_blocking_lsm_notifier(struct notifier_block *nb)
+{
+	return blocking_notifier_chain_register(&blocking_lsm_notifier_chain,
+						nb);
+}
+EXPORT_SYMBOL(register_blocking_lsm_notifier);
+
+int unregister_blocking_lsm_notifier(struct notifier_block *nb)
+{
+	return blocking_notifier_chain_unregister(&blocking_lsm_notifier_chain,
+						  nb);
+}
+EXPORT_SYMBOL(unregister_blocking_lsm_notifier);
diff --git a/security/security.c b/security/security.c
index fb57e8fddd91..477be0a17e3f 100644
--- a/security/security.c
+++ b/security/security.c
@@ -90,8 +90,6 @@ const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX + 1] = {
 	[LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality",
 };
 
-static BLOCKING_NOTIFIER_HEAD(blocking_lsm_notifier_chain);
-
 static struct kmem_cache *lsm_file_cache;
 static struct kmem_cache *lsm_inode_cache;
 
@@ -643,27 +641,6 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
 	}
 }
 
-int call_blocking_lsm_notifier(enum lsm_event event, void *data)
-{
-	return blocking_notifier_call_chain(&blocking_lsm_notifier_chain,
-					    event, data);
-}
-EXPORT_SYMBOL(call_blocking_lsm_notifier);
-
-int register_blocking_lsm_notifier(struct notifier_block *nb)
-{
-	return blocking_notifier_chain_register(&blocking_lsm_notifier_chain,
-						nb);
-}
-EXPORT_SYMBOL(register_blocking_lsm_notifier);
-
-int unregister_blocking_lsm_notifier(struct notifier_block *nb)
-{
-	return blocking_notifier_chain_unregister(&blocking_lsm_notifier_chain,
-						  nb);
-}
-EXPORT_SYMBOL(unregister_blocking_lsm_notifier);
-
 /**
  * lsm_blob_alloc - allocate a composite blob
  * @dest: the destination for the blob
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 02/29] lsm: split the init code out into lsm_init.c
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
  2025-04-09 18:49 ` [RFC PATCH 01/29] lsm: split the notifier code out into lsm_notifier.c Paul Moore
@ 2025-04-09 18:49 ` Paul Moore
  2025-04-09 21:18   ` Kees Cook
  2025-04-15 22:01   ` John Johansen
  2025-04-09 18:49 ` [RFC PATCH 03/29] lsm: simplify prepare_lsm() and rename to lsm_prep_single() Paul Moore
                   ` (27 subsequent siblings)
  29 siblings, 2 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:49 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

Continue to pull code out of security/security.c to help improve
readability by pulling all of the LSM framework initialization
code out into a new file.

No code changes.

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 include/linux/lsm_hooks.h |   3 +-
 security/Makefile         |   2 +-
 security/lsm.h            |  22 ++
 security/lsm_init.c       | 537 ++++++++++++++++++++++++++++++++++
 security/security.c       | 591 +++-----------------------------------
 5 files changed, 595 insertions(+), 560 deletions(-)
 create mode 100644 security/lsm.h
 create mode 100644 security/lsm_init.c

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 090d1d3e19fe..eeb4bfd60b79 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -167,11 +167,10 @@ struct lsm_info {
 		__used __section(".early_lsm_info.init")		\
 		__aligned(sizeof(unsigned long))
 
+
 /* DO NOT tamper with these variables outside of the LSM framework */
 extern char *lsm_names;
 extern struct lsm_static_calls_table static_calls_table __ro_after_init;
-extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
-extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
 
 /**
  * lsm_get_xattr_slot - Return the next available slot and increment the index
diff --git a/security/Makefile b/security/Makefile
index 14d87847bce8..4601230ba442 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -11,7 +11,7 @@ obj-$(CONFIG_SECURITY) 			+= lsm_syscalls.o
 obj-$(CONFIG_MMU)			+= min_addr.o
 
 # Object file lists
-obj-$(CONFIG_SECURITY)			+= security.o lsm_notifier.o
+obj-$(CONFIG_SECURITY)			+= security.o lsm_notifier.o lsm_init.o
 obj-$(CONFIG_SECURITYFS)		+= inode.o
 obj-$(CONFIG_SECURITY_SELINUX)		+= selinux/
 obj-$(CONFIG_SECURITY_SMACK)		+= smack/
diff --git a/security/lsm.h b/security/lsm.h
new file mode 100644
index 000000000000..0e1731bad4a7
--- /dev/null
+++ b/security/lsm.h
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * LSM functions
+ */
+
+#ifndef _LSM_H_
+#define _LSM_H_
+
+#include <linux/lsm_hooks.h>
+
+/* LSM blob configuration */
+extern struct lsm_blob_sizes blob_sizes;
+
+/* LSM blob caches */
+extern struct kmem_cache *lsm_file_cache;
+extern struct kmem_cache *lsm_inode_cache;
+
+/* LSM blob allocators */
+int lsm_cred_alloc(struct cred *cred, gfp_t gfp);
+int lsm_task_alloc(struct task_struct *task);
+
+#endif /* _LSM_H_ */
diff --git a/security/lsm_init.c b/security/lsm_init.c
new file mode 100644
index 000000000000..70e7d4207dae
--- /dev/null
+++ b/security/lsm_init.c
@@ -0,0 +1,537 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * LSM initialization functions
+ */
+
+#define pr_fmt(fmt) "LSM: " fmt
+
+#include <linux/init.h>
+#include <linux/lsm_hooks.h>
+
+#include "lsm.h"
+
+char *lsm_names;
+
+/* Pointers to LSM sections defined in include/asm-generic/vmlinux.lds.h */
+extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
+extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
+
+/* Boot-time LSM user choice */
+static __initconst const char *const builtin_lsm_order = CONFIG_LSM;
+static __initdata const char *chosen_lsm_order;
+static __initdata const char *chosen_major_lsm;
+
+/* Ordered list of LSMs to initialize. */
+static __initdata struct lsm_info *ordered_lsms[MAX_LSM_COUNT + 1];
+static __initdata struct lsm_info *exclusive;
+
+static __initdata bool debug;
+#define init_debug(...)							\
+	do {								\
+		if (debug)						\
+			pr_info(__VA_ARGS__);				\
+	} while (0)
+
+static int lsm_append(const char *new, char **result);
+
+/* Save user chosen LSM */
+static int __init choose_major_lsm(char *str)
+{
+	chosen_major_lsm = str;
+	return 1;
+}
+__setup("security=", choose_major_lsm);
+
+/* Explicitly choose LSM initialization order. */
+static int __init choose_lsm_order(char *str)
+{
+	chosen_lsm_order = str;
+	return 1;
+}
+__setup("lsm=", choose_lsm_order);
+
+/* Enable LSM order debugging. */
+static int __init enable_debug(char *str)
+{
+	debug = true;
+	return 1;
+}
+__setup("lsm.debug", enable_debug);
+
+/* Mark an LSM's enabled flag. */
+static int lsm_enabled_true __initdata = 1;
+static int lsm_enabled_false __initdata = 0;
+static void __init set_enabled(struct lsm_info *lsm, bool enabled)
+{
+	/*
+	 * When an LSM hasn't configured an enable variable, we can use
+	 * a hard-coded location for storing the default enabled state.
+	 */
+	if (!lsm->enabled) {
+		if (enabled)
+			lsm->enabled = &lsm_enabled_true;
+		else
+			lsm->enabled = &lsm_enabled_false;
+	} else if (lsm->enabled == &lsm_enabled_true) {
+		if (!enabled)
+			lsm->enabled = &lsm_enabled_false;
+	} else if (lsm->enabled == &lsm_enabled_false) {
+		if (enabled)
+			lsm->enabled = &lsm_enabled_true;
+	} else {
+		*lsm->enabled = enabled;
+	}
+}
+
+static inline bool is_enabled(struct lsm_info *lsm)
+{
+	if (!lsm->enabled)
+		return false;
+
+	return *lsm->enabled;
+}
+
+/* Is an LSM already listed in the ordered LSMs list? */
+static bool __init exists_ordered_lsm(struct lsm_info *lsm)
+{
+	struct lsm_info **check;
+
+	for (check = ordered_lsms; *check; check++)
+		if (*check == lsm)
+			return true;
+
+	return false;
+}
+
+/* Append an LSM to the list of ordered LSMs to initialize. */
+static int last_lsm __initdata;
+static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
+{
+	/* Ignore duplicate selections. */
+	if (exists_ordered_lsm(lsm))
+		return;
+
+	if (WARN(last_lsm == MAX_LSM_COUNT, "%s: out of LSM static calls!?\n", from))
+		return;
+
+	/* Enable this LSM, if it is not already set. */
+	if (!lsm->enabled)
+		lsm->enabled = &lsm_enabled_true;
+	ordered_lsms[last_lsm++] = lsm;
+
+	init_debug("%s ordered: %s (%s)\n", from, lsm->name,
+		   is_enabled(lsm) ? "enabled" : "disabled");
+}
+
+/* Is an LSM allowed to be initialized? */
+static bool __init lsm_allowed(struct lsm_info *lsm)
+{
+	/* Skip if the LSM is disabled. */
+	if (!is_enabled(lsm))
+		return false;
+
+	/* Not allowed if another exclusive LSM already initialized. */
+	if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
+		init_debug("exclusive disabled: %s\n", lsm->name);
+		return false;
+	}
+
+	return true;
+}
+
+static void __init lsm_set_blob_size(int *need, int *lbs)
+{
+	int offset;
+
+	if (*need <= 0)
+		return;
+
+	offset = ALIGN(*lbs, sizeof(void *));
+	*lbs = offset + *need;
+	*need = offset;
+}
+
+static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
+{
+	if (!needed)
+		return;
+
+	lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
+	lsm_set_blob_size(&needed->lbs_file, &blob_sizes.lbs_file);
+	lsm_set_blob_size(&needed->lbs_ib, &blob_sizes.lbs_ib);
+	/*
+	 * The inode blob gets an rcu_head in addition to
+	 * what the modules might need.
+	 */
+	if (needed->lbs_inode && blob_sizes.lbs_inode == 0)
+		blob_sizes.lbs_inode = sizeof(struct rcu_head);
+	lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
+	lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
+	lsm_set_blob_size(&needed->lbs_key, &blob_sizes.lbs_key);
+	lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
+	lsm_set_blob_size(&needed->lbs_perf_event, &blob_sizes.lbs_perf_event);
+	lsm_set_blob_size(&needed->lbs_sock, &blob_sizes.lbs_sock);
+	lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
+	lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
+	lsm_set_blob_size(&needed->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
+	lsm_set_blob_size(&needed->lbs_xattr_count,
+			  &blob_sizes.lbs_xattr_count);
+	lsm_set_blob_size(&needed->lbs_bdev, &blob_sizes.lbs_bdev);
+}
+
+/* Prepare LSM for initialization. */
+static void __init prepare_lsm(struct lsm_info *lsm)
+{
+	int enabled = lsm_allowed(lsm);
+
+	/* Record enablement (to handle any following exclusive LSMs). */
+	set_enabled(lsm, enabled);
+
+	/* If enabled, do pre-initialization work. */
+	if (enabled) {
+		if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
+			exclusive = lsm;
+			init_debug("exclusive chosen:   %s\n", lsm->name);
+		}
+
+		lsm_set_blob_sizes(lsm->blobs);
+	}
+}
+
+/* Initialize a given LSM, if it is enabled. */
+static void __init initialize_lsm(struct lsm_info *lsm)
+{
+	if (is_enabled(lsm)) {
+		int ret;
+
+		init_debug("initializing %s\n", lsm->name);
+		ret = lsm->init();
+		WARN(ret, "%s failed to initialize: %d\n", lsm->name, ret);
+	}
+}
+
+/*
+ * Current index to use while initializing the lsm id list.
+ */
+u32 lsm_active_cnt __ro_after_init;
+const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
+
+/* Populate ordered LSMs list from comma-separated LSM name list. */
+static void __init ordered_lsm_parse(const char *order, const char *origin)
+{
+	struct lsm_info *lsm;
+	char *sep, *name, *next;
+
+	/* LSM_ORDER_FIRST is always first. */
+	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+		if (lsm->order == LSM_ORDER_FIRST)
+			append_ordered_lsm(lsm, "  first");
+	}
+
+	/* Process "security=", if given. */
+	if (chosen_major_lsm) {
+		struct lsm_info *major;
+
+		/*
+		 * To match the original "security=" behavior, this
+		 * explicitly does NOT fallback to another Legacy Major
+		 * if the selected one was separately disabled: disable
+		 * all non-matching Legacy Major LSMs.
+		 */
+		for (major = __start_lsm_info; major < __end_lsm_info;
+		     major++) {
+			if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
+			    strcmp(major->name, chosen_major_lsm) != 0) {
+				set_enabled(major, false);
+				init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
+					   chosen_major_lsm, major->name);
+			}
+		}
+	}
+
+	sep = kstrdup(order, GFP_KERNEL);
+	next = sep;
+	/* Walk the list, looking for matching LSMs. */
+	while ((name = strsep(&next, ",")) != NULL) {
+		bool found = false;
+
+		for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+			if (strcmp(lsm->name, name) == 0) {
+				if (lsm->order == LSM_ORDER_MUTABLE)
+					append_ordered_lsm(lsm, origin);
+				found = true;
+			}
+		}
+
+		if (!found)
+			init_debug("%s ignored: %s (not built into kernel)\n",
+				   origin, name);
+	}
+
+	/* Process "security=", if given. */
+	if (chosen_major_lsm) {
+		for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+			if (exists_ordered_lsm(lsm))
+				continue;
+			if (strcmp(lsm->name, chosen_major_lsm) == 0)
+				append_ordered_lsm(lsm, "security=");
+		}
+	}
+
+	/* LSM_ORDER_LAST is always last. */
+	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+		if (lsm->order == LSM_ORDER_LAST)
+			append_ordered_lsm(lsm, "   last");
+	}
+
+	/* Disable all LSMs not in the ordered list. */
+	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+		if (exists_ordered_lsm(lsm))
+			continue;
+		set_enabled(lsm, false);
+		init_debug("%s skipped: %s (not in requested order)\n",
+			   origin, lsm->name);
+	}
+
+	kfree(sep);
+}
+
+static void __init report_lsm_order(void)
+{
+	struct lsm_info **lsm, *early;
+	int first = 0;
+
+	pr_info("initializing lsm=");
+
+	/* Report each enabled LSM name, comma separated. */
+	for (early = __start_early_lsm_info;
+	     early < __end_early_lsm_info; early++)
+		if (is_enabled(early))
+			pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
+	for (lsm = ordered_lsms; *lsm; lsm++)
+		if (is_enabled(*lsm))
+			pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
+
+	pr_cont("\n");
+}
+
+/**
+ * lsm_early_cred - during initialization allocate a composite cred blob
+ * @cred: the cred that needs a blob
+ *
+ * Allocate the cred blob for all the modules
+ */
+static void __init lsm_early_cred(struct cred *cred)
+{
+	int rc = lsm_cred_alloc(cred, GFP_KERNEL);
+
+	if (rc)
+		panic("%s: Early cred alloc failed.\n", __func__);
+}
+
+/**
+ * lsm_early_task - during initialization allocate a composite task blob
+ * @task: the task that needs a blob
+ *
+ * Allocate the task blob for all the modules
+ */
+static void __init lsm_early_task(struct task_struct *task)
+{
+	int rc = lsm_task_alloc(task);
+
+	if (rc)
+		panic("%s: Early task alloc failed.\n", __func__);
+}
+
+static void __init ordered_lsm_init(void)
+{
+	struct lsm_info **lsm;
+
+	if (chosen_lsm_order) {
+		if (chosen_major_lsm) {
+			pr_warn("security=%s is ignored because it is superseded by lsm=%s\n",
+				chosen_major_lsm, chosen_lsm_order);
+			chosen_major_lsm = NULL;
+		}
+		ordered_lsm_parse(chosen_lsm_order, "cmdline");
+	} else
+		ordered_lsm_parse(builtin_lsm_order, "builtin");
+
+	for (lsm = ordered_lsms; *lsm; lsm++)
+		prepare_lsm(*lsm);
+
+	report_lsm_order();
+
+	init_debug("cred blob size       = %d\n", blob_sizes.lbs_cred);
+	init_debug("file blob size       = %d\n", blob_sizes.lbs_file);
+	init_debug("ib blob size         = %d\n", blob_sizes.lbs_ib);
+	init_debug("inode blob size      = %d\n", blob_sizes.lbs_inode);
+	init_debug("ipc blob size        = %d\n", blob_sizes.lbs_ipc);
+#ifdef CONFIG_KEYS
+	init_debug("key blob size        = %d\n", blob_sizes.lbs_key);
+#endif /* CONFIG_KEYS */
+	init_debug("msg_msg blob size    = %d\n", blob_sizes.lbs_msg_msg);
+	init_debug("sock blob size       = %d\n", blob_sizes.lbs_sock);
+	init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
+	init_debug("perf event blob size = %d\n", blob_sizes.lbs_perf_event);
+	init_debug("task blob size       = %d\n", blob_sizes.lbs_task);
+	init_debug("tun device blob size = %d\n", blob_sizes.lbs_tun_dev);
+	init_debug("xattr slots          = %d\n", blob_sizes.lbs_xattr_count);
+	init_debug("bdev blob size       = %d\n", blob_sizes.lbs_bdev);
+
+	/*
+	 * Create any kmem_caches needed for blobs
+	 */
+	if (blob_sizes.lbs_file)
+		lsm_file_cache = kmem_cache_create("lsm_file_cache",
+						   blob_sizes.lbs_file, 0,
+						   SLAB_PANIC, NULL);
+	if (blob_sizes.lbs_inode)
+		lsm_inode_cache = kmem_cache_create("lsm_inode_cache",
+						    blob_sizes.lbs_inode, 0,
+						    SLAB_PANIC, NULL);
+
+	lsm_early_cred((struct cred *) current->cred);
+	lsm_early_task(current);
+	for (lsm = ordered_lsms; *lsm; lsm++)
+		initialize_lsm(*lsm);
+}
+
+static bool match_last_lsm(const char *list, const char *lsm)
+{
+	const char *last;
+
+	if (WARN_ON(!list || !lsm))
+		return false;
+	last = strrchr(list, ',');
+	if (last)
+		/* Pass the comma, strcmp() will check for '\0' */
+		last++;
+	else
+		last = list;
+	return !strcmp(last, lsm);
+}
+
+static int lsm_append(const char *new, char **result)
+{
+	char *cp;
+
+	if (*result == NULL) {
+		*result = kstrdup(new, GFP_KERNEL);
+		if (*result == NULL)
+			return -ENOMEM;
+	} else {
+		/* Check if it is the last registered name */
+		if (match_last_lsm(*result, new))
+			return 0;
+		cp = kasprintf(GFP_KERNEL, "%s,%s", *result, new);
+		if (cp == NULL)
+			return -ENOMEM;
+		kfree(*result);
+		*result = cp;
+	}
+	return 0;
+}
+
+static void __init lsm_static_call_init(struct security_hook_list *hl)
+{
+	struct lsm_static_call *scall = hl->scalls;
+	int i;
+
+	for (i = 0; i < MAX_LSM_COUNT; i++) {
+		/* Update the first static call that is not used yet */
+		if (!scall->hl) {
+			__static_call_update(scall->key, scall->trampoline,
+					     hl->hook.lsm_func_addr);
+			scall->hl = hl;
+			static_branch_enable(scall->active);
+			return;
+		}
+		scall++;
+	}
+	panic("%s - Ran out of static slots.\n", __func__);
+}
+
+/**
+ * security_add_hooks - Add a modules hooks to the hook lists.
+ * @hooks: the hooks to add
+ * @count: the number of hooks to add
+ * @lsmid: the identification information for the security module
+ *
+ * Each LSM has to register its hooks with the infrastructure.
+ */
+void __init security_add_hooks(struct security_hook_list *hooks, int count,
+			       const struct lsm_id *lsmid)
+{
+	int i;
+
+	/*
+	 * A security module may call security_add_hooks() more
+	 * than once during initialization, and LSM initialization
+	 * is serialized. Landlock is one such case.
+	 * Look at the previous entry, if there is one, for duplication.
+	 */
+	if (lsm_active_cnt == 0 || lsm_idlist[lsm_active_cnt - 1] != lsmid) {
+		if (lsm_active_cnt >= MAX_LSM_COUNT)
+			panic("%s Too many LSMs registered.\n", __func__);
+		lsm_idlist[lsm_active_cnt++] = lsmid;
+	}
+
+	for (i = 0; i < count; i++) {
+		hooks[i].lsmid = lsmid;
+		lsm_static_call_init(&hooks[i]);
+	}
+
+	/*
+	 * Don't try to append during early_security_init(), we'll come back
+	 * and fix this up afterwards.
+	 */
+	if (slab_is_available()) {
+		if (lsm_append(lsmid->name, &lsm_names) < 0)
+			panic("%s - Cannot get early memory.\n", __func__);
+	}
+}
+
+int __init early_security_init(void)
+{
+	struct lsm_info *lsm;
+
+	for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
+		if (!lsm->enabled)
+			lsm->enabled = &lsm_enabled_true;
+		prepare_lsm(lsm);
+		initialize_lsm(lsm);
+	}
+
+	return 0;
+}
+
+/**
+ * security_init - initializes the security framework
+ *
+ * This should be called early in the kernel initialization sequence.
+ */
+int __init security_init(void)
+{
+	struct lsm_info *lsm;
+
+	init_debug("legacy security=%s\n", chosen_major_lsm ? : " *unspecified*");
+	init_debug("  CONFIG_LSM=%s\n", builtin_lsm_order);
+	init_debug("boot arg lsm=%s\n", chosen_lsm_order ? : " *unspecified*");
+
+	/*
+	 * Append the names of the early LSM modules now that kmalloc() is
+	 * available
+	 */
+	for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
+		init_debug("  early started: %s (%s)\n", lsm->name,
+			   is_enabled(lsm) ? "enabled" : "disabled");
+		if (lsm->enabled)
+			lsm_append(lsm->name, &lsm_names);
+	}
+
+	/* Load LSMs in specified order. */
+	ordered_lsm_init();
+
+	return 0;
+}
diff --git a/security/security.c b/security/security.c
index 477be0a17e3f..8d370a4c5e74 100644
--- a/security/security.c
+++ b/security/security.c
@@ -32,24 +32,7 @@
 #include <net/flow.h>
 #include <net/sock.h>
 
-#define SECURITY_HOOK_ACTIVE_KEY(HOOK, IDX) security_hook_active_##HOOK##_##IDX
-
-/*
- * Identifier for the LSM static calls.
- * HOOK is an LSM hook as defined in linux/lsm_hookdefs.h
- * IDX is the index of the static call. 0 <= NUM < MAX_LSM_COUNT
- */
-#define LSM_STATIC_CALL(HOOK, IDX) lsm_static_call_##HOOK##_##IDX
-
-/*
- * Call the macro M for each LSM hook MAX_LSM_COUNT times.
- */
-#define LSM_LOOP_UNROLL(M, ...) 		\
-do {						\
-	UNROLL(MAX_LSM_COUNT, M, __VA_ARGS__)	\
-} while (0)
-
-#define LSM_DEFINE_UNROLL(M, ...) UNROLL(MAX_LSM_COUNT, M, __VA_ARGS__)
+#include "lsm.h"
 
 /*
  * These are descriptions of the reasons that can be passed to the
@@ -90,21 +73,29 @@ const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX + 1] = {
 	[LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality",
 };
 
-static struct kmem_cache *lsm_file_cache;
-static struct kmem_cache *lsm_inode_cache;
+struct lsm_blob_sizes blob_sizes;
 
-char *lsm_names;
-static struct lsm_blob_sizes blob_sizes __ro_after_init;
+struct kmem_cache *lsm_file_cache;
+struct kmem_cache *lsm_inode_cache;
 
-/* Boot-time LSM user choice */
-static __initdata const char *chosen_lsm_order;
-static __initdata const char *chosen_major_lsm;
+#define SECURITY_HOOK_ACTIVE_KEY(HOOK, IDX) security_hook_active_##HOOK##_##IDX
 
-static __initconst const char *const builtin_lsm_order = CONFIG_LSM;
+/*
+ * Identifier for the LSM static calls.
+ * HOOK is an LSM hook as defined in linux/lsm_hookdefs.h
+ * IDX is the index of the static call. 0 <= NUM < MAX_LSM_COUNT
+ */
+#define LSM_STATIC_CALL(HOOK, IDX) lsm_static_call_##HOOK##_##IDX
 
-/* Ordered list of LSMs to initialize. */
-static __initdata struct lsm_info *ordered_lsms[MAX_LSM_COUNT + 1];
-static __initdata struct lsm_info *exclusive;
+/*
+ * Call the macro M for each LSM hook MAX_LSM_COUNT times.
+ */
+#define LSM_LOOP_UNROLL(M, ...) 		\
+do {						\
+	UNROLL(MAX_LSM_COUNT, M, __VA_ARGS__)	\
+} while (0)
+
+#define LSM_DEFINE_UNROLL(M, ...) UNROLL(MAX_LSM_COUNT, M, __VA_ARGS__)
 
 #ifdef CONFIG_HAVE_STATIC_CALL
 #define LSM_HOOK_TRAMP(NAME, NUM) \
@@ -155,490 +146,25 @@ struct lsm_static_calls_table
 #undef INIT_LSM_STATIC_CALL
 	};
 
-static __initdata bool debug;
-#define init_debug(...)						\
-	do {							\
-		if (debug)					\
-			pr_info(__VA_ARGS__);			\
-	} while (0)
-
-static bool __init is_enabled(struct lsm_info *lsm)
-{
-	if (!lsm->enabled)
-		return false;
-
-	return *lsm->enabled;
-}
-
-/* Mark an LSM's enabled flag. */
-static int lsm_enabled_true __initdata = 1;
-static int lsm_enabled_false __initdata = 0;
-static void __init set_enabled(struct lsm_info *lsm, bool enabled)
-{
-	/*
-	 * When an LSM hasn't configured an enable variable, we can use
-	 * a hard-coded location for storing the default enabled state.
-	 */
-	if (!lsm->enabled) {
-		if (enabled)
-			lsm->enabled = &lsm_enabled_true;
-		else
-			lsm->enabled = &lsm_enabled_false;
-	} else if (lsm->enabled == &lsm_enabled_true) {
-		if (!enabled)
-			lsm->enabled = &lsm_enabled_false;
-	} else if (lsm->enabled == &lsm_enabled_false) {
-		if (enabled)
-			lsm->enabled = &lsm_enabled_true;
-	} else {
-		*lsm->enabled = enabled;
-	}
-}
-
-/* Is an LSM already listed in the ordered LSMs list? */
-static bool __init exists_ordered_lsm(struct lsm_info *lsm)
-{
-	struct lsm_info **check;
-
-	for (check = ordered_lsms; *check; check++)
-		if (*check == lsm)
-			return true;
-
-	return false;
-}
-
-/* Append an LSM to the list of ordered LSMs to initialize. */
-static int last_lsm __initdata;
-static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
-{
-	/* Ignore duplicate selections. */
-	if (exists_ordered_lsm(lsm))
-		return;
-
-	if (WARN(last_lsm == MAX_LSM_COUNT, "%s: out of LSM static calls!?\n", from))
-		return;
-
-	/* Enable this LSM, if it is not already set. */
-	if (!lsm->enabled)
-		lsm->enabled = &lsm_enabled_true;
-	ordered_lsms[last_lsm++] = lsm;
-
-	init_debug("%s ordered: %s (%s)\n", from, lsm->name,
-		   is_enabled(lsm) ? "enabled" : "disabled");
-}
-
-/* Is an LSM allowed to be initialized? */
-static bool __init lsm_allowed(struct lsm_info *lsm)
-{
-	/* Skip if the LSM is disabled. */
-	if (!is_enabled(lsm))
-		return false;
-
-	/* Not allowed if another exclusive LSM already initialized. */
-	if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
-		init_debug("exclusive disabled: %s\n", lsm->name);
-		return false;
-	}
-
-	return true;
-}
-
-static void __init lsm_set_blob_size(int *need, int *lbs)
-{
-	int offset;
-
-	if (*need <= 0)
-		return;
-
-	offset = ALIGN(*lbs, sizeof(void *));
-	*lbs = offset + *need;
-	*need = offset;
-}
-
-static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
-{
-	if (!needed)
-		return;
-
-	lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
-	lsm_set_blob_size(&needed->lbs_file, &blob_sizes.lbs_file);
-	lsm_set_blob_size(&needed->lbs_ib, &blob_sizes.lbs_ib);
-	/*
-	 * The inode blob gets an rcu_head in addition to
-	 * what the modules might need.
-	 */
-	if (needed->lbs_inode && blob_sizes.lbs_inode == 0)
-		blob_sizes.lbs_inode = sizeof(struct rcu_head);
-	lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
-	lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
-	lsm_set_blob_size(&needed->lbs_key, &blob_sizes.lbs_key);
-	lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
-	lsm_set_blob_size(&needed->lbs_perf_event, &blob_sizes.lbs_perf_event);
-	lsm_set_blob_size(&needed->lbs_sock, &blob_sizes.lbs_sock);
-	lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
-	lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
-	lsm_set_blob_size(&needed->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
-	lsm_set_blob_size(&needed->lbs_xattr_count,
-			  &blob_sizes.lbs_xattr_count);
-	lsm_set_blob_size(&needed->lbs_bdev, &blob_sizes.lbs_bdev);
-}
-
-/* Prepare LSM for initialization. */
-static void __init prepare_lsm(struct lsm_info *lsm)
-{
-	int enabled = lsm_allowed(lsm);
-
-	/* Record enablement (to handle any following exclusive LSMs). */
-	set_enabled(lsm, enabled);
-
-	/* If enabled, do pre-initialization work. */
-	if (enabled) {
-		if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
-			exclusive = lsm;
-			init_debug("exclusive chosen:   %s\n", lsm->name);
-		}
-
-		lsm_set_blob_sizes(lsm->blobs);
-	}
-}
-
-/* Initialize a given LSM, if it is enabled. */
-static void __init initialize_lsm(struct lsm_info *lsm)
-{
-	if (is_enabled(lsm)) {
-		int ret;
-
-		init_debug("initializing %s\n", lsm->name);
-		ret = lsm->init();
-		WARN(ret, "%s failed to initialize: %d\n", lsm->name, ret);
-	}
-}
-
-/*
- * Current index to use while initializing the lsm id list.
- */
-u32 lsm_active_cnt __ro_after_init;
-const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
-
-/* Populate ordered LSMs list from comma-separated LSM name list. */
-static void __init ordered_lsm_parse(const char *order, const char *origin)
-{
-	struct lsm_info *lsm;
-	char *sep, *name, *next;
-
-	/* LSM_ORDER_FIRST is always first. */
-	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
-		if (lsm->order == LSM_ORDER_FIRST)
-			append_ordered_lsm(lsm, "  first");
-	}
-
-	/* Process "security=", if given. */
-	if (chosen_major_lsm) {
-		struct lsm_info *major;
-
-		/*
-		 * To match the original "security=" behavior, this
-		 * explicitly does NOT fallback to another Legacy Major
-		 * if the selected one was separately disabled: disable
-		 * all non-matching Legacy Major LSMs.
-		 */
-		for (major = __start_lsm_info; major < __end_lsm_info;
-		     major++) {
-			if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
-			    strcmp(major->name, chosen_major_lsm) != 0) {
-				set_enabled(major, false);
-				init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
-					   chosen_major_lsm, major->name);
-			}
-		}
-	}
-
-	sep = kstrdup(order, GFP_KERNEL);
-	next = sep;
-	/* Walk the list, looking for matching LSMs. */
-	while ((name = strsep(&next, ",")) != NULL) {
-		bool found = false;
-
-		for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
-			if (strcmp(lsm->name, name) == 0) {
-				if (lsm->order == LSM_ORDER_MUTABLE)
-					append_ordered_lsm(lsm, origin);
-				found = true;
-			}
-		}
-
-		if (!found)
-			init_debug("%s ignored: %s (not built into kernel)\n",
-				   origin, name);
-	}
-
-	/* Process "security=", if given. */
-	if (chosen_major_lsm) {
-		for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
-			if (exists_ordered_lsm(lsm))
-				continue;
-			if (strcmp(lsm->name, chosen_major_lsm) == 0)
-				append_ordered_lsm(lsm, "security=");
-		}
-	}
-
-	/* LSM_ORDER_LAST is always last. */
-	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
-		if (lsm->order == LSM_ORDER_LAST)
-			append_ordered_lsm(lsm, "   last");
-	}
-
-	/* Disable all LSMs not in the ordered list. */
-	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
-		if (exists_ordered_lsm(lsm))
-			continue;
-		set_enabled(lsm, false);
-		init_debug("%s skipped: %s (not in requested order)\n",
-			   origin, lsm->name);
-	}
-
-	kfree(sep);
-}
-
-static void __init lsm_static_call_init(struct security_hook_list *hl)
-{
-	struct lsm_static_call *scall = hl->scalls;
-	int i;
-
-	for (i = 0; i < MAX_LSM_COUNT; i++) {
-		/* Update the first static call that is not used yet */
-		if (!scall->hl) {
-			__static_call_update(scall->key, scall->trampoline,
-					     hl->hook.lsm_func_addr);
-			scall->hl = hl;
-			static_branch_enable(scall->active);
-			return;
-		}
-		scall++;
-	}
-	panic("%s - Ran out of static slots.\n", __func__);
-}
-
-static void __init lsm_early_cred(struct cred *cred);
-static void __init lsm_early_task(struct task_struct *task);
-
-static int lsm_append(const char *new, char **result);
-
-static void __init report_lsm_order(void)
-{
-	struct lsm_info **lsm, *early;
-	int first = 0;
-
-	pr_info("initializing lsm=");
-
-	/* Report each enabled LSM name, comma separated. */
-	for (early = __start_early_lsm_info;
-	     early < __end_early_lsm_info; early++)
-		if (is_enabled(early))
-			pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
-	for (lsm = ordered_lsms; *lsm; lsm++)
-		if (is_enabled(*lsm))
-			pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
-
-	pr_cont("\n");
-}
-
-static void __init ordered_lsm_init(void)
-{
-	struct lsm_info **lsm;
-
-	if (chosen_lsm_order) {
-		if (chosen_major_lsm) {
-			pr_warn("security=%s is ignored because it is superseded by lsm=%s\n",
-				chosen_major_lsm, chosen_lsm_order);
-			chosen_major_lsm = NULL;
-		}
-		ordered_lsm_parse(chosen_lsm_order, "cmdline");
-	} else
-		ordered_lsm_parse(builtin_lsm_order, "builtin");
-
-	for (lsm = ordered_lsms; *lsm; lsm++)
-		prepare_lsm(*lsm);
-
-	report_lsm_order();
-
-	init_debug("cred blob size       = %d\n", blob_sizes.lbs_cred);
-	init_debug("file blob size       = %d\n", blob_sizes.lbs_file);
-	init_debug("ib blob size         = %d\n", blob_sizes.lbs_ib);
-	init_debug("inode blob size      = %d\n", blob_sizes.lbs_inode);
-	init_debug("ipc blob size        = %d\n", blob_sizes.lbs_ipc);
-#ifdef CONFIG_KEYS
-	init_debug("key blob size        = %d\n", blob_sizes.lbs_key);
-#endif /* CONFIG_KEYS */
-	init_debug("msg_msg blob size    = %d\n", blob_sizes.lbs_msg_msg);
-	init_debug("sock blob size       = %d\n", blob_sizes.lbs_sock);
-	init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
-	init_debug("perf event blob size = %d\n", blob_sizes.lbs_perf_event);
-	init_debug("task blob size       = %d\n", blob_sizes.lbs_task);
-	init_debug("tun device blob size = %d\n", blob_sizes.lbs_tun_dev);
-	init_debug("xattr slots          = %d\n", blob_sizes.lbs_xattr_count);
-	init_debug("bdev blob size       = %d\n", blob_sizes.lbs_bdev);
-
-	/*
-	 * Create any kmem_caches needed for blobs
-	 */
-	if (blob_sizes.lbs_file)
-		lsm_file_cache = kmem_cache_create("lsm_file_cache",
-						   blob_sizes.lbs_file, 0,
-						   SLAB_PANIC, NULL);
-	if (blob_sizes.lbs_inode)
-		lsm_inode_cache = kmem_cache_create("lsm_inode_cache",
-						    blob_sizes.lbs_inode, 0,
-						    SLAB_PANIC, NULL);
-
-	lsm_early_cred((struct cred *) current->cred);
-	lsm_early_task(current);
-	for (lsm = ordered_lsms; *lsm; lsm++)
-		initialize_lsm(*lsm);
-}
-
-int __init early_security_init(void)
-{
-	struct lsm_info *lsm;
-
-	for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
-		if (!lsm->enabled)
-			lsm->enabled = &lsm_enabled_true;
-		prepare_lsm(lsm);
-		initialize_lsm(lsm);
-	}
-
-	return 0;
-}
-
 /**
- * security_init - initializes the security framework
+ * lsm_file_alloc - allocate a composite file blob
+ * @file: the file that needs a blob
  *
- * This should be called early in the kernel initialization sequence.
- */
-int __init security_init(void)
-{
-	struct lsm_info *lsm;
-
-	init_debug("legacy security=%s\n", chosen_major_lsm ? : " *unspecified*");
-	init_debug("  CONFIG_LSM=%s\n", builtin_lsm_order);
-	init_debug("boot arg lsm=%s\n", chosen_lsm_order ? : " *unspecified*");
-
-	/*
-	 * Append the names of the early LSM modules now that kmalloc() is
-	 * available
-	 */
-	for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
-		init_debug("  early started: %s (%s)\n", lsm->name,
-			   is_enabled(lsm) ? "enabled" : "disabled");
-		if (lsm->enabled)
-			lsm_append(lsm->name, &lsm_names);
-	}
-
-	/* Load LSMs in specified order. */
-	ordered_lsm_init();
-
-	return 0;
-}
-
-/* Save user chosen LSM */
-static int __init choose_major_lsm(char *str)
-{
-	chosen_major_lsm = str;
-	return 1;
-}
-__setup("security=", choose_major_lsm);
-
-/* Explicitly choose LSM initialization order. */
-static int __init choose_lsm_order(char *str)
-{
-	chosen_lsm_order = str;
-	return 1;
-}
-__setup("lsm=", choose_lsm_order);
-
-/* Enable LSM order debugging. */
-static int __init enable_debug(char *str)
-{
-	debug = true;
-	return 1;
-}
-__setup("lsm.debug", enable_debug);
-
-static bool match_last_lsm(const char *list, const char *lsm)
-{
-	const char *last;
-
-	if (WARN_ON(!list || !lsm))
-		return false;
-	last = strrchr(list, ',');
-	if (last)
-		/* Pass the comma, strcmp() will check for '\0' */
-		last++;
-	else
-		last = list;
-	return !strcmp(last, lsm);
-}
-
-static int lsm_append(const char *new, char **result)
-{
-	char *cp;
-
-	if (*result == NULL) {
-		*result = kstrdup(new, GFP_KERNEL);
-		if (*result == NULL)
-			return -ENOMEM;
-	} else {
-		/* Check if it is the last registered name */
-		if (match_last_lsm(*result, new))
-			return 0;
-		cp = kasprintf(GFP_KERNEL, "%s,%s", *result, new);
-		if (cp == NULL)
-			return -ENOMEM;
-		kfree(*result);
-		*result = cp;
-	}
-	return 0;
-}
-
-/**
- * security_add_hooks - Add a modules hooks to the hook lists.
- * @hooks: the hooks to add
- * @count: the number of hooks to add
- * @lsmid: the identification information for the security module
+ * Allocate the file blob for all the modules
  *
- * Each LSM has to register its hooks with the infrastructure.
+ * Returns 0, or -ENOMEM if memory can't be allocated.
  */
-void __init security_add_hooks(struct security_hook_list *hooks, int count,
-			       const struct lsm_id *lsmid)
+static int lsm_file_alloc(struct file *file)
 {
-	int i;
-
-	/*
-	 * A security module may call security_add_hooks() more
-	 * than once during initialization, and LSM initialization
-	 * is serialized. Landlock is one such case.
-	 * Look at the previous entry, if there is one, for duplication.
-	 */
-	if (lsm_active_cnt == 0 || lsm_idlist[lsm_active_cnt - 1] != lsmid) {
-		if (lsm_active_cnt >= MAX_LSM_COUNT)
-			panic("%s Too many LSMs registered.\n", __func__);
-		lsm_idlist[lsm_active_cnt++] = lsmid;
+	if (!lsm_file_cache) {
+		file->f_security = NULL;
+		return 0;
 	}
 
-	for (i = 0; i < count; i++) {
-		hooks[i].lsmid = lsmid;
-		lsm_static_call_init(&hooks[i]);
-	}
-
-	/*
-	 * Don't try to append during early_security_init(), we'll come back
-	 * and fix this up afterwards.
-	 */
-	if (slab_is_available()) {
-		if (lsm_append(lsmid->name, &lsm_names) < 0)
-			panic("%s - Cannot get early memory.\n", __func__);
-	}
+	file->f_security = kmem_cache_zalloc(lsm_file_cache, GFP_KERNEL);
+	if (file->f_security == NULL)
+		return -ENOMEM;
+	return 0;
 }
 
 /**
@@ -673,46 +199,11 @@ static int lsm_blob_alloc(void **dest, size_t size, gfp_t gfp)
  *
  * Returns 0, or -ENOMEM if memory can't be allocated.
  */
-static int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
+int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
 {
 	return lsm_blob_alloc(&cred->security, blob_sizes.lbs_cred, gfp);
 }
 
-/**
- * lsm_early_cred - during initialization allocate a composite cred blob
- * @cred: the cred that needs a blob
- *
- * Allocate the cred blob for all the modules
- */
-static void __init lsm_early_cred(struct cred *cred)
-{
-	int rc = lsm_cred_alloc(cred, GFP_KERNEL);
-
-	if (rc)
-		panic("%s: Early cred alloc failed.\n", __func__);
-}
-
-/**
- * lsm_file_alloc - allocate a composite file blob
- * @file: the file that needs a blob
- *
- * Allocate the file blob for all the modules
- *
- * Returns 0, or -ENOMEM if memory can't be allocated.
- */
-static int lsm_file_alloc(struct file *file)
-{
-	if (!lsm_file_cache) {
-		file->f_security = NULL;
-		return 0;
-	}
-
-	file->f_security = kmem_cache_zalloc(lsm_file_cache, GFP_KERNEL);
-	if (file->f_security == NULL)
-		return -ENOMEM;
-	return 0;
-}
-
 /**
  * lsm_inode_alloc - allocate a composite inode blob
  * @inode: the inode that needs a blob
@@ -743,7 +234,7 @@ static int lsm_inode_alloc(struct inode *inode, gfp_t gfp)
  *
  * Returns 0, or -ENOMEM if memory can't be allocated.
  */
-static int lsm_task_alloc(struct task_struct *task)
+int lsm_task_alloc(struct task_struct *task)
 {
 	return lsm_blob_alloc(&task->security, blob_sizes.lbs_task, GFP_KERNEL);
 }
@@ -812,20 +303,6 @@ static int lsm_bdev_alloc(struct block_device *bdev)
 	return 0;
 }
 
-/**
- * lsm_early_task - during initialization allocate a composite task blob
- * @task: the task that needs a blob
- *
- * Allocate the task blob for all the modules
- */
-static void __init lsm_early_task(struct task_struct *task)
-{
-	int rc = lsm_task_alloc(task);
-
-	if (rc)
-		panic("%s: Early task alloc failed.\n", __func__);
-}
-
 /**
  * lsm_superblock_alloc - allocate a composite superblock blob
  * @sb: the superblock that needs a blob
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 03/29] lsm: simplify prepare_lsm() and rename to lsm_prep_single()
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
  2025-04-09 18:49 ` [RFC PATCH 01/29] lsm: split the notifier code out into lsm_notifier.c Paul Moore
  2025-04-09 18:49 ` [RFC PATCH 02/29] lsm: split the init code out into lsm_init.c Paul Moore
@ 2025-04-09 18:49 ` Paul Moore
  2025-04-09 21:30   ` Kees Cook
  2025-04-15 22:10   ` John Johansen
  2025-04-09 18:49 ` [RFC PATCH 04/29] lsm: simplify ordered_lsm_init() and rename to lsm_init_ordered() Paul Moore
                   ` (26 subsequent siblings)
  29 siblings, 2 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:49 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

One part of a larger effort to cleanup the LSM framework initialization
code.

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 security/lsm_init.c | 103 ++++++++++++++++++--------------------------
 1 file changed, 43 insertions(+), 60 deletions(-)

diff --git a/security/lsm_init.c b/security/lsm_init.c
index 70e7d4207dae..dffa8dc2da36 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -123,22 +123,6 @@ static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
 		   is_enabled(lsm) ? "enabled" : "disabled");
 }
 
-/* Is an LSM allowed to be initialized? */
-static bool __init lsm_allowed(struct lsm_info *lsm)
-{
-	/* Skip if the LSM is disabled. */
-	if (!is_enabled(lsm))
-		return false;
-
-	/* Not allowed if another exclusive LSM already initialized. */
-	if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
-		init_debug("exclusive disabled: %s\n", lsm->name);
-		return false;
-	}
-
-	return true;
-}
-
 static void __init lsm_set_blob_size(int *need, int *lbs)
 {
 	int offset;
@@ -151,51 +135,50 @@ static void __init lsm_set_blob_size(int *need, int *lbs)
 	*need = offset;
 }
 
-static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
+/**
+ * lsm_prep_single - Prepare the LSM framework for a new LSM
+ * @lsm: LSM definition
+ */
+static void __init lsm_prep_single(struct lsm_info *lsm)
 {
-	if (!needed)
+	struct lsm_blob_sizes *blobs;
+
+	if (!is_enabled(lsm)) {
+		set_enabled(lsm, false);
+		return;
+	} else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
+		init_debug("exclusive disabled: %s\n", lsm->name);
+		set_enabled(lsm, false);
 		return;
-
-	lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
-	lsm_set_blob_size(&needed->lbs_file, &blob_sizes.lbs_file);
-	lsm_set_blob_size(&needed->lbs_ib, &blob_sizes.lbs_ib);
-	/*
-	 * The inode blob gets an rcu_head in addition to
-	 * what the modules might need.
-	 */
-	if (needed->lbs_inode && blob_sizes.lbs_inode == 0)
-		blob_sizes.lbs_inode = sizeof(struct rcu_head);
-	lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
-	lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
-	lsm_set_blob_size(&needed->lbs_key, &blob_sizes.lbs_key);
-	lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
-	lsm_set_blob_size(&needed->lbs_perf_event, &blob_sizes.lbs_perf_event);
-	lsm_set_blob_size(&needed->lbs_sock, &blob_sizes.lbs_sock);
-	lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
-	lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
-	lsm_set_blob_size(&needed->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
-	lsm_set_blob_size(&needed->lbs_xattr_count,
-			  &blob_sizes.lbs_xattr_count);
-	lsm_set_blob_size(&needed->lbs_bdev, &blob_sizes.lbs_bdev);
-}
-
-/* Prepare LSM for initialization. */
-static void __init prepare_lsm(struct lsm_info *lsm)
-{
-	int enabled = lsm_allowed(lsm);
-
-	/* Record enablement (to handle any following exclusive LSMs). */
-	set_enabled(lsm, enabled);
-
-	/* If enabled, do pre-initialization work. */
-	if (enabled) {
-		if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
-			exclusive = lsm;
-			init_debug("exclusive chosen:   %s\n", lsm->name);
-		}
-
-		lsm_set_blob_sizes(lsm->blobs);
 	}
+
+	/* Mark the LSM as enabled. */
+	set_enabled(lsm, true);
+	if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
+		init_debug("exclusive chosen:   %s\n", lsm->name);
+		exclusive = lsm;
+	}
+
+	/* Register the LSM blob sizes. */
+	blobs = lsm->blobs;
+	lsm_set_blob_size(&blobs->lbs_cred, &blob_sizes.lbs_cred);
+	lsm_set_blob_size(&blobs->lbs_file, &blob_sizes.lbs_file);
+	lsm_set_blob_size(&blobs->lbs_ib, &blob_sizes.lbs_ib);
+	/* inode blob gets an rcu_head in addition to LSM blobs. */
+	if (blobs->lbs_inode && blob_sizes.lbs_inode == 0)
+		blob_sizes.lbs_inode = sizeof(struct rcu_head);
+	lsm_set_blob_size(&blobs->lbs_inode, &blob_sizes.lbs_inode);
+	lsm_set_blob_size(&blobs->lbs_ipc, &blob_sizes.lbs_ipc);
+	lsm_set_blob_size(&blobs->lbs_key, &blob_sizes.lbs_key);
+	lsm_set_blob_size(&blobs->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
+	lsm_set_blob_size(&blobs->lbs_perf_event, &blob_sizes.lbs_perf_event);
+	lsm_set_blob_size(&blobs->lbs_sock, &blob_sizes.lbs_sock);
+	lsm_set_blob_size(&blobs->lbs_superblock, &blob_sizes.lbs_superblock);
+	lsm_set_blob_size(&blobs->lbs_task, &blob_sizes.lbs_task);
+	lsm_set_blob_size(&blobs->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
+	lsm_set_blob_size(&blobs->lbs_xattr_count,
+			  &blob_sizes.lbs_xattr_count);
+	lsm_set_blob_size(&blobs->lbs_bdev, &blob_sizes.lbs_bdev);
 }
 
 /* Initialize a given LSM, if it is enabled. */
@@ -358,7 +341,7 @@ static void __init ordered_lsm_init(void)
 		ordered_lsm_parse(builtin_lsm_order, "builtin");
 
 	for (lsm = ordered_lsms; *lsm; lsm++)
-		prepare_lsm(*lsm);
+		lsm_prep_single(*lsm);
 
 	report_lsm_order();
 
@@ -499,7 +482,7 @@ int __init early_security_init(void)
 	for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
 		if (!lsm->enabled)
 			lsm->enabled = &lsm_enabled_true;
-		prepare_lsm(lsm);
+		lsm_prep_single(lsm);
 		initialize_lsm(lsm);
 	}
 
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 04/29] lsm: simplify ordered_lsm_init() and rename to lsm_init_ordered()
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (2 preceding siblings ...)
  2025-04-09 18:49 ` [RFC PATCH 03/29] lsm: simplify prepare_lsm() and rename to lsm_prep_single() Paul Moore
@ 2025-04-09 18:49 ` Paul Moore
  2025-04-09 21:38   ` Kees Cook
  2025-04-09 18:49 ` [RFC PATCH 05/29] lsm: replace the name field with a pointer to the lsm_id struct Paul Moore
                   ` (25 subsequent siblings)
  29 siblings, 1 reply; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:49 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

One part of a larger effort to cleanup the LSM framework initialization
code.

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 security/lsm_init.c | 94 +++++++++++++++++----------------------------
 1 file changed, 36 insertions(+), 58 deletions(-)

diff --git a/security/lsm_init.c b/security/lsm_init.c
index dffa8dc2da36..407429688f1b 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -32,6 +32,12 @@ static __initdata bool debug;
 			pr_info(__VA_ARGS__);				\
 	} while (0)
 
+#define lsm_order_for_each(iter)					\
+	for ((iter) = ordered_lsms; *(iter); (iter)++)
+#define lsm_early_for_each_raw(iter)					\
+	for ((iter) = __start_early_lsm_info;				\
+	     (iter) < __end_early_lsm_info; (iter)++)
+
 static int lsm_append(const char *new, char **result);
 
 /* Save user chosen LSM */
@@ -96,9 +102,10 @@ static bool __init exists_ordered_lsm(struct lsm_info *lsm)
 {
 	struct lsm_info **check;
 
-	for (check = ordered_lsms; *check; check++)
+	lsm_order_for_each(check) {
 		if (*check == lsm)
 			return true;
+	}
 
 	return false;
 }
@@ -279,56 +286,13 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
 	kfree(sep);
 }
 
-static void __init report_lsm_order(void)
-{
-	struct lsm_info **lsm, *early;
-	int first = 0;
-
-	pr_info("initializing lsm=");
-
-	/* Report each enabled LSM name, comma separated. */
-	for (early = __start_early_lsm_info;
-	     early < __end_early_lsm_info; early++)
-		if (is_enabled(early))
-			pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
-	for (lsm = ordered_lsms; *lsm; lsm++)
-		if (is_enabled(*lsm))
-			pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
-
-	pr_cont("\n");
-}
-
 /**
- * lsm_early_cred - during initialization allocate a composite cred blob
- * @cred: the cred that needs a blob
- *
- * Allocate the cred blob for all the modules
+ * lsm_init_ordered - Initialize the ordered LSMs
  */
-static void __init lsm_early_cred(struct cred *cred)
-{
-	int rc = lsm_cred_alloc(cred, GFP_KERNEL);
-
-	if (rc)
-		panic("%s: Early cred alloc failed.\n", __func__);
-}
-
-/**
- * lsm_early_task - during initialization allocate a composite task blob
- * @task: the task that needs a blob
- *
- * Allocate the task blob for all the modules
- */
-static void __init lsm_early_task(struct task_struct *task)
-{
-	int rc = lsm_task_alloc(task);
-
-	if (rc)
-		panic("%s: Early task alloc failed.\n", __func__);
-}
-
-static void __init ordered_lsm_init(void)
+static void __init lsm_init_ordered(void)
 {
 	struct lsm_info **lsm;
+	struct lsm_info *early;
 
 	if (chosen_lsm_order) {
 		if (chosen_major_lsm) {
@@ -340,10 +304,23 @@ static void __init ordered_lsm_init(void)
 	} else
 		ordered_lsm_parse(builtin_lsm_order, "builtin");
 
-	for (lsm = ordered_lsms; *lsm; lsm++)
+	lsm_order_for_each(lsm) {
 		lsm_prep_single(*lsm);
+	}
 
-	report_lsm_order();
+	pr_info("initializing lsm=");
+	lsm_early_for_each_raw(early) {
+		if (is_enabled(early))
+			pr_cont("%s%s",
+				early == __start_early_lsm_info ? "" : ",",
+				early->name);
+	}
+	lsm_order_for_each(lsm) {
+		if (is_enabled(*lsm))
+			pr_cont("%s%s",
+				lsm == ordered_lsms ? "" : ",", (*lsm)->name);
+	}
+	pr_cont("\n");
 
 	init_debug("cred blob size       = %d\n", blob_sizes.lbs_cred);
 	init_debug("file blob size       = %d\n", blob_sizes.lbs_file);
@@ -362,9 +339,6 @@ static void __init ordered_lsm_init(void)
 	init_debug("xattr slots          = %d\n", blob_sizes.lbs_xattr_count);
 	init_debug("bdev blob size       = %d\n", blob_sizes.lbs_bdev);
 
-	/*
-	 * Create any kmem_caches needed for blobs
-	 */
 	if (blob_sizes.lbs_file)
 		lsm_file_cache = kmem_cache_create("lsm_file_cache",
 						   blob_sizes.lbs_file, 0,
@@ -374,10 +348,14 @@ static void __init ordered_lsm_init(void)
 						    blob_sizes.lbs_inode, 0,
 						    SLAB_PANIC, NULL);
 
-	lsm_early_cred((struct cred *) current->cred);
-	lsm_early_task(current);
-	for (lsm = ordered_lsms; *lsm; lsm++)
+	if (lsm_cred_alloc((struct cred *)current->cred, GFP_KERNEL))
+		panic("%s: early cred alloc failed.\n", __func__);
+	if (lsm_task_alloc(current))
+		panic("%s: early task alloc failed.\n", __func__);
+
+	lsm_order_for_each(lsm) {
 		initialize_lsm(*lsm);
+	}
 }
 
 static bool match_last_lsm(const char *list, const char *lsm)
@@ -479,7 +457,7 @@ int __init early_security_init(void)
 {
 	struct lsm_info *lsm;
 
-	for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
+	lsm_early_for_each_raw(lsm) {
 		if (!lsm->enabled)
 			lsm->enabled = &lsm_enabled_true;
 		lsm_prep_single(lsm);
@@ -506,7 +484,7 @@ int __init security_init(void)
 	 * Append the names of the early LSM modules now that kmalloc() is
 	 * available
 	 */
-	for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
+	lsm_early_for_each_raw(lsm) {
 		init_debug("  early started: %s (%s)\n", lsm->name,
 			   is_enabled(lsm) ? "enabled" : "disabled");
 		if (lsm->enabled)
@@ -514,7 +492,7 @@ int __init security_init(void)
 	}
 
 	/* Load LSMs in specified order. */
-	ordered_lsm_init();
+	lsm_init_ordered();
 
 	return 0;
 }
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 05/29] lsm: replace the name field with a pointer to the lsm_id struct
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (3 preceding siblings ...)
  2025-04-09 18:49 ` [RFC PATCH 04/29] lsm: simplify ordered_lsm_init() and rename to lsm_init_ordered() Paul Moore
@ 2025-04-09 18:49 ` Paul Moore
  2025-04-09 21:40   ` Kees Cook
  2025-04-15 22:20   ` John Johansen
  2025-04-09 18:49 ` [RFC PATCH 06/29] lsm: cleanup and normalize the LSM order symbols naming Paul Moore
                   ` (24 subsequent siblings)
  29 siblings, 2 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:49 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

Reduce the duplication between the lsm_id struct and the DEFINE_LSM()
definition by linking the lsm_id struct directly into the individual
LSM's DEFINE_LSM() instance.

Linking the lsm_id into the LSM definition also allows us to simplify
the security_add_hooks() function by removing the code which populates
the lsm_idlist[] array and moving it into the normal LSM startup code
where the LSM list is parsed and the individual LSMs are enabled,
making for a cleaner implementation with less overhead at boot.

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 include/linux/lsm_hooks.h         |  2 +-
 security/apparmor/lsm.c           |  2 +-
 security/bpf/hooks.c              |  2 +-
 security/commoncap.c              |  2 +-
 security/integrity/evm/evm_main.c |  2 +-
 security/integrity/ima/ima_main.c |  2 +-
 security/ipe/ipe.c                |  2 +-
 security/landlock/setup.c         |  2 +-
 security/loadpin/loadpin.c        |  2 +-
 security/lockdown/lockdown.c      |  2 +-
 security/lsm_init.c               | 43 ++++++++++++-------------------
 security/safesetid/lsm.c          |  2 +-
 security/selinux/hooks.c          |  2 +-
 security/smack/smack_lsm.c        |  2 +-
 security/tomoyo/tomoyo.c          |  2 +-
 security/yama/yama_lsm.c          |  2 +-
 16 files changed, 31 insertions(+), 42 deletions(-)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index eeb4bfd60b79..4cd17c9a229f 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -149,7 +149,7 @@ enum lsm_order {
 };
 
 struct lsm_info {
-	const char *name;	/* Required. */
+	const struct lsm_id *id;
 	enum lsm_order order;	/* Optional: default is LSM_ORDER_MUTABLE */
 	unsigned long flags;	/* Optional: flags describing LSM */
 	int *enabled;		/* Optional: controlled by CONFIG_LSM */
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 9b6c2f157f83..a7f6a3274682 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -2272,7 +2272,7 @@ static int __init apparmor_init(void)
 }
 
 DEFINE_LSM(apparmor) = {
-	.name = "apparmor",
+	.id = &apparmor_lsmid,
 	.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
 	.enabled = &apparmor_enabled,
 	.blobs = &apparmor_blob_sizes,
diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c
index db759025abe1..40efde233f3a 100644
--- a/security/bpf/hooks.c
+++ b/security/bpf/hooks.c
@@ -33,7 +33,7 @@ struct lsm_blob_sizes bpf_lsm_blob_sizes __ro_after_init = {
 };
 
 DEFINE_LSM(bpf) = {
-	.name = "bpf",
+	.id = &bpf_lsmid,
 	.init = bpf_lsm_init,
 	.blobs = &bpf_lsm_blob_sizes
 };
diff --git a/security/commoncap.c b/security/commoncap.c
index 28d4248bf001..e04aa4f50eaf 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -1509,7 +1509,7 @@ static int __init capability_init(void)
 }
 
 DEFINE_LSM(capability) = {
-	.name = "capability",
+	.id = &capability_lsmid,
 	.order = LSM_ORDER_FIRST,
 	.init = capability_init,
 };
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 0add782e73ba..db8e324ed4e6 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -1175,7 +1175,7 @@ struct lsm_blob_sizes evm_blob_sizes __ro_after_init = {
 };
 
 DEFINE_LSM(evm) = {
-	.name = "evm",
+	.id = &evm_lsmid,
 	.init = init_evm_lsm,
 	.order = LSM_ORDER_LAST,
 	.blobs = &evm_blob_sizes,
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index f3e7ac513db3..55a4f08a2565 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -1251,7 +1251,7 @@ struct lsm_blob_sizes ima_blob_sizes __ro_after_init = {
 };
 
 DEFINE_LSM(ima) = {
-	.name = "ima",
+	.id = &ima_lsmid,
 	.init = init_ima_lsm,
 	.order = LSM_ORDER_LAST,
 	.blobs = &ima_blob_sizes,
diff --git a/security/ipe/ipe.c b/security/ipe/ipe.c
index 4317134cb0da..2426441181dc 100644
--- a/security/ipe/ipe.c
+++ b/security/ipe/ipe.c
@@ -92,7 +92,7 @@ static int __init ipe_init(void)
 }
 
 DEFINE_LSM(ipe) = {
-	.name = "ipe",
+	.id = &ipe_lsmid,
 	.init = ipe_init,
 	.blobs = &ipe_blobs,
 };
diff --git a/security/landlock/setup.c b/security/landlock/setup.c
index bd53c7a56ab9..47dac1736f10 100644
--- a/security/landlock/setup.c
+++ b/security/landlock/setup.c
@@ -75,7 +75,7 @@ static int __init landlock_init(void)
 }
 
 DEFINE_LSM(LANDLOCK_NAME) = {
-	.name = LANDLOCK_NAME,
+	.id = &landlock_lsmid,
 	.init = landlock_init,
 	.blobs = &landlock_blob_sizes,
 };
diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c
index 68252452b66c..b9ddf05c5c16 100644
--- a/security/loadpin/loadpin.c
+++ b/security/loadpin/loadpin.c
@@ -271,7 +271,7 @@ static int __init loadpin_init(void)
 }
 
 DEFINE_LSM(loadpin) = {
-	.name = "loadpin",
+	.id = &loadpin_lsmid,
 	.init = loadpin_init,
 };
 
diff --git a/security/lockdown/lockdown.c b/security/lockdown/lockdown.c
index cf83afa1d879..4813f168ff93 100644
--- a/security/lockdown/lockdown.c
+++ b/security/lockdown/lockdown.c
@@ -168,6 +168,6 @@ DEFINE_EARLY_LSM(lockdown) = {
 #else
 DEFINE_LSM(lockdown) = {
 #endif
-	.name = "lockdown",
+	.id = &lockdown_lsmid,
 	.init = lockdown_lsm_init,
 };
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 407429688f1b..d458a365b0d5 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -124,9 +124,10 @@ static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
 	/* Enable this LSM, if it is not already set. */
 	if (!lsm->enabled)
 		lsm->enabled = &lsm_enabled_true;
-	ordered_lsms[last_lsm++] = lsm;
+	ordered_lsms[last_lsm] = lsm;
+	lsm_idlist[last_lsm++] = lsm->id;
 
-	init_debug("%s ordered: %s (%s)\n", from, lsm->name,
+	init_debug("%s ordered: %s (%s)\n", from, lsm->id->name,
 		   is_enabled(lsm) ? "enabled" : "disabled");
 }
 
@@ -154,7 +155,7 @@ static void __init lsm_prep_single(struct lsm_info *lsm)
 		set_enabled(lsm, false);
 		return;
 	} else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
-		init_debug("exclusive disabled: %s\n", lsm->name);
+		init_debug("exclusive disabled: %s\n", lsm->id->name);
 		set_enabled(lsm, false);
 		return;
 	}
@@ -162,7 +163,7 @@ static void __init lsm_prep_single(struct lsm_info *lsm)
 	/* Mark the LSM as enabled. */
 	set_enabled(lsm, true);
 	if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
-		init_debug("exclusive chosen:   %s\n", lsm->name);
+		init_debug("exclusive chosen:   %s\n", lsm->id->name);
 		exclusive = lsm;
 	}
 
@@ -194,9 +195,9 @@ static void __init initialize_lsm(struct lsm_info *lsm)
 	if (is_enabled(lsm)) {
 		int ret;
 
-		init_debug("initializing %s\n", lsm->name);
+		init_debug("initializing %s\n", lsm->id->name);
 		ret = lsm->init();
-		WARN(ret, "%s failed to initialize: %d\n", lsm->name, ret);
+		WARN(ret, "%s failed to initialize: %d\n", lsm->id->name, ret);
 	}
 }
 
@@ -231,10 +232,10 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
 		for (major = __start_lsm_info; major < __end_lsm_info;
 		     major++) {
 			if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
-			    strcmp(major->name, chosen_major_lsm) != 0) {
+			    strcmp(major->id->name, chosen_major_lsm) != 0) {
 				set_enabled(major, false);
 				init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
-					   chosen_major_lsm, major->name);
+					   chosen_major_lsm, major->id->name);
 			}
 		}
 	}
@@ -246,7 +247,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
 		bool found = false;
 
 		for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
-			if (strcmp(lsm->name, name) == 0) {
+			if (strcmp(lsm->id->name, name) == 0) {
 				if (lsm->order == LSM_ORDER_MUTABLE)
 					append_ordered_lsm(lsm, origin);
 				found = true;
@@ -263,7 +264,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
 		for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
 			if (exists_ordered_lsm(lsm))
 				continue;
-			if (strcmp(lsm->name, chosen_major_lsm) == 0)
+			if (strcmp(lsm->id->name, chosen_major_lsm) == 0)
 				append_ordered_lsm(lsm, "security=");
 		}
 	}
@@ -280,7 +281,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
 			continue;
 		set_enabled(lsm, false);
 		init_debug("%s skipped: %s (not in requested order)\n",
-			   origin, lsm->name);
+			   origin, lsm->id->name);
 	}
 
 	kfree(sep);
@@ -313,12 +314,12 @@ static void __init lsm_init_ordered(void)
 		if (is_enabled(early))
 			pr_cont("%s%s",
 				early == __start_early_lsm_info ? "" : ",",
-				early->name);
+				early->id->name);
 	}
 	lsm_order_for_each(lsm) {
 		if (is_enabled(*lsm))
 			pr_cont("%s%s",
-				lsm == ordered_lsms ? "" : ",", (*lsm)->name);
+				lsm == ordered_lsms ? "" : ",", (*lsm)->id->name);
 	}
 	pr_cont("\n");
 
@@ -426,18 +427,6 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
 {
 	int i;
 
-	/*
-	 * A security module may call security_add_hooks() more
-	 * than once during initialization, and LSM initialization
-	 * is serialized. Landlock is one such case.
-	 * Look at the previous entry, if there is one, for duplication.
-	 */
-	if (lsm_active_cnt == 0 || lsm_idlist[lsm_active_cnt - 1] != lsmid) {
-		if (lsm_active_cnt >= MAX_LSM_COUNT)
-			panic("%s Too many LSMs registered.\n", __func__);
-		lsm_idlist[lsm_active_cnt++] = lsmid;
-	}
-
 	for (i = 0; i < count; i++) {
 		hooks[i].lsmid = lsmid;
 		lsm_static_call_init(&hooks[i]);
@@ -485,10 +474,10 @@ int __init security_init(void)
 	 * available
 	 */
 	lsm_early_for_each_raw(lsm) {
-		init_debug("  early started: %s (%s)\n", lsm->name,
+		init_debug("  early started: %s (%s)\n", lsm->id->name,
 			   is_enabled(lsm) ? "enabled" : "disabled");
 		if (lsm->enabled)
-			lsm_append(lsm->name, &lsm_names);
+			lsm_append(lsm->id->name, &lsm_names);
 	}
 
 	/* Load LSMs in specified order. */
diff --git a/security/safesetid/lsm.c b/security/safesetid/lsm.c
index 1ba564f097f5..9a7c68d4e642 100644
--- a/security/safesetid/lsm.c
+++ b/security/safesetid/lsm.c
@@ -287,6 +287,6 @@ static int __init safesetid_security_init(void)
 }
 
 DEFINE_LSM(safesetid_security_init) = {
+	.id = &safesetid_lsmid,
 	.init = safesetid_security_init,
-	.name = "safesetid",
 };
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index e7a7dcab81db..f28a12a0a1c8 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -7562,7 +7562,7 @@ void selinux_complete_init(void)
 /* SELinux requires early initialization in order to label
    all processes and objects when they are created. */
 DEFINE_LSM(selinux) = {
-	.name = "selinux",
+	.id = &selinux_lsmid,
 	.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
 	.enabled = &selinux_enabled_boot,
 	.blobs = &selinux_blob_sizes,
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 99833168604e..e09b33fed5f0 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -5282,7 +5282,7 @@ static __init int smack_init(void)
  * all processes and objects when they are created.
  */
 DEFINE_LSM(smack) = {
-	.name = "smack",
+	.id = &smack_lsmid,
 	.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
 	.blobs = &smack_blob_sizes,
 	.init = smack_init,
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index d6ebcd9db80a..ed0f7b052a85 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -612,7 +612,7 @@ static int __init tomoyo_init(void)
 }
 
 DEFINE_LSM(tomoyo) = {
-	.name = "tomoyo",
+	.id = &tomoyo_lsmid,
 	.enabled = &tomoyo_enabled,
 	.flags = LSM_FLAG_LEGACY_MAJOR,
 	.blobs = &tomoyo_blob_sizes,
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c
index 3d064dd4e03f..38b21ee0c560 100644
--- a/security/yama/yama_lsm.c
+++ b/security/yama/yama_lsm.c
@@ -476,6 +476,6 @@ static int __init yama_init(void)
 }
 
 DEFINE_LSM(yama) = {
-	.name = "yama",
+	.id = &yama_lsmid,
 	.init = yama_init,
 };
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 06/29] lsm: cleanup and normalize the LSM order symbols naming
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (4 preceding siblings ...)
  2025-04-09 18:49 ` [RFC PATCH 05/29] lsm: replace the name field with a pointer to the lsm_id struct Paul Moore
@ 2025-04-09 18:49 ` Paul Moore
  2025-04-09 23:00   ` Kees Cook
  2025-04-15 22:23   ` John Johansen
  2025-04-09 18:49 ` [RFC PATCH 07/29] lsm: rework lsm_active_cnt and lsm_idlist[] Paul Moore
                   ` (23 subsequent siblings)
  29 siblings, 2 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:49 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

One part of a larger effort to cleanup the LSM framework initialization
code.

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 security/lsm_init.c | 88 +++++++++++++++++++++++++--------------------
 1 file changed, 49 insertions(+), 39 deletions(-)

diff --git a/security/lsm_init.c b/security/lsm_init.c
index d458a365b0d5..edf2f4140eaa 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -16,14 +16,14 @@ char *lsm_names;
 extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
 extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
 
-/* Boot-time LSM user choice */
-static __initconst const char *const builtin_lsm_order = CONFIG_LSM;
-static __initdata const char *chosen_lsm_order;
-static __initdata const char *chosen_major_lsm;
+/* Build and boot-time LSM ordering. */
+static __initconst const char *const lsm_order_builtin = CONFIG_LSM;
+static __initdata const char *lsm_order_cmdline;
+static __initdata const char *lsm_order_legacy;
 
 /* Ordered list of LSMs to initialize. */
-static __initdata struct lsm_info *ordered_lsms[MAX_LSM_COUNT + 1];
-static __initdata struct lsm_info *exclusive;
+static __initdata struct lsm_info *lsm_order[MAX_LSM_COUNT + 1];
+static __initdata struct lsm_info *lsm_exclusive;
 
 static __initdata bool debug;
 #define init_debug(...)							\
@@ -33,36 +33,46 @@ static __initdata bool debug;
 	} while (0)
 
 #define lsm_order_for_each(iter)					\
-	for ((iter) = ordered_lsms; *(iter); (iter)++)
+	for ((iter) = lsm_order; *(iter); (iter)++)
 #define lsm_early_for_each_raw(iter)					\
 	for ((iter) = __start_early_lsm_info;				\
 	     (iter) < __end_early_lsm_info; (iter)++)
 
-static int lsm_append(const char *new, char **result);
-
-/* Save user chosen LSM */
-static int __init choose_major_lsm(char *str)
+/**
+ * lsm_choose_security - Legacy "major" LSM selection
+ * @str: kernel command line parameter
+ */
+static int __init lsm_choose_security(char *str)
 {
-	chosen_major_lsm = str;
+	lsm_order_legacy = str;
 	return 1;
 }
-__setup("security=", choose_major_lsm);
+__setup("security=", lsm_choose_security);
 
-/* Explicitly choose LSM initialization order. */
-static int __init choose_lsm_order(char *str)
+/**
+ * lsm_choose_lsm - Modern LSM selection
+ * @str: kernel command line parameter
+ */
+static int __init lsm_choose_lsm(char *str)
 {
-	chosen_lsm_order = str;
+	lsm_order_cmdline = str;
 	return 1;
 }
-__setup("lsm=", choose_lsm_order);
+__setup("lsm=", lsm_choose_lsm);
 
-/* Enable LSM order debugging. */
-static int __init enable_debug(char *str)
+/**
+ * lsm_debug_enable - Enable LSM framework debugging
+ * @str: kernel command line parameter
+ *
+ * Currently we only provide debug info during LSM initialization, but we may
+ * want to expand this in the future.
+ */
+static int __init lsm_debug_enable(char *str)
 {
 	debug = true;
 	return 1;
 }
-__setup("lsm.debug", enable_debug);
+__setup("lsm.debug", lsm_debug_enable);
 
 /* Mark an LSM's enabled flag. */
 static int lsm_enabled_true __initdata = 1;
@@ -124,7 +134,7 @@ static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
 	/* Enable this LSM, if it is not already set. */
 	if (!lsm->enabled)
 		lsm->enabled = &lsm_enabled_true;
-	ordered_lsms[last_lsm] = lsm;
+	lsm_order[last_lsm] = lsm;
 	lsm_idlist[last_lsm++] = lsm->id;
 
 	init_debug("%s ordered: %s (%s)\n", from, lsm->id->name,
@@ -154,7 +164,7 @@ static void __init lsm_prep_single(struct lsm_info *lsm)
 	if (!is_enabled(lsm)) {
 		set_enabled(lsm, false);
 		return;
-	} else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
+	} else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && lsm_exclusive) {
 		init_debug("exclusive disabled: %s\n", lsm->id->name);
 		set_enabled(lsm, false);
 		return;
@@ -162,9 +172,9 @@ static void __init lsm_prep_single(struct lsm_info *lsm)
 
 	/* Mark the LSM as enabled. */
 	set_enabled(lsm, true);
-	if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
+	if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !lsm_exclusive) {
 		init_debug("exclusive chosen:   %s\n", lsm->id->name);
-		exclusive = lsm;
+		lsm_exclusive = lsm;
 	}
 
 	/* Register the LSM blob sizes. */
@@ -220,7 +230,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
 	}
 
 	/* Process "security=", if given. */
-	if (chosen_major_lsm) {
+	if (lsm_order_legacy) {
 		struct lsm_info *major;
 
 		/*
@@ -232,10 +242,10 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
 		for (major = __start_lsm_info; major < __end_lsm_info;
 		     major++) {
 			if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
-			    strcmp(major->id->name, chosen_major_lsm) != 0) {
+			    strcmp(major->id->name, lsm_order_legacy) != 0) {
 				set_enabled(major, false);
 				init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
-					   chosen_major_lsm, major->id->name);
+					   lsm_order_legacy, major->id->name);
 			}
 		}
 	}
@@ -260,11 +270,11 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
 	}
 
 	/* Process "security=", if given. */
-	if (chosen_major_lsm) {
+	if (lsm_order_legacy) {
 		for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
 			if (exists_ordered_lsm(lsm))
 				continue;
-			if (strcmp(lsm->id->name, chosen_major_lsm) == 0)
+			if (strcmp(lsm->id->name, lsm_order_legacy) == 0)
 				append_ordered_lsm(lsm, "security=");
 		}
 	}
@@ -295,15 +305,15 @@ static void __init lsm_init_ordered(void)
 	struct lsm_info **lsm;
 	struct lsm_info *early;
 
-	if (chosen_lsm_order) {
-		if (chosen_major_lsm) {
+	if (lsm_order_cmdline) {
+		if (lsm_order_legacy) {
 			pr_warn("security=%s is ignored because it is superseded by lsm=%s\n",
-				chosen_major_lsm, chosen_lsm_order);
-			chosen_major_lsm = NULL;
+				lsm_order_legacy, lsm_order_cmdline);
+			lsm_order_legacy = NULL;
 		}
-		ordered_lsm_parse(chosen_lsm_order, "cmdline");
+		ordered_lsm_parse(lsm_order_cmdline, "cmdline");
 	} else
-		ordered_lsm_parse(builtin_lsm_order, "builtin");
+		ordered_lsm_parse(lsm_order_builtin, "builtin");
 
 	lsm_order_for_each(lsm) {
 		lsm_prep_single(*lsm);
@@ -319,7 +329,7 @@ static void __init lsm_init_ordered(void)
 	lsm_order_for_each(lsm) {
 		if (is_enabled(*lsm))
 			pr_cont("%s%s",
-				lsm == ordered_lsms ? "" : ",", (*lsm)->id->name);
+				lsm == lsm_order ? "" : ",", (*lsm)->id->name);
 	}
 	pr_cont("\n");
 
@@ -465,9 +475,9 @@ int __init security_init(void)
 {
 	struct lsm_info *lsm;
 
-	init_debug("legacy security=%s\n", chosen_major_lsm ? : " *unspecified*");
-	init_debug("  CONFIG_LSM=%s\n", builtin_lsm_order);
-	init_debug("boot arg lsm=%s\n", chosen_lsm_order ? : " *unspecified*");
+	init_debug("legacy security=%s\n", lsm_order_legacy ? : " *unspecified*");
+	init_debug("  CONFIG_LSM=%s\n", lsm_order_builtin);
+	init_debug("boot arg lsm=%s\n", lsm_order_cmdline ? : " *unspecified*");
 
 	/*
 	 * Append the names of the early LSM modules now that kmalloc() is
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 07/29] lsm: rework lsm_active_cnt and lsm_idlist[]
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (5 preceding siblings ...)
  2025-04-09 18:49 ` [RFC PATCH 06/29] lsm: cleanup and normalize the LSM order symbols naming Paul Moore
@ 2025-04-09 18:49 ` Paul Moore
  2025-04-09 21:38   ` Casey Schaufler
  2025-04-09 23:06   ` Kees Cook
  2025-04-09 18:49 ` [RFC PATCH 08/29] lsm: get rid of the lsm_names list and do some cleanup Paul Moore
                   ` (22 subsequent siblings)
  29 siblings, 2 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:49 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

Move the LSM count and lsm_id list declarations out of a header that is
visible across the kernel and into a header that is limited to the LSM
framework.  This not only helps keep the include/linux headers smaller
and cleaner, it helps prevent misuse of these variables.

During the move, lsm_active_cnt was renamed to lsm_count for the sake
of brevity.

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 include/linux/security.h | 2 --
 security/lsm.h           | 5 +++++
 security/lsm_init.c      | 8 +-------
 security/lsm_syscalls.c  | 8 +++++---
 security/security.c      | 3 +++
 5 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/include/linux/security.h b/include/linux/security.h
index cc9b54d95d22..8aac21787a9f 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -167,8 +167,6 @@ struct lsm_prop {
 };
 
 extern const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1];
-extern u32 lsm_active_cnt;
-extern const struct lsm_id *lsm_idlist[];
 
 /* These functions are in security/commoncap.c */
 extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
diff --git a/security/lsm.h b/security/lsm.h
index 0e1731bad4a7..af343072199d 100644
--- a/security/lsm.h
+++ b/security/lsm.h
@@ -7,6 +7,11 @@
 #define _LSM_H_
 
 #include <linux/lsm_hooks.h>
+#include <linux/lsm_count.h>
+
+/* List of configured LSMs */
+extern unsigned int lsm_count;
+extern const struct lsm_id *lsm_idlist[];
 
 /* LSM blob configuration */
 extern struct lsm_blob_sizes blob_sizes;
diff --git a/security/lsm_init.c b/security/lsm_init.c
index edf2f4140eaa..981ddb20f48e 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -22,8 +22,8 @@ static __initdata const char *lsm_order_cmdline;
 static __initdata const char *lsm_order_legacy;
 
 /* Ordered list of LSMs to initialize. */
-static __initdata struct lsm_info *lsm_order[MAX_LSM_COUNT + 1];
 static __initdata struct lsm_info *lsm_exclusive;
+static __initdata struct lsm_info *lsm_order[MAX_LSM_COUNT + 1];
 
 static __initdata bool debug;
 #define init_debug(...)							\
@@ -211,12 +211,6 @@ static void __init initialize_lsm(struct lsm_info *lsm)
 	}
 }
 
-/*
- * Current index to use while initializing the lsm id list.
- */
-u32 lsm_active_cnt __ro_after_init;
-const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
-
 /* Populate ordered LSMs list from comma-separated LSM name list. */
 static void __init ordered_lsm_parse(const char *order, const char *origin)
 {
diff --git a/security/lsm_syscalls.c b/security/lsm_syscalls.c
index 8440948a690c..3fb0d77ae65c 100644
--- a/security/lsm_syscalls.c
+++ b/security/lsm_syscalls.c
@@ -17,6 +17,8 @@
 #include <linux/lsm_hooks.h>
 #include <uapi/linux/lsm.h>
 
+#include "lsm.h"
+
 /**
  * lsm_name_to_attr - map an LSM attribute name to its ID
  * @name: name of the attribute
@@ -96,7 +98,7 @@ SYSCALL_DEFINE4(lsm_get_self_attr, unsigned int, attr, struct lsm_ctx __user *,
 SYSCALL_DEFINE3(lsm_list_modules, u64 __user *, ids, u32 __user *, size,
 		u32, flags)
 {
-	u32 total_size = lsm_active_cnt * sizeof(*ids);
+	u32 total_size = lsm_count * sizeof(*ids);
 	u32 usize;
 	int i;
 
@@ -112,9 +114,9 @@ SYSCALL_DEFINE3(lsm_list_modules, u64 __user *, ids, u32 __user *, size,
 	if (usize < total_size)
 		return -E2BIG;
 
-	for (i = 0; i < lsm_active_cnt; i++)
+	for (i = 0; i < lsm_count; i++)
 		if (put_user(lsm_idlist[i]->id, ids++))
 			return -EFAULT;
 
-	return lsm_active_cnt;
+	return lsm_count;
 }
diff --git a/security/security.c b/security/security.c
index 8d370a4c5e74..a3e8dd640b39 100644
--- a/security/security.c
+++ b/security/security.c
@@ -73,6 +73,9 @@ const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX + 1] = {
 	[LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality",
 };
 
+unsigned int lsm_count __ro_after_init;
+const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
+
 struct lsm_blob_sizes blob_sizes;
 
 struct kmem_cache *lsm_file_cache;
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 08/29] lsm: get rid of the lsm_names list and do some cleanup
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (6 preceding siblings ...)
  2025-04-09 18:49 ` [RFC PATCH 07/29] lsm: rework lsm_active_cnt and lsm_idlist[] Paul Moore
@ 2025-04-09 18:49 ` Paul Moore
  2025-04-09 23:13   ` Kees Cook
  2025-05-22 21:26   ` Casey Schaufler
  2025-04-09 18:49 ` [RFC PATCH 09/29] lsm: cleanup and normalize the LSM enabled functions Paul Moore
                   ` (21 subsequent siblings)
  29 siblings, 2 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:49 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

The LSM currently has a lot of code to maintain a list of the
currently active LSMs in a human readable string, with the only
user being the "/sys/kernel/security/lsm" code.  Let's drop all
of that code and generate the string on an as-needed basis when
userspace reads "/sys/kernel/security/lsm".

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 include/linux/lsm_hooks.h |  1 -
 security/inode.c          | 27 +++++++++++++++++++--
 security/lsm_init.c       | 49 ---------------------------------------
 3 files changed, 25 insertions(+), 52 deletions(-)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 4cd17c9a229f..bc477fb20d02 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -169,7 +169,6 @@ struct lsm_info {
 
 
 /* DO NOT tamper with these variables outside of the LSM framework */
-extern char *lsm_names;
 extern struct lsm_static_calls_table static_calls_table __ro_after_init;
 
 /**
diff --git a/security/inode.c b/security/inode.c
index da3ab44c8e57..49bc3578bd23 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -22,6 +22,8 @@
 #include <linux/lsm_hooks.h>
 #include <linux/magic.h>
 
+#include "lsm.h"
+
 static struct vfsmount *mount;
 static int mount_count;
 
@@ -343,8 +345,29 @@ static struct dentry *lsm_dentry;
 static ssize_t lsm_read(struct file *filp, char __user *buf, size_t count,
 			loff_t *ppos)
 {
-	return simple_read_from_buffer(buf, count, ppos, lsm_names,
-		strlen(lsm_names));
+	int i;
+	char *str;
+	ssize_t rc, len = 0;
+
+	for (i = 0; i < lsm_count; i++)
+		/* the '+ 1' accounts for either a comma or a NUL terminator */
+		len += strlen(lsm_order[i]->id->name) + 1;
+
+	str = kmalloc(len, GFP_KERNEL);
+	if (!str)
+		return -ENOMEM;
+	str[0] = '\0';
+
+	i = 0;
+	while (i < lsm_count) {
+		strcat(str, lsm_order[i]->id->name);
+		if (++i < lsm_count)
+			strcat(str, ",");
+	}
+
+	rc = simple_read_from_buffer(buf, count, ppos, str, len);
+	kfree(str);
+	return rc;
 }
 
 static const struct file_operations lsm_ops = {
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 981ddb20f48e..978bb81b58fa 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -10,8 +10,6 @@
 
 #include "lsm.h"
 
-char *lsm_names;
-
 /* Pointers to LSM sections defined in include/asm-generic/vmlinux.lds.h */
 extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
 extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
@@ -363,42 +361,6 @@ static void __init lsm_init_ordered(void)
 	}
 }
 
-static bool match_last_lsm(const char *list, const char *lsm)
-{
-	const char *last;
-
-	if (WARN_ON(!list || !lsm))
-		return false;
-	last = strrchr(list, ',');
-	if (last)
-		/* Pass the comma, strcmp() will check for '\0' */
-		last++;
-	else
-		last = list;
-	return !strcmp(last, lsm);
-}
-
-static int lsm_append(const char *new, char **result)
-{
-	char *cp;
-
-	if (*result == NULL) {
-		*result = kstrdup(new, GFP_KERNEL);
-		if (*result == NULL)
-			return -ENOMEM;
-	} else {
-		/* Check if it is the last registered name */
-		if (match_last_lsm(*result, new))
-			return 0;
-		cp = kasprintf(GFP_KERNEL, "%s,%s", *result, new);
-		if (cp == NULL)
-			return -ENOMEM;
-		kfree(*result);
-		*result = cp;
-	}
-	return 0;
-}
-
 static void __init lsm_static_call_init(struct security_hook_list *hl)
 {
 	struct lsm_static_call *scall = hl->scalls;
@@ -435,15 +397,6 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
 		hooks[i].lsmid = lsmid;
 		lsm_static_call_init(&hooks[i]);
 	}
-
-	/*
-	 * Don't try to append during early_security_init(), we'll come back
-	 * and fix this up afterwards.
-	 */
-	if (slab_is_available()) {
-		if (lsm_append(lsmid->name, &lsm_names) < 0)
-			panic("%s - Cannot get early memory.\n", __func__);
-	}
 }
 
 int __init early_security_init(void)
@@ -480,8 +433,6 @@ int __init security_init(void)
 	lsm_early_for_each_raw(lsm) {
 		init_debug("  early started: %s (%s)\n", lsm->id->name,
 			   is_enabled(lsm) ? "enabled" : "disabled");
-		if (lsm->enabled)
-			lsm_append(lsm->id->name, &lsm_names);
 	}
 
 	/* Load LSMs in specified order. */
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 09/29] lsm: cleanup and normalize the LSM enabled functions
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (7 preceding siblings ...)
  2025-04-09 18:49 ` [RFC PATCH 08/29] lsm: get rid of the lsm_names list and do some cleanup Paul Moore
@ 2025-04-09 18:49 ` Paul Moore
  2025-04-10  0:11   ` Kees Cook
  2025-04-09 18:49 ` [RFC PATCH 10/29] lsm: cleanup the LSM blob size code Paul Moore
                   ` (20 subsequent siblings)
  29 siblings, 1 reply; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:49 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

One part of a larger effort to cleanup the LSM framework initialization
code.

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 security/inode.c    |   9 ++--
 security/lsm_init.c | 110 ++++++++++++++++++++++++--------------------
 2 files changed, 63 insertions(+), 56 deletions(-)

diff --git a/security/inode.c b/security/inode.c
index 49bc3578bd23..f687e22e6809 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -351,18 +351,17 @@ static ssize_t lsm_read(struct file *filp, char __user *buf, size_t count,
 
 	for (i = 0; i < lsm_count; i++)
 		/* the '+ 1' accounts for either a comma or a NUL terminator */
-		len += strlen(lsm_order[i]->id->name) + 1;
+		len += strlen(lsm_idlist[i]->name) + 1;
 
 	str = kmalloc(len, GFP_KERNEL);
 	if (!str)
 		return -ENOMEM;
 	str[0] = '\0';
 
-	i = 0;
-	while (i < lsm_count) {
-		strcat(str, lsm_order[i]->id->name);
-		if (++i < lsm_count)
+	for (i = 0; i < lsm_count; i++) {
+		if (i > 0)
 			strcat(str, ",");
+		strcat(str, lsm_idlist[i]->name);
 	}
 
 	rc = simple_read_from_buffer(buf, count, ppos, str, len);
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 978bb81b58fa..7f2bc8c22ce9 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -10,6 +10,10 @@
 
 #include "lsm.h"
 
+/* LSM enabled constants. */
+int lsm_enabled_true = 1;
+int lsm_enabled_false = 0;
+
 /* Pointers to LSM sections defined in include/asm-generic/vmlinux.lds.h */
 extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
 extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
@@ -72,41 +76,42 @@ static int __init lsm_debug_enable(char *str)
 }
 __setup("lsm.debug", lsm_debug_enable);
 
-/* Mark an LSM's enabled flag. */
-static int lsm_enabled_true __initdata = 1;
-static int lsm_enabled_false __initdata = 0;
-static void __init set_enabled(struct lsm_info *lsm, bool enabled)
+/**
+ * lsm_enabled_set - Mark a LSM as enabled
+ * @lsm: LSM definition
+ * @enabled: enabled flag
+ */
+static void __init lsm_enabled_set(struct lsm_info *lsm, bool enabled)
 {
 	/*
 	 * When an LSM hasn't configured an enable variable, we can use
 	 * a hard-coded location for storing the default enabled state.
 	 */
-	if (!lsm->enabled) {
-		if (enabled)
-			lsm->enabled = &lsm_enabled_true;
-		else
-			lsm->enabled = &lsm_enabled_false;
-	} else if (lsm->enabled == &lsm_enabled_true) {
-		if (!enabled)
-			lsm->enabled = &lsm_enabled_false;
-	} else if (lsm->enabled == &lsm_enabled_false) {
-		if (enabled)
-			lsm->enabled = &lsm_enabled_true;
+	if (!lsm->enabled ||
+	    lsm->enabled == &lsm_enabled_true ||
+	    lsm->enabled == &lsm_enabled_false) {
+		lsm->enabled = enabled ? &lsm_enabled_true : &lsm_enabled_false;
 	} else {
 		*lsm->enabled = enabled;
 	}
 }
 
-static inline bool is_enabled(struct lsm_info *lsm)
+/**
+ * lsm_is_enabled - Determine if a LSM is enabled
+ * @lsm: LSM definition
+ */
+static inline bool lsm_is_enabled(struct lsm_info *lsm)
 {
 	if (!lsm->enabled)
 		return false;
-
 	return *lsm->enabled;
 }
 
-/* Is an LSM already listed in the ordered LSMs list? */
-static bool __init exists_ordered_lsm(struct lsm_info *lsm)
+/**
+ * lsm_order_exists - Determine if a LSM exists in the ordered list
+ * @lsm: LSM definition
+ */
+static bool __init lsm_order_exists(struct lsm_info *lsm)
 {
 	struct lsm_info **check;
 
@@ -118,25 +123,29 @@ static bool __init exists_ordered_lsm(struct lsm_info *lsm)
 	return false;
 }
 
-/* Append an LSM to the list of ordered LSMs to initialize. */
-static int last_lsm __initdata;
-static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
+/**
+ * lsm_order_append - Append a LSM to the ordered list
+ * @lsm: LSM definition
+ * @src: source of the addition
+ */
+static void __init lsm_order_append(struct lsm_info *lsm, const char *src)
 {
 	/* Ignore duplicate selections. */
-	if (exists_ordered_lsm(lsm))
+	if (lsm_order_exists(lsm))
 		return;
 
-	if (WARN(last_lsm == MAX_LSM_COUNT, "%s: out of LSM static calls!?\n", from))
-		return;
+	/* Skip explicitly disabled LSMs. */
+	if (lsm->enabled && !lsm_is_enabled(lsm)) {
+		if (WARN(lsm_count == MAX_LSM_COUNT,
+			 "%s: out of LSM static calls!?\n", src))
+			return;
+		lsm_enabled_set(lsm, true);
+		lsm_order[lsm_count] = lsm;
+		lsm_idlist[lsm_count++] = lsm->id;
+	}
 
-	/* Enable this LSM, if it is not already set. */
-	if (!lsm->enabled)
-		lsm->enabled = &lsm_enabled_true;
-	lsm_order[last_lsm] = lsm;
-	lsm_idlist[last_lsm++] = lsm->id;
-
-	init_debug("%s ordered: %s (%s)\n", from, lsm->id->name,
-		   is_enabled(lsm) ? "enabled" : "disabled");
+	init_debug("%s ordered: %s (%s)\n", src, lsm->id->name,
+		   lsm_is_enabled(lsm) ? "enabled" : "disabled");
 }
 
 static void __init lsm_set_blob_size(int *need, int *lbs)
@@ -159,17 +168,17 @@ static void __init lsm_prep_single(struct lsm_info *lsm)
 {
 	struct lsm_blob_sizes *blobs;
 
-	if (!is_enabled(lsm)) {
-		set_enabled(lsm, false);
+	if (!lsm_is_enabled(lsm)) {
+		lsm_enabled_set(lsm, false);
 		return;
 	} else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && lsm_exclusive) {
 		init_debug("exclusive disabled: %s\n", lsm->id->name);
-		set_enabled(lsm, false);
+		lsm_enabled_set(lsm, false);
 		return;
 	}
 
 	/* Mark the LSM as enabled. */
-	set_enabled(lsm, true);
+	lsm_enabled_set(lsm, true);
 	if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !lsm_exclusive) {
 		init_debug("exclusive chosen:   %s\n", lsm->id->name);
 		lsm_exclusive = lsm;
@@ -200,7 +209,7 @@ static void __init lsm_prep_single(struct lsm_info *lsm)
 /* Initialize a given LSM, if it is enabled. */
 static void __init initialize_lsm(struct lsm_info *lsm)
 {
-	if (is_enabled(lsm)) {
+	if (lsm_is_enabled(lsm)) {
 		int ret;
 
 		init_debug("initializing %s\n", lsm->id->name);
@@ -218,7 +227,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
 	/* LSM_ORDER_FIRST is always first. */
 	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
 		if (lsm->order == LSM_ORDER_FIRST)
-			append_ordered_lsm(lsm, "  first");
+			lsm_order_append(lsm, "  first");
 	}
 
 	/* Process "security=", if given. */
@@ -235,7 +244,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
 		     major++) {
 			if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
 			    strcmp(major->id->name, lsm_order_legacy) != 0) {
-				set_enabled(major, false);
+				lsm_enabled_set(major, false);
 				init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
 					   lsm_order_legacy, major->id->name);
 			}
@@ -251,7 +260,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
 		for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
 			if (strcmp(lsm->id->name, name) == 0) {
 				if (lsm->order == LSM_ORDER_MUTABLE)
-					append_ordered_lsm(lsm, origin);
+					lsm_order_append(lsm, origin);
 				found = true;
 			}
 		}
@@ -264,24 +273,24 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
 	/* Process "security=", if given. */
 	if (lsm_order_legacy) {
 		for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
-			if (exists_ordered_lsm(lsm))
+			if (lsm_order_exists(lsm))
 				continue;
 			if (strcmp(lsm->id->name, lsm_order_legacy) == 0)
-				append_ordered_lsm(lsm, "security=");
+				lsm_order_append(lsm, "security=");
 		}
 	}
 
 	/* LSM_ORDER_LAST is always last. */
 	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
 		if (lsm->order == LSM_ORDER_LAST)
-			append_ordered_lsm(lsm, "   last");
+			lsm_order_append(lsm, "   last");
 	}
 
 	/* Disable all LSMs not in the ordered list. */
 	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
-		if (exists_ordered_lsm(lsm))
+		if (lsm_order_exists(lsm))
 			continue;
-		set_enabled(lsm, false);
+		lsm_enabled_set(lsm, false);
 		init_debug("%s skipped: %s (not in requested order)\n",
 			   origin, lsm->id->name);
 	}
@@ -313,13 +322,13 @@ static void __init lsm_init_ordered(void)
 
 	pr_info("initializing lsm=");
 	lsm_early_for_each_raw(early) {
-		if (is_enabled(early))
+		if (lsm_is_enabled(early))
 			pr_cont("%s%s",
 				early == __start_early_lsm_info ? "" : ",",
 				early->id->name);
 	}
 	lsm_order_for_each(lsm) {
-		if (is_enabled(*lsm))
+		if (lsm_is_enabled(*lsm))
 			pr_cont("%s%s",
 				lsm == lsm_order ? "" : ",", (*lsm)->id->name);
 	}
@@ -404,8 +413,7 @@ int __init early_security_init(void)
 	struct lsm_info *lsm;
 
 	lsm_early_for_each_raw(lsm) {
-		if (!lsm->enabled)
-			lsm->enabled = &lsm_enabled_true;
+		lsm_enabled_set(lsm, true);
 		lsm_prep_single(lsm);
 		initialize_lsm(lsm);
 	}
@@ -432,7 +440,7 @@ int __init security_init(void)
 	 */
 	lsm_early_for_each_raw(lsm) {
 		init_debug("  early started: %s (%s)\n", lsm->id->name,
-			   is_enabled(lsm) ? "enabled" : "disabled");
+			   lsm_is_enabled(lsm) ? "enabled" : "disabled");
 	}
 
 	/* Load LSMs in specified order. */
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 10/29] lsm: cleanup the LSM blob size code
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (8 preceding siblings ...)
  2025-04-09 18:49 ` [RFC PATCH 09/29] lsm: cleanup and normalize the LSM enabled functions Paul Moore
@ 2025-04-09 18:49 ` Paul Moore
  2025-04-09 23:29   ` Kees Cook
                     ` (2 more replies)
  2025-04-09 18:49 ` [RFC PATCH 11/29] lsm: cleanup initialize_lsm() and rename to lsm_init_single() Paul Moore
                   ` (19 subsequent siblings)
  29 siblings, 3 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:49 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

Convert the lsm_blob_size fields to unsigned integers as there is no
current need for them to be negative, change "lsm_set_blob_size()" to
"lsm_blob_size_update()" to better reflect reality, and perform some
other minor cleanups to the associated code.

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 include/linux/lsm_hooks.h | 28 +++++++++++-----------
 security/lsm_init.c       | 50 +++++++++++++++++++++++----------------
 2 files changed, 43 insertions(+), 35 deletions(-)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index bc477fb20d02..a7ecb0791a0f 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -102,20 +102,20 @@ struct security_hook_list {
  * Security blob size or offset data.
  */
 struct lsm_blob_sizes {
-	int lbs_cred;
-	int lbs_file;
-	int lbs_ib;
-	int lbs_inode;
-	int lbs_sock;
-	int lbs_superblock;
-	int lbs_ipc;
-	int lbs_key;
-	int lbs_msg_msg;
-	int lbs_perf_event;
-	int lbs_task;
-	int lbs_xattr_count; /* number of xattr slots in new_xattrs array */
-	int lbs_tun_dev;
-	int lbs_bdev;
+	unsigned int lbs_cred;
+	unsigned int lbs_file;
+	unsigned int lbs_ib;
+	unsigned int lbs_inode;
+	unsigned int lbs_sock;
+	unsigned int lbs_superblock;
+	unsigned int lbs_ipc;
+	unsigned int lbs_key;
+	unsigned int lbs_msg_msg;
+	unsigned int lbs_perf_event;
+	unsigned int lbs_task;
+	unsigned int lbs_xattr_count; /* num xattr slots in new_xattrs array */
+	unsigned int lbs_tun_dev;
+	unsigned int lbs_bdev;
 };
 
 /*
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 7f2bc8c22ce9..9bb4b4fc9888 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -148,16 +148,22 @@ static void __init lsm_order_append(struct lsm_info *lsm, const char *src)
 		   lsm_is_enabled(lsm) ? "enabled" : "disabled");
 }
 
-static void __init lsm_set_blob_size(int *need, int *lbs)
+/**
+ * lsm_blob_size_update - Update the LSM blob size and offset information
+ * @sz_req: the requested additional blob size
+ * @sz_cur: the existing blob size
+ */
+static void __init lsm_blob_size_update(unsigned int *sz_req,
+					unsigned int *sz_cur)
 {
-	int offset;
+	unsigned int offset;
 
-	if (*need <= 0)
+	if (*sz_req == 0)
 		return;
 
-	offset = ALIGN(*lbs, sizeof(void *));
-	*lbs = offset + *need;
-	*need = offset;
+	offset = ALIGN(*sz_cur, sizeof(void *));
+	*sz_cur = offset + *sz_req;
+	*sz_req = offset;
 }
 
 /**
@@ -186,24 +192,26 @@ static void __init lsm_prep_single(struct lsm_info *lsm)
 
 	/* Register the LSM blob sizes. */
 	blobs = lsm->blobs;
-	lsm_set_blob_size(&blobs->lbs_cred, &blob_sizes.lbs_cred);
-	lsm_set_blob_size(&blobs->lbs_file, &blob_sizes.lbs_file);
-	lsm_set_blob_size(&blobs->lbs_ib, &blob_sizes.lbs_ib);
+	lsm_blob_size_update(&blobs->lbs_cred, &blob_sizes.lbs_cred);
+	lsm_blob_size_update(&blobs->lbs_file, &blob_sizes.lbs_file);
+	lsm_blob_size_update(&blobs->lbs_ib, &blob_sizes.lbs_ib);
 	/* inode blob gets an rcu_head in addition to LSM blobs. */
 	if (blobs->lbs_inode && blob_sizes.lbs_inode == 0)
 		blob_sizes.lbs_inode = sizeof(struct rcu_head);
-	lsm_set_blob_size(&blobs->lbs_inode, &blob_sizes.lbs_inode);
-	lsm_set_blob_size(&blobs->lbs_ipc, &blob_sizes.lbs_ipc);
-	lsm_set_blob_size(&blobs->lbs_key, &blob_sizes.lbs_key);
-	lsm_set_blob_size(&blobs->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
-	lsm_set_blob_size(&blobs->lbs_perf_event, &blob_sizes.lbs_perf_event);
-	lsm_set_blob_size(&blobs->lbs_sock, &blob_sizes.lbs_sock);
-	lsm_set_blob_size(&blobs->lbs_superblock, &blob_sizes.lbs_superblock);
-	lsm_set_blob_size(&blobs->lbs_task, &blob_sizes.lbs_task);
-	lsm_set_blob_size(&blobs->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
-	lsm_set_blob_size(&blobs->lbs_xattr_count,
-			  &blob_sizes.lbs_xattr_count);
-	lsm_set_blob_size(&blobs->lbs_bdev, &blob_sizes.lbs_bdev);
+	lsm_blob_size_update(&blobs->lbs_inode, &blob_sizes.lbs_inode);
+	lsm_blob_size_update(&blobs->lbs_ipc, &blob_sizes.lbs_ipc);
+	lsm_blob_size_update(&blobs->lbs_key, &blob_sizes.lbs_key);
+	lsm_blob_size_update(&blobs->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
+	lsm_blob_size_update(&blobs->lbs_perf_event,
+			     &blob_sizes.lbs_perf_event);
+	lsm_blob_size_update(&blobs->lbs_sock, &blob_sizes.lbs_sock);
+	lsm_blob_size_update(&blobs->lbs_superblock,
+			     &blob_sizes.lbs_superblock);
+	lsm_blob_size_update(&blobs->lbs_task, &blob_sizes.lbs_task);
+	lsm_blob_size_update(&blobs->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
+	lsm_blob_size_update(&blobs->lbs_xattr_count,
+			     &blob_sizes.lbs_xattr_count);
+	lsm_blob_size_update(&blobs->lbs_bdev, &blob_sizes.lbs_bdev);
 }
 
 /* Initialize a given LSM, if it is enabled. */
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 11/29] lsm: cleanup initialize_lsm() and rename to lsm_init_single()
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (9 preceding siblings ...)
  2025-04-09 18:49 ` [RFC PATCH 10/29] lsm: cleanup the LSM blob size code Paul Moore
@ 2025-04-09 18:49 ` Paul Moore
  2025-04-09 23:30   ` Kees Cook
  2025-04-15 23:04   ` John Johansen
  2025-04-09 18:49 ` [RFC PATCH 12/29] lsm: cleanup the LSM ordered parsing Paul Moore
                   ` (18 subsequent siblings)
  29 siblings, 2 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:49 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

One part of a larger effort to cleanup the LSM framework initialization
code.

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 security/lsm_init.c | 24 ++++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/security/lsm_init.c b/security/lsm_init.c
index 9bb4b4fc9888..163fc2a1a952 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -214,16 +214,20 @@ static void __init lsm_prep_single(struct lsm_info *lsm)
 	lsm_blob_size_update(&blobs->lbs_bdev, &blob_sizes.lbs_bdev);
 }
 
-/* Initialize a given LSM, if it is enabled. */
-static void __init initialize_lsm(struct lsm_info *lsm)
+/**
+ * lsm_init_single - Initialize a given LSM
+ * @lsm: LSM definition
+ */
+static void __init lsm_init_single(struct lsm_info *lsm)
 {
-	if (lsm_is_enabled(lsm)) {
-		int ret;
+	int ret;
 
-		init_debug("initializing %s\n", lsm->id->name);
-		ret = lsm->init();
-		WARN(ret, "%s failed to initialize: %d\n", lsm->id->name, ret);
-	}
+	if (!lsm_is_enabled(lsm))
+		return;
+
+	init_debug("initializing %s\n", lsm->id->name);
+	ret = lsm->init();
+	WARN(ret, "%s failed to initialize: %d\n", lsm->id->name, ret);
 }
 
 /* Populate ordered LSMs list from comma-separated LSM name list. */
@@ -374,7 +378,7 @@ static void __init lsm_init_ordered(void)
 		panic("%s: early task alloc failed.\n", __func__);
 
 	lsm_order_for_each(lsm) {
-		initialize_lsm(*lsm);
+		lsm_init_single(*lsm);
 	}
 }
 
@@ -423,7 +427,7 @@ int __init early_security_init(void)
 	lsm_early_for_each_raw(lsm) {
 		lsm_enabled_set(lsm, true);
 		lsm_prep_single(lsm);
-		initialize_lsm(lsm);
+		lsm_init_single(lsm);
 	}
 
 	return 0;
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 12/29] lsm: cleanup the LSM ordered parsing
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (10 preceding siblings ...)
  2025-04-09 18:49 ` [RFC PATCH 11/29] lsm: cleanup initialize_lsm() and rename to lsm_init_single() Paul Moore
@ 2025-04-09 18:49 ` Paul Moore
  2025-04-09 18:49 ` [RFC PATCH 13/29] lsm: fold lsm_init_ordered() into security_init() Paul Moore
                   ` (17 subsequent siblings)
  29 siblings, 0 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:49 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

One part of a larger effort to cleanup the LSM framework initialization
code.

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 security/lsm_init.c | 211 ++++++++++++++++++++++----------------------
 1 file changed, 106 insertions(+), 105 deletions(-)

diff --git a/security/lsm_init.c b/security/lsm_init.c
index 163fc2a1a952..e07fd4d2a16a 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -36,6 +36,9 @@ static __initdata bool debug;
 
 #define lsm_order_for_each(iter)					\
 	for ((iter) = lsm_order; *(iter); (iter)++)
+#define lsm_for_each_raw(iter)						\
+	for ((iter) = __start_lsm_info;					\
+	     (iter) < __end_lsm_info; (iter)++)
 #define lsm_early_for_each_raw(iter)					\
 	for ((iter) = __start_early_lsm_info;				\
 	     (iter) < __end_early_lsm_info; (iter)++)
@@ -127,6 +130,10 @@ static bool __init lsm_order_exists(struct lsm_info *lsm)
  * lsm_order_append - Append a LSM to the ordered list
  * @lsm: LSM definition
  * @src: source of the addition
+ *
+ * Append @lsm to the enabled LSM array after ensuring that it hasn't been
+ * explicitly disabled, is a duplicate entry, or would run afoul of the
+ * LSM_FLAG_EXCLUSIVE logic.
  */
 static void __init lsm_order_append(struct lsm_info *lsm, const char *src)
 {
@@ -135,19 +142,106 @@ static void __init lsm_order_append(struct lsm_info *lsm, const char *src)
 		return;
 
 	/* Skip explicitly disabled LSMs. */
-	if (lsm->enabled && !lsm_is_enabled(lsm)) {
-		if (WARN(lsm_count == MAX_LSM_COUNT,
-			 "%s: out of LSM static calls!?\n", src))
-			return;
-		lsm_enabled_set(lsm, true);
-		lsm_order[lsm_count] = lsm;
-		lsm_idlist[lsm_count++] = lsm->id;
+	if (lsm->enabled && !lsm_is_enabled(lsm))
+		goto out;
+
+	if (WARN(lsm_count == MAX_LSM_COUNT,
+		 "%s: out of LSM static calls!?\n", src)) {
+		lsm_enabled_set(lsm, false);
+		goto out;
 	}
 
+	if (lsm->flags & LSM_FLAG_EXCLUSIVE) {
+		if (lsm_exclusive) {
+			init_debug("exclusive disabled: %s\n", lsm->id->name);
+			lsm_enabled_set(lsm, false);
+			goto out;
+		} else {
+			init_debug("exclusive chosen:   %s\n", lsm->id->name);
+			lsm_exclusive = lsm;
+		}
+	}
+
+	lsm_enabled_set(lsm, true);
+	lsm_order[lsm_count] = lsm;
+	lsm_idlist[lsm_count++] = lsm->id;
+
+out:
 	init_debug("%s ordered: %s (%s)\n", src, lsm->id->name,
 		   lsm_is_enabled(lsm) ? "enabled" : "disabled");
 }
 
+/**
+ * lsm_order_parse - Parse the comma delimited LSM list
+ * @list: LSM list
+ * @src: source of the list
+ */
+static void __init lsm_order_parse(const char *list, const char *src)
+{
+	struct lsm_info *lsm;
+	char *sep, *name, *next;
+
+	/* Handle any Legacy LSM exclusions if one was specified. */
+	if (lsm_order_legacy) {
+		/*
+		 * To match the original "security=" behavior, this explicitly
+		 * does NOT fallback to another Legacy Major if the selected
+		 * one was separately disabled: disable all non-matching
+		 * Legacy Major LSMs.
+		 */
+		lsm_for_each_raw(lsm) {
+			if ((lsm->flags & LSM_FLAG_LEGACY_MAJOR) &&
+			     strcmp(lsm->id->name, lsm_order_legacy)) {
+				lsm_enabled_set(lsm, false);
+				init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
+					   lsm_order_legacy, lsm->id->name);
+			}
+		}
+	}
+
+	/* LSM_ORDER_FIRST */
+	lsm_for_each_raw(lsm) {
+		if (lsm->order == LSM_ORDER_FIRST)
+			lsm_order_append(lsm, "first");
+	}
+
+	/* Normal or "mutable" LSMs */
+	sep = kstrdup(list, GFP_KERNEL);
+	next = sep;
+	/* Walk the list, looking for matching LSMs. */
+	while ((name = strsep(&next, ",")) != NULL) {
+		lsm_for_each_raw(lsm) {
+			if (!strcmp(lsm->id->name, name) &&
+			    lsm->order == LSM_ORDER_MUTABLE)
+				lsm_order_append(lsm, src);
+		}
+	}
+	kfree(sep);
+
+	/* Legacy LSM if specified. */
+	if (lsm_order_legacy) {
+		lsm_for_each_raw(lsm) {
+			if (!strcmp(lsm->id->name, lsm_order_legacy))
+				lsm_order_append(lsm, src);
+		}
+	}
+
+	/* LSM_ORDER_LAST */
+	lsm_for_each_raw(lsm) {
+		if (lsm->order == LSM_ORDER_LAST)
+			lsm_order_append(lsm, "last");
+	}
+
+	/* Disable all LSMs not previously enabled. */
+	lsm_for_each_raw(lsm) {
+		if (lsm_order_exists(lsm))
+			continue;
+		lsm_enabled_set(lsm, false);
+		init_debug("%s skipped: %s (not in requested order)\n",
+			   src, lsm->id->name);
+	}
+}
+
 /**
  * lsm_blob_size_update - Update the LSM blob size and offset information
  * @sz_req: the requested additional blob size
@@ -172,26 +266,12 @@ static void __init lsm_blob_size_update(unsigned int *sz_req,
  */
 static void __init lsm_prep_single(struct lsm_info *lsm)
 {
-	struct lsm_blob_sizes *blobs;
+	struct lsm_blob_sizes *blobs = lsm->blobs;
 
-	if (!lsm_is_enabled(lsm)) {
-		lsm_enabled_set(lsm, false);
+	if (!blobs)
 		return;
-	} else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && lsm_exclusive) {
-		init_debug("exclusive disabled: %s\n", lsm->id->name);
-		lsm_enabled_set(lsm, false);
-		return;
-	}
-
-	/* Mark the LSM as enabled. */
-	lsm_enabled_set(lsm, true);
-	if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !lsm_exclusive) {
-		init_debug("exclusive chosen:   %s\n", lsm->id->name);
-		lsm_exclusive = lsm;
-	}
 
 	/* Register the LSM blob sizes. */
-	blobs = lsm->blobs;
 	lsm_blob_size_update(&blobs->lbs_cred, &blob_sizes.lbs_cred);
 	lsm_blob_size_update(&blobs->lbs_file, &blob_sizes.lbs_file);
 	lsm_blob_size_update(&blobs->lbs_ib, &blob_sizes.lbs_ib);
@@ -230,86 +310,6 @@ static void __init lsm_init_single(struct lsm_info *lsm)
 	WARN(ret, "%s failed to initialize: %d\n", lsm->id->name, ret);
 }
 
-/* Populate ordered LSMs list from comma-separated LSM name list. */
-static void __init ordered_lsm_parse(const char *order, const char *origin)
-{
-	struct lsm_info *lsm;
-	char *sep, *name, *next;
-
-	/* LSM_ORDER_FIRST is always first. */
-	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
-		if (lsm->order == LSM_ORDER_FIRST)
-			lsm_order_append(lsm, "  first");
-	}
-
-	/* Process "security=", if given. */
-	if (lsm_order_legacy) {
-		struct lsm_info *major;
-
-		/*
-		 * To match the original "security=" behavior, this
-		 * explicitly does NOT fallback to another Legacy Major
-		 * if the selected one was separately disabled: disable
-		 * all non-matching Legacy Major LSMs.
-		 */
-		for (major = __start_lsm_info; major < __end_lsm_info;
-		     major++) {
-			if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
-			    strcmp(major->id->name, lsm_order_legacy) != 0) {
-				lsm_enabled_set(major, false);
-				init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
-					   lsm_order_legacy, major->id->name);
-			}
-		}
-	}
-
-	sep = kstrdup(order, GFP_KERNEL);
-	next = sep;
-	/* Walk the list, looking for matching LSMs. */
-	while ((name = strsep(&next, ",")) != NULL) {
-		bool found = false;
-
-		for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
-			if (strcmp(lsm->id->name, name) == 0) {
-				if (lsm->order == LSM_ORDER_MUTABLE)
-					lsm_order_append(lsm, origin);
-				found = true;
-			}
-		}
-
-		if (!found)
-			init_debug("%s ignored: %s (not built into kernel)\n",
-				   origin, name);
-	}
-
-	/* Process "security=", if given. */
-	if (lsm_order_legacy) {
-		for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
-			if (lsm_order_exists(lsm))
-				continue;
-			if (strcmp(lsm->id->name, lsm_order_legacy) == 0)
-				lsm_order_append(lsm, "security=");
-		}
-	}
-
-	/* LSM_ORDER_LAST is always last. */
-	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
-		if (lsm->order == LSM_ORDER_LAST)
-			lsm_order_append(lsm, "   last");
-	}
-
-	/* Disable all LSMs not in the ordered list. */
-	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
-		if (lsm_order_exists(lsm))
-			continue;
-		lsm_enabled_set(lsm, false);
-		init_debug("%s skipped: %s (not in requested order)\n",
-			   origin, lsm->id->name);
-	}
-
-	kfree(sep);
-}
-
 /**
  * lsm_init_ordered - Initialize the ordered LSMs
  */
@@ -324,9 +324,9 @@ static void __init lsm_init_ordered(void)
 				lsm_order_legacy, lsm_order_cmdline);
 			lsm_order_legacy = NULL;
 		}
-		ordered_lsm_parse(lsm_order_cmdline, "cmdline");
+		lsm_order_parse(lsm_order_cmdline, "cmdline");
 	} else
-		ordered_lsm_parse(lsm_order_builtin, "builtin");
+		lsm_order_parse(lsm_order_builtin, "builtin");
 
 	lsm_order_for_each(lsm) {
 		lsm_prep_single(*lsm);
@@ -426,6 +426,7 @@ int __init early_security_init(void)
 
 	lsm_early_for_each_raw(lsm) {
 		lsm_enabled_set(lsm, true);
+		lsm_order_append(lsm, "early");
 		lsm_prep_single(lsm);
 		lsm_init_single(lsm);
 	}
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 13/29] lsm: fold lsm_init_ordered() into security_init()
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (11 preceding siblings ...)
  2025-04-09 18:49 ` [RFC PATCH 12/29] lsm: cleanup the LSM ordered parsing Paul Moore
@ 2025-04-09 18:49 ` Paul Moore
  2025-04-09 18:49 ` [RFC PATCH 14/29] lsm: add missing function header comment blocks in lsm_init.c Paul Moore
                   ` (16 subsequent siblings)
  29 siblings, 0 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:49 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

One part of a larger effort to cleanup the LSM framework initialization
code.

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 security/lsm_init.c | 156 ++++++++++++++++++++------------------------
 1 file changed, 72 insertions(+), 84 deletions(-)

diff --git a/security/lsm_init.c b/security/lsm_init.c
index e07fd4d2a16a..55b3fa82db76 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -18,6 +18,9 @@ int lsm_enabled_false = 0;
 extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
 extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
 
+/* Number of "early" LSMs */
+static __initdata unsigned int lsm_count_early;
+
 /* Build and boot-time LSM ordering. */
 static __initconst const char *const lsm_order_builtin = CONFIG_LSM;
 static __initdata const char *lsm_order_cmdline;
@@ -310,78 +313,6 @@ static void __init lsm_init_single(struct lsm_info *lsm)
 	WARN(ret, "%s failed to initialize: %d\n", lsm->id->name, ret);
 }
 
-/**
- * lsm_init_ordered - Initialize the ordered LSMs
- */
-static void __init lsm_init_ordered(void)
-{
-	struct lsm_info **lsm;
-	struct lsm_info *early;
-
-	if (lsm_order_cmdline) {
-		if (lsm_order_legacy) {
-			pr_warn("security=%s is ignored because it is superseded by lsm=%s\n",
-				lsm_order_legacy, lsm_order_cmdline);
-			lsm_order_legacy = NULL;
-		}
-		lsm_order_parse(lsm_order_cmdline, "cmdline");
-	} else
-		lsm_order_parse(lsm_order_builtin, "builtin");
-
-	lsm_order_for_each(lsm) {
-		lsm_prep_single(*lsm);
-	}
-
-	pr_info("initializing lsm=");
-	lsm_early_for_each_raw(early) {
-		if (lsm_is_enabled(early))
-			pr_cont("%s%s",
-				early == __start_early_lsm_info ? "" : ",",
-				early->id->name);
-	}
-	lsm_order_for_each(lsm) {
-		if (lsm_is_enabled(*lsm))
-			pr_cont("%s%s",
-				lsm == lsm_order ? "" : ",", (*lsm)->id->name);
-	}
-	pr_cont("\n");
-
-	init_debug("cred blob size       = %d\n", blob_sizes.lbs_cred);
-	init_debug("file blob size       = %d\n", blob_sizes.lbs_file);
-	init_debug("ib blob size         = %d\n", blob_sizes.lbs_ib);
-	init_debug("inode blob size      = %d\n", blob_sizes.lbs_inode);
-	init_debug("ipc blob size        = %d\n", blob_sizes.lbs_ipc);
-#ifdef CONFIG_KEYS
-	init_debug("key blob size        = %d\n", blob_sizes.lbs_key);
-#endif /* CONFIG_KEYS */
-	init_debug("msg_msg blob size    = %d\n", blob_sizes.lbs_msg_msg);
-	init_debug("sock blob size       = %d\n", blob_sizes.lbs_sock);
-	init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
-	init_debug("perf event blob size = %d\n", blob_sizes.lbs_perf_event);
-	init_debug("task blob size       = %d\n", blob_sizes.lbs_task);
-	init_debug("tun device blob size = %d\n", blob_sizes.lbs_tun_dev);
-	init_debug("xattr slots          = %d\n", blob_sizes.lbs_xattr_count);
-	init_debug("bdev blob size       = %d\n", blob_sizes.lbs_bdev);
-
-	if (blob_sizes.lbs_file)
-		lsm_file_cache = kmem_cache_create("lsm_file_cache",
-						   blob_sizes.lbs_file, 0,
-						   SLAB_PANIC, NULL);
-	if (blob_sizes.lbs_inode)
-		lsm_inode_cache = kmem_cache_create("lsm_inode_cache",
-						    blob_sizes.lbs_inode, 0,
-						    SLAB_PANIC, NULL);
-
-	if (lsm_cred_alloc((struct cred *)current->cred, GFP_KERNEL))
-		panic("%s: early cred alloc failed.\n", __func__);
-	if (lsm_task_alloc(current))
-		panic("%s: early task alloc failed.\n", __func__);
-
-	lsm_order_for_each(lsm) {
-		lsm_init_single(*lsm);
-	}
-}
-
 static void __init lsm_static_call_init(struct security_hook_list *hl)
 {
 	struct lsm_static_call *scall = hl->scalls;
@@ -429,35 +360,92 @@ int __init early_security_init(void)
 		lsm_order_append(lsm, "early");
 		lsm_prep_single(lsm);
 		lsm_init_single(lsm);
+		lsm_count_early++;
 	}
 
 	return 0;
 }
 
 /**
- * security_init - initializes the security framework
+ * security_init - Initializes the LSM framework
  *
  * This should be called early in the kernel initialization sequence.
  */
 int __init security_init(void)
 {
-	struct lsm_info *lsm;
+	unsigned int cnt;
+	struct lsm_info **lsm;
+	struct lsm_info *early;
 
 	init_debug("legacy security=%s\n", lsm_order_legacy ? : " *unspecified*");
 	init_debug("  CONFIG_LSM=%s\n", lsm_order_builtin);
 	init_debug("boot arg lsm=%s\n", lsm_order_cmdline ? : " *unspecified*");
 
-	/*
-	 * Append the names of the early LSM modules now that kmalloc() is
-	 * available
-	 */
-	lsm_early_for_each_raw(lsm) {
-		init_debug("  early started: %s (%s)\n", lsm->id->name,
-			   lsm_is_enabled(lsm) ? "enabled" : "disabled");
-	}
+	if (lsm_order_cmdline) {
+		if (lsm_order_legacy) {
+			pr_warn("security=%s is ignored because it is superseded by lsm=%s\n",
+				lsm_order_legacy, lsm_order_cmdline);
+			lsm_order_legacy = NULL;
+		}
+		lsm_order_parse(lsm_order_cmdline, "cmdline");
+	} else
+		lsm_order_parse(lsm_order_builtin, "builtin");
 
-	/* Load LSMs in specified order. */
-	lsm_init_ordered();
+	lsm_order_for_each(lsm)
+		lsm_prep_single(*lsm);
+
+	pr_info("initializing lsm=");
+	lsm_early_for_each_raw(early) {
+		if (lsm_is_enabled(early))
+			pr_cont("%s%s",
+				early == __start_early_lsm_info ? "" : ",",
+				early->id->name);
+	}
+	lsm_order_for_each(lsm) {
+		if (lsm_is_enabled(*lsm))
+			pr_cont("%s%s",
+				lsm == lsm_order ? "" : ",", (*lsm)->id->name);
+	}
+	pr_cont("\n");
+
+	init_debug("cred blob size       = %d\n", blob_sizes.lbs_cred);
+	init_debug("file blob size       = %d\n", blob_sizes.lbs_file);
+	init_debug("ib blob size         = %d\n", blob_sizes.lbs_ib);
+	init_debug("inode blob size      = %d\n", blob_sizes.lbs_inode);
+	init_debug("ipc blob size        = %d\n", blob_sizes.lbs_ipc);
+#ifdef CONFIG_KEYS
+	init_debug("key blob size        = %d\n", blob_sizes.lbs_key);
+#endif /* CONFIG_KEYS */
+	init_debug("msg_msg blob size    = %d\n", blob_sizes.lbs_msg_msg);
+	init_debug("sock blob size       = %d\n", blob_sizes.lbs_sock);
+	init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
+	init_debug("perf event blob size = %d\n", blob_sizes.lbs_perf_event);
+	init_debug("task blob size       = %d\n", blob_sizes.lbs_task);
+	init_debug("tun device blob size = %d\n", blob_sizes.lbs_tun_dev);
+	init_debug("xattr slots          = %d\n", blob_sizes.lbs_xattr_count);
+	init_debug("bdev blob size       = %d\n", blob_sizes.lbs_bdev);
+
+	if (blob_sizes.lbs_file)
+		lsm_file_cache = kmem_cache_create("lsm_file_cache",
+						   blob_sizes.lbs_file, 0,
+						   SLAB_PANIC, NULL);
+	if (blob_sizes.lbs_inode)
+		lsm_inode_cache = kmem_cache_create("lsm_inode_cache",
+						    blob_sizes.lbs_inode, 0,
+						    SLAB_PANIC, NULL);
+
+	if (lsm_cred_alloc((struct cred *)current->cred, GFP_KERNEL))
+		panic("%s: early cred alloc failed.\n", __func__);
+	if (lsm_task_alloc(current))
+		panic("%s: early task alloc failed.\n", __func__);
+
+	cnt = 0;
+	lsm_order_for_each(lsm) {
+		/* skip the "early" LSMs as they have already been setup */
+		if (cnt++ < lsm_count_early)
+			continue;
+		lsm_init_single(*lsm);
+	}
 
 	return 0;
 }
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 14/29] lsm: add missing function header comment blocks in lsm_init.c
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (12 preceding siblings ...)
  2025-04-09 18:49 ` [RFC PATCH 13/29] lsm: fold lsm_init_ordered() into security_init() Paul Moore
@ 2025-04-09 18:49 ` Paul Moore
  2025-05-14 10:10   ` John Johansen
  2025-04-09 18:50 ` [RFC PATCH 15/29] lsm: cleanup the debug and console output " Paul Moore
                   ` (15 subsequent siblings)
  29 siblings, 1 reply; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:49 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 security/lsm_init.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/security/lsm_init.c b/security/lsm_init.c
index 55b3fa82db76..04b1f5e760b1 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -313,6 +313,10 @@ static void __init lsm_init_single(struct lsm_info *lsm)
 	WARN(ret, "%s failed to initialize: %d\n", lsm->id->name, ret);
 }
 
+/**
+ * lsm_static_call_init - Initialize a LSM's static calls
+ * @hl: LSM hook list
+ */
 static void __init lsm_static_call_init(struct security_hook_list *hl)
 {
 	struct lsm_static_call *scall = hl->scalls;
@@ -351,6 +355,9 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
 	}
 }
 
+/**
+ * early_security_init - Initialize the early LSMs
+ */
 int __init early_security_init(void)
 {
 	struct lsm_info *lsm;
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 15/29] lsm: cleanup the debug and console output in lsm_init.c
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (13 preceding siblings ...)
  2025-04-09 18:49 ` [RFC PATCH 14/29] lsm: add missing function header comment blocks in lsm_init.c Paul Moore
@ 2025-04-09 18:50 ` Paul Moore
  2025-04-09 18:50 ` [RFC PATCH 16/29] lsm: output available LSMs when debugging Paul Moore
                   ` (14 subsequent siblings)
  29 siblings, 0 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:50 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

One part of a larger effort to cleanup the LSM framework initialization
code.

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 security/lsm.h      |  11 ++++
 security/lsm_init.c | 121 +++++++++++++++++++-------------------------
 security/security.c |   2 +
 3 files changed, 66 insertions(+), 68 deletions(-)

diff --git a/security/lsm.h b/security/lsm.h
index af343072199d..8ecb66896646 100644
--- a/security/lsm.h
+++ b/security/lsm.h
@@ -6,9 +6,20 @@
 #ifndef _LSM_H_
 #define _LSM_H_
 
+#include <linux/printk.h>
 #include <linux/lsm_hooks.h>
 #include <linux/lsm_count.h>
 
+/* LSM debugging */
+extern bool lsm_debug;
+#define lsm_pr(...)		pr_info(__VA_ARGS__)
+#define lsm_pr_cont(...)	pr_cont(__VA_ARGS__)
+#define lsm_pr_dbg(...)							\
+	do {								\
+		if (lsm_debug)						\
+			pr_info(__VA_ARGS__);				\
+	} while (0)
+
 /* List of configured LSMs */
 extern unsigned int lsm_count;
 extern const struct lsm_id *lsm_idlist[];
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 04b1f5e760b1..aba1253ffc4c 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -30,13 +30,6 @@ static __initdata const char *lsm_order_legacy;
 static __initdata struct lsm_info *lsm_exclusive;
 static __initdata struct lsm_info *lsm_order[MAX_LSM_COUNT + 1];
 
-static __initdata bool debug;
-#define init_debug(...)							\
-	do {								\
-		if (debug)						\
-			pr_info(__VA_ARGS__);				\
-	} while (0)
-
 #define lsm_order_for_each(iter)					\
 	for ((iter) = lsm_order; *(iter); (iter)++)
 #define lsm_for_each_raw(iter)						\
@@ -77,7 +70,7 @@ __setup("lsm=", lsm_choose_lsm);
  */
 static int __init lsm_debug_enable(char *str)
 {
-	debug = true;
+	lsm_debug = true;
 	return 1;
 }
 __setup("lsm.debug", lsm_debug_enable);
@@ -145,22 +138,28 @@ static void __init lsm_order_append(struct lsm_info *lsm, const char *src)
 		return;
 
 	/* Skip explicitly disabled LSMs. */
-	if (lsm->enabled && !lsm_is_enabled(lsm))
-		goto out;
+	if (lsm->enabled && !lsm_is_enabled(lsm)) {
+		lsm_pr_dbg("skip previously disabled LSM %s:%s\n",
+			   src, lsm->id->name);
+		return;
+	}
 
-	if (WARN(lsm_count == MAX_LSM_COUNT,
-		 "%s: out of LSM static calls!?\n", src)) {
+	if (lsm_count == MAX_LSM_COUNT) {
+		pr_warn("exceeded maximum LSM count on %s:%s\n",
+			src, lsm->id->name);
 		lsm_enabled_set(lsm, false);
-		goto out;
+		return;
 	}
 
 	if (lsm->flags & LSM_FLAG_EXCLUSIVE) {
 		if (lsm_exclusive) {
-			init_debug("exclusive disabled: %s\n", lsm->id->name);
+			lsm_pr_dbg("skip exclusive LSM conflict %s:%s\n",
+				   src, lsm->id->name);
 			lsm_enabled_set(lsm, false);
-			goto out;
+			return;
 		} else {
-			init_debug("exclusive chosen:   %s\n", lsm->id->name);
+			lsm_pr_dbg("select exclusive LSM %s:%s\n",
+				   src, lsm->id->name);
 			lsm_exclusive = lsm;
 		}
 	}
@@ -169,9 +168,7 @@ static void __init lsm_order_append(struct lsm_info *lsm, const char *src)
 	lsm_order[lsm_count] = lsm;
 	lsm_idlist[lsm_count++] = lsm->id;
 
-out:
-	init_debug("%s ordered: %s (%s)\n", src, lsm->id->name,
-		   lsm_is_enabled(lsm) ? "enabled" : "disabled");
+	lsm_pr_dbg("enabling LSM %s:%s\n", src, lsm->id->name);
 }
 
 /**
@@ -196,8 +193,8 @@ static void __init lsm_order_parse(const char *list, const char *src)
 			if ((lsm->flags & LSM_FLAG_LEGACY_MAJOR) &&
 			     strcmp(lsm->id->name, lsm_order_legacy)) {
 				lsm_enabled_set(lsm, false);
-				init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
-					   lsm_order_legacy, lsm->id->name);
+				lsm_pr_dbg("skip legacy LSM conflict %s:%s\n",
+					   src, lsm->id->name);
 			}
 		}
 	}
@@ -240,8 +237,7 @@ static void __init lsm_order_parse(const char *list, const char *src)
 		if (lsm_order_exists(lsm))
 			continue;
 		lsm_enabled_set(lsm, false);
-		init_debug("%s skipped: %s (not in requested order)\n",
-			   src, lsm->id->name);
+		lsm_pr_dbg("skip disabled LSM %s:%s\n", src, lsm->id->name);
 	}
 }
 
@@ -308,16 +304,18 @@ static void __init lsm_init_single(struct lsm_info *lsm)
 	if (!lsm_is_enabled(lsm))
 		return;
 
-	init_debug("initializing %s\n", lsm->id->name);
+	lsm_pr_dbg("initialize LSM %s\n", lsm->id->name);
 	ret = lsm->init();
-	WARN(ret, "%s failed to initialize: %d\n", lsm->id->name, ret);
+	if (ret)
+		pr_warn("failed to initialize LSM %s with errno %d\n",
+			lsm->id->name, ret);
 }
 
 /**
  * lsm_static_call_init - Initialize a LSM's static calls
  * @hl: LSM hook list
  */
-static void __init lsm_static_call_init(struct security_hook_list *hl)
+static int __init lsm_static_call_init(struct security_hook_list *hl)
 {
 	struct lsm_static_call *scall = hl->scalls;
 	int i;
@@ -329,11 +327,12 @@ static void __init lsm_static_call_init(struct security_hook_list *hl)
 					     hl->hook.lsm_func_addr);
 			scall->hl = hl;
 			static_branch_enable(scall->active);
-			return;
+			return 0;
 		}
 		scall++;
 	}
-	panic("%s - Ran out of static slots.\n", __func__);
+
+	return -ENOSPC;
 }
 
 /**
@@ -351,7 +350,9 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
 
 	for (i = 0; i < count; i++) {
 		hooks[i].lsmid = lsmid;
-		lsm_static_call_init(&hooks[i]);
+		if (lsm_static_call_init(&hooks[i]))
+			panic("exhausted LSM callback slots with LSM %s\n",
+			      lsmid->name);
 	}
 }
 
@@ -382,18 +383,16 @@ int __init security_init(void)
 {
 	unsigned int cnt;
 	struct lsm_info **lsm;
-	struct lsm_info *early;
 
-	init_debug("legacy security=%s\n", lsm_order_legacy ? : " *unspecified*");
-	init_debug("  CONFIG_LSM=%s\n", lsm_order_builtin);
-	init_debug("boot arg lsm=%s\n", lsm_order_cmdline ? : " *unspecified*");
+	if (lsm_debug) {
+		lsm_pr("built-in LSM list: %s\n", lsm_order_builtin);
+		lsm_pr("legacy LSM parameter: %s\n", lsm_order_legacy);
+		lsm_pr("boot LSM parameter: %s\n", lsm_order_cmdline);
+	}
 
 	if (lsm_order_cmdline) {
-		if (lsm_order_legacy) {
-			pr_warn("security=%s is ignored because it is superseded by lsm=%s\n",
-				lsm_order_legacy, lsm_order_cmdline);
+		if (lsm_order_legacy)
 			lsm_order_legacy = NULL;
-		}
 		lsm_order_parse(lsm_order_cmdline, "cmdline");
 	} else
 		lsm_order_parse(lsm_order_builtin, "builtin");
@@ -401,36 +400,22 @@ int __init security_init(void)
 	lsm_order_for_each(lsm)
 		lsm_prep_single(*lsm);
 
-	pr_info("initializing lsm=");
-	lsm_early_for_each_raw(early) {
-		if (lsm_is_enabled(early))
-			pr_cont("%s%s",
-				early == __start_early_lsm_info ? "" : ",",
-				early->id->name);
+	if (lsm_debug) {
+		lsm_pr("blob(cred) size %d\n", blob_sizes.lbs_cred);
+		lsm_pr("blob(file) size %d\n", blob_sizes.lbs_file);
+		lsm_pr("blob(ib) size %d\n", blob_sizes.lbs_ib);
+		lsm_pr("blob(inode) size %d\n", blob_sizes.lbs_inode);
+		lsm_pr("blob(ipc) size %d\n", blob_sizes.lbs_ipc);
+		lsm_pr("blob(key) size %d\n", blob_sizes.lbs_key);
+		lsm_pr("blob(msg_msg)_size %d\n", blob_sizes.lbs_msg_msg);
+		lsm_pr("blob(sock) size %d\n", blob_sizes.lbs_sock);
+		lsm_pr("blob(superblock) size %d\n", blob_sizes.lbs_superblock);
+		lsm_pr("blob(perf_event) size %d\n", blob_sizes.lbs_perf_event);
+		lsm_pr("blob(task) size %d\n", blob_sizes.lbs_task);
+		lsm_pr("blob(tun_dev) size %d\n", blob_sizes.lbs_tun_dev);
+		lsm_pr("blob(xattr) count %d\n", blob_sizes.lbs_xattr_count);
+		lsm_pr("blob(bdev) size %d\n", blob_sizes.lbs_bdev);
 	}
-	lsm_order_for_each(lsm) {
-		if (lsm_is_enabled(*lsm))
-			pr_cont("%s%s",
-				lsm == lsm_order ? "" : ",", (*lsm)->id->name);
-	}
-	pr_cont("\n");
-
-	init_debug("cred blob size       = %d\n", blob_sizes.lbs_cred);
-	init_debug("file blob size       = %d\n", blob_sizes.lbs_file);
-	init_debug("ib blob size         = %d\n", blob_sizes.lbs_ib);
-	init_debug("inode blob size      = %d\n", blob_sizes.lbs_inode);
-	init_debug("ipc blob size        = %d\n", blob_sizes.lbs_ipc);
-#ifdef CONFIG_KEYS
-	init_debug("key blob size        = %d\n", blob_sizes.lbs_key);
-#endif /* CONFIG_KEYS */
-	init_debug("msg_msg blob size    = %d\n", blob_sizes.lbs_msg_msg);
-	init_debug("sock blob size       = %d\n", blob_sizes.lbs_sock);
-	init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
-	init_debug("perf event blob size = %d\n", blob_sizes.lbs_perf_event);
-	init_debug("task blob size       = %d\n", blob_sizes.lbs_task);
-	init_debug("tun device blob size = %d\n", blob_sizes.lbs_tun_dev);
-	init_debug("xattr slots          = %d\n", blob_sizes.lbs_xattr_count);
-	init_debug("bdev blob size       = %d\n", blob_sizes.lbs_bdev);
 
 	if (blob_sizes.lbs_file)
 		lsm_file_cache = kmem_cache_create("lsm_file_cache",
@@ -442,9 +427,9 @@ int __init security_init(void)
 						    SLAB_PANIC, NULL);
 
 	if (lsm_cred_alloc((struct cred *)current->cred, GFP_KERNEL))
-		panic("%s: early cred alloc failed.\n", __func__);
+		panic("early LSM cred alloc failed\n");
 	if (lsm_task_alloc(current))
-		panic("%s: early task alloc failed.\n", __func__);
+		panic("early LSM task alloc failed\n");
 
 	cnt = 0;
 	lsm_order_for_each(lsm) {
diff --git a/security/security.c b/security/security.c
index a3e8dd640b39..cbd544d71093 100644
--- a/security/security.c
+++ b/security/security.c
@@ -73,6 +73,8 @@ const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX + 1] = {
 	[LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality",
 };
 
+bool lsm_debug __ro_after_init;
+
 unsigned int lsm_count __ro_after_init;
 const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
 
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 16/29] lsm: output available LSMs when debugging
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (14 preceding siblings ...)
  2025-04-09 18:50 ` [RFC PATCH 15/29] lsm: cleanup the debug and console output " Paul Moore
@ 2025-04-09 18:50 ` Paul Moore
  2025-05-14 12:01   ` John Johansen
  2025-04-09 18:50 ` [RFC PATCH 17/29] lsm: introduce an initcall mechanism into the LSM framework Paul Moore
                   ` (13 subsequent siblings)
  29 siblings, 1 reply; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:50 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

This will display all of the LSMs built into the kernel, regardless
of if they are enabled or not.

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 security/lsm_init.c | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/security/lsm_init.c b/security/lsm_init.c
index aba1253ffc4c..8e00afeb84cf 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -363,6 +363,8 @@ int __init early_security_init(void)
 {
 	struct lsm_info *lsm;
 
+	/* NOTE: lsm_pr_dbg() doesn't work here as lsm_debug is not yet set */
+
 	lsm_early_for_each_raw(lsm) {
 		lsm_enabled_set(lsm, true);
 		lsm_order_append(lsm, "early");
@@ -385,9 +387,24 @@ int __init security_init(void)
 	struct lsm_info **lsm;
 
 	if (lsm_debug) {
-		lsm_pr("built-in LSM list: %s\n", lsm_order_builtin);
+		struct lsm_info *i;
+
+		cnt = 0;
+		lsm_pr("available LSMs: ");
+		lsm_early_for_each_raw(i)
+			lsm_pr_cont("%s%s(E)", (cnt++ ? "," : ""), i->id->name);
+		lsm_for_each_raw(i)
+			lsm_pr_cont("%s%s", (cnt++ ? "," : ""), i->id->name);
+		lsm_pr_cont("\n");
+
+		lsm_pr("built-in LSM config: %s\n", lsm_order_builtin);
+
 		lsm_pr("legacy LSM parameter: %s\n", lsm_order_legacy);
 		lsm_pr("boot LSM parameter: %s\n", lsm_order_cmdline);
+
+		/* see the note about lsm_pr_dbg() in early_security_init() */
+		lsm_early_for_each_raw(i)
+			lsm_pr("enabled LSM early:%s\n", i->id->name);
 	}
 
 	if (lsm_order_cmdline) {
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 17/29] lsm: introduce an initcall mechanism into the LSM framework
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (15 preceding siblings ...)
  2025-04-09 18:50 ` [RFC PATCH 16/29] lsm: output available LSMs when debugging Paul Moore
@ 2025-04-09 18:50 ` Paul Moore
  2025-04-09 21:16   ` Kees Cook
  2025-05-14 11:59   ` John Johansen
  2025-04-09 18:50 ` [RFC PATCH 18/29] loadpin: move initcalls to " Paul Moore
                   ` (12 subsequent siblings)
  29 siblings, 2 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:50 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

Currently the individual LSMs register their own initcalls, and while
this should be harmless, it can be wasteful in the case where a LSM
is disabled at boot as the initcall will still be executed.  This
patch introduces support for managing the initcalls in the LSM
framework, and future patches will convert the existing LSMs over to
this new mechanism.

Only initcall types which are used by the current in-tree LSMs are
supported, additional initcall types can easily be added in the future
if needed.

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 include/linux/lsm_hooks.h | 33 ++++++++++++---
 security/lsm_init.c       | 89 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 117 insertions(+), 5 deletions(-)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index a7ecb0791a0f..0d2c2a017ffc 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -148,13 +148,36 @@ enum lsm_order {
 	LSM_ORDER_LAST = 1,	/* This is only for integrity. */
 };
 
+/**
+ * struct lsm_info - Define an individual LSM for the LSM framework.
+ * @id: LSM name/ID info
+ * @order: ordering with respect to other LSMs, optional
+ * @flags: descriptive flags, optional
+ * @blobs: LSM blob sharing, optional
+ * @enabled: controlled by CONFIG_LSM, optional
+ * @init: LSM specific initialization routine
+ * @initcall_pure: LSM callback for initcall_pure() setup, optional
+ * @initcall_early: LSM callback for early_initcall setup, optional
+ * @initcall_core: LSM callback for core_initcall() setup, optional
+ * @initcall_subsys: LSM callback for subsys_initcall() setup, optional
+ * @initcall_fs: LSM callback for fs_initcall setup, optional
+ * @nitcall_device: LSM callback for device_initcall() setup, optional
+ * @initcall_late: LSM callback for late_initcall() setup, optional
+ */
 struct lsm_info {
 	const struct lsm_id *id;
-	enum lsm_order order;	/* Optional: default is LSM_ORDER_MUTABLE */
-	unsigned long flags;	/* Optional: flags describing LSM */
-	int *enabled;		/* Optional: controlled by CONFIG_LSM */
-	int (*init)(void);	/* Required. */
-	struct lsm_blob_sizes *blobs; /* Optional: for blob sharing. */
+	enum lsm_order order;
+	unsigned long flags;
+	struct lsm_blob_sizes *blobs;
+	int *enabled;
+	int (*init)(void);
+	int (*initcall_pure)(void);
+	int (*initcall_early)(void);
+	int (*initcall_core)(void);
+	int (*initcall_subsys)(void);
+	int (*initcall_fs)(void);
+	int (*initcall_device)(void);
+	int (*initcall_late)(void);
 };
 
 #define DEFINE_LSM(lsm)							\
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 8e00afeb84cf..75eb0cc82869 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -39,6 +39,27 @@ static __initdata struct lsm_info *lsm_order[MAX_LSM_COUNT + 1];
 	for ((iter) = __start_early_lsm_info;				\
 	     (iter) < __end_early_lsm_info; (iter)++)
 
+#define lsm_initcall(level)						\
+	({ 								\
+		int _r, _rc = 0;					\
+		struct lsm_info **_lp, *_l; 				\
+		lsm_order_for_each(_lp) { 				\
+			_l = *_lp; 					\
+			if (!_l->initcall_##level) 			\
+				continue;				\
+			lsm_pr_dbg("running %s %s initcall",		\
+				   _l->id->name, #level);		\
+			_r = _l->initcall_##level();			\
+			if (_r) {					\
+				pr_warn("failed LSM %s %s initcall with errno %d\n", \
+					_l->id->name, #level, _r);	\
+				if (!_rc)				\
+					_rc = _r;			\
+			}						\
+		}							\
+		_rc;							\
+	})
+
 /**
  * lsm_choose_security - Legacy "major" LSM selection
  * @str: kernel command line parameter
@@ -458,3 +479,71 @@ int __init security_init(void)
 
 	return 0;
 }
+
+/**
+ * security_initcall_pure - Run the LSM pure initcalls
+ */
+static int __init security_initcall_pure(void)
+{
+	return lsm_initcall(pure);
+}
+pure_initcall(security_initcall_pure);
+
+/**
+ * security_initcall_early - Run the LSM early initcalls
+ */
+static int __init security_initcall_early(void)
+{
+	return lsm_initcall(early);
+}
+early_initcall(security_initcall_early);
+
+/**
+ * security_initcall_core - Run the LSM core initcalls
+ */
+static int __init security_initcall_core(void)
+{
+	return lsm_initcall(core);
+}
+core_initcall(security_initcall_core);
+
+/**
+ * security_initcall_subsys - Run the LSM subsys initcalls
+ */
+static int __init security_initcall_subsys(void)
+{
+	return lsm_initcall(subsys);
+}
+subsys_initcall(security_initcall_subsys);
+
+/**
+ * security_initcall_fs - Run the LSM fs initcalls
+ */
+static int __init security_initcall_fs(void)
+{
+	return lsm_initcall(fs);
+}
+fs_initcall(security_initcall_fs);
+
+/**
+ * security_initcall_device - Run the LSM device initcalls
+ */
+static int __init security_initcall_device(void)
+{
+	return lsm_initcall(device);
+}
+device_initcall(security_initcall_device);
+
+/**
+ * security_initcall_late - Run the LSM late initcalls
+ */
+static int __init security_initcall_late(void)
+{
+	int rc;
+
+	rc = lsm_initcall(late);
+	lsm_pr_dbg("all enabled LSMs fully activated\n");
+
+	return rc;
+}
+late_initcall(security_initcall_late);
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 18/29] loadpin: move initcalls to the LSM framework
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (16 preceding siblings ...)
  2025-04-09 18:50 ` [RFC PATCH 17/29] lsm: introduce an initcall mechanism into the LSM framework Paul Moore
@ 2025-04-09 18:50 ` Paul Moore
  2025-04-09 23:39   ` Kees Cook
  2025-05-14 11:57   ` John Johansen
  2025-04-09 18:50 ` [RFC PATCH 19/29] ipe: " Paul Moore
                   ` (11 subsequent siblings)
  29 siblings, 2 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:50 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 security/loadpin/loadpin.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c
index b9ddf05c5c16..273ffbd6defe 100644
--- a/security/loadpin/loadpin.c
+++ b/security/loadpin/loadpin.c
@@ -270,11 +270,6 @@ static int __init loadpin_init(void)
 	return 0;
 }
 
-DEFINE_LSM(loadpin) = {
-	.id = &loadpin_lsmid,
-	.init = loadpin_init,
-};
-
 #ifdef CONFIG_SECURITY_LOADPIN_VERITY
 
 enum loadpin_securityfs_interface_index {
@@ -434,10 +429,16 @@ static int __init init_loadpin_securityfs(void)
 	return 0;
 }
 
-fs_initcall(init_loadpin_securityfs);
-
 #endif /* CONFIG_SECURITY_LOADPIN_VERITY */
 
+DEFINE_LSM(loadpin) = {
+	.id = &loadpin_lsmid,
+	.init = loadpin_init,
+#ifdef CONFIG_SECURITY_LOADPIN_VERITY
+	.initcall_fs = init_loadpin_securityfs,
+#endif /* CONFIG_SECURITY_LOADPIN_VERITY */
+};
+
 /* Should not be mutable after boot, so not listed in sysfs (perm == 0). */
 module_param(enforce, int, 0);
 MODULE_PARM_DESC(enforce, "Enforce module/firmware pinning");
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 19/29] ipe: move initcalls to the LSM framework
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (17 preceding siblings ...)
  2025-04-09 18:50 ` [RFC PATCH 18/29] loadpin: move initcalls to " Paul Moore
@ 2025-04-09 18:50 ` Paul Moore
  2025-04-09 23:40   ` Kees Cook
                     ` (2 more replies)
  2025-04-09 18:50 ` [RFC PATCH 20/29] smack: " Paul Moore
                   ` (10 subsequent siblings)
  29 siblings, 3 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:50 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 security/ipe/fs.c  | 4 +---
 security/ipe/ipe.c | 1 +
 security/ipe/ipe.h | 2 ++
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/security/ipe/fs.c b/security/ipe/fs.c
index 5b6d19fb844a..e4437c70ed3d 100644
--- a/security/ipe/fs.c
+++ b/security/ipe/fs.c
@@ -187,7 +187,7 @@ static const struct file_operations enforce_fops = {
  * Return: %0 on success. If an error occurs, the function will return
  * the -errno.
  */
-static int __init ipe_init_securityfs(void)
+int __init ipe_init_securityfs(void)
 {
 	int rc = 0;
 	struct ipe_policy *ap;
@@ -243,5 +243,3 @@ static int __init ipe_init_securityfs(void)
 	securityfs_remove(root);
 	return rc;
 }
-
-fs_initcall(ipe_init_securityfs);
diff --git a/security/ipe/ipe.c b/security/ipe/ipe.c
index 2426441181dc..71644748ed56 100644
--- a/security/ipe/ipe.c
+++ b/security/ipe/ipe.c
@@ -95,4 +95,5 @@ DEFINE_LSM(ipe) = {
 	.id = &ipe_lsmid,
 	.init = ipe_init,
 	.blobs = &ipe_blobs,
+	.initcall_fs = ipe_init_securityfs,
 };
diff --git a/security/ipe/ipe.h b/security/ipe/ipe.h
index fb37513812dd..25cfdb8f0c20 100644
--- a/security/ipe/ipe.h
+++ b/security/ipe/ipe.h
@@ -23,4 +23,6 @@ struct ipe_bdev *ipe_bdev(struct block_device *b);
 struct ipe_inode *ipe_inode(const struct inode *inode);
 #endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
 
+int ipe_init_securityfs(void);
+
 #endif /* _IPE_H */
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 20/29] smack: move initcalls to the LSM framework
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (18 preceding siblings ...)
  2025-04-09 18:50 ` [RFC PATCH 19/29] ipe: " Paul Moore
@ 2025-04-09 18:50 ` Paul Moore
  2025-04-09 23:42   ` Kees Cook
                     ` (2 more replies)
  2025-04-09 18:50 ` [RFC PATCH 21/29] tomoyo: " Paul Moore
                   ` (9 subsequent siblings)
  29 siblings, 3 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:50 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

As the LSM framework only supports one LSM initcall callback for each
initcall type, the init_smk_fs() and smack_nf_ip_init() functions were
wrapped with a new function, smack_initcall() that is registered with
the LSM framework.

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 security/smack/smack.h           |  6 ++++++
 security/smack/smack_lsm.c       | 16 ++++++++++++++++
 security/smack/smack_netfilter.c |  4 +---
 security/smack/smackfs.c         |  4 +---
 4 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/security/smack/smack.h b/security/smack/smack.h
index bf6a6ed3946c..709e0d6cd5e1 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -275,6 +275,12 @@ struct smk_audit_info {
 #endif
 };
 
+/*
+ * Initialization
+ */
+int init_smk_fs(void);
+int smack_nf_ip_init(void);
+
 /*
  * These functions are in smack_access.c
  */
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index e09b33fed5f0..80b129a0c92c 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -5277,6 +5277,21 @@ static __init int smack_init(void)
 	return 0;
 }
 
+static int smack_initcall(void)
+{
+	int rc, rc_tmp;
+
+	rc_tmp = init_smk_fs();
+	if (rc_tmp)
+		rc = rc_tmp;
+
+	rc_tmp = smack_nf_ip_init();
+	if (!rc && rc_tmp)
+		rc = rc_tmp;
+
+	return rc;
+}
+
 /*
  * Smack requires early initialization in order to label
  * all processes and objects when they are created.
@@ -5286,4 +5301,5 @@ DEFINE_LSM(smack) = {
 	.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
 	.blobs = &smack_blob_sizes,
 	.init = smack_init,
+	.initcall_device = smack_initcall,
 };
diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c
index 8fd747b3653a..17ba578b1308 100644
--- a/security/smack/smack_netfilter.c
+++ b/security/smack/smack_netfilter.c
@@ -68,7 +68,7 @@ static struct pernet_operations smack_net_ops = {
 	.exit = smack_nf_unregister,
 };
 
-static int __init smack_nf_ip_init(void)
+int __init smack_nf_ip_init(void)
 {
 	if (smack_enabled == 0)
 		return 0;
@@ -76,5 +76,3 @@ static int __init smack_nf_ip_init(void)
 	printk(KERN_DEBUG "Smack: Registering netfilter hooks\n");
 	return register_pernet_subsys(&smack_net_ops);
 }
-
-__initcall(smack_nf_ip_init);
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 90a67e410808..d33dd0368807 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -2980,7 +2980,7 @@ static struct vfsmount *smackfs_mount;
  * Returns true if we were not chosen on boot or if
  * we were chosen and filesystem registration succeeded.
  */
-static int __init init_smk_fs(void)
+int __init init_smk_fs(void)
 {
 	int err;
 	int rc;
@@ -3023,5 +3023,3 @@ static int __init init_smk_fs(void)
 
 	return err;
 }
-
-__initcall(init_smk_fs);
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 21/29] tomoyo: move initcalls to the LSM framework
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (19 preceding siblings ...)
  2025-04-09 18:50 ` [RFC PATCH 20/29] smack: " Paul Moore
@ 2025-04-09 18:50 ` Paul Moore
  2025-04-09 23:43   ` Kees Cook
  2025-05-14 12:05   ` John Johansen
  2025-04-09 18:50 ` [RFC PATCH 22/29] safesetid: " Paul Moore
                   ` (8 subsequent siblings)
  29 siblings, 2 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:50 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 security/tomoyo/common.h        | 2 ++
 security/tomoyo/securityfs_if.c | 4 +---
 security/tomoyo/tomoyo.c        | 1 +
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
index 0e8e2e959aef..3b2a97d10a5d 100644
--- a/security/tomoyo/common.h
+++ b/security/tomoyo/common.h
@@ -924,6 +924,8 @@ struct tomoyo_task {
 
 /********** Function prototypes. **********/
 
+int tomoyo_interface_init(void);
+
 bool tomoyo_address_matches_group(const bool is_ipv6, const __be32 *address,
 				  const struct tomoyo_group *group);
 bool tomoyo_compare_number_union(const unsigned long value,
diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c
index 7e69747b2f77..33933645f5b9 100644
--- a/security/tomoyo/securityfs_if.c
+++ b/security/tomoyo/securityfs_if.c
@@ -233,7 +233,7 @@ static void __init tomoyo_create_entry(const char *name, const umode_t mode,
  *
  * Returns 0.
  */
-static int __init tomoyo_interface_init(void)
+int __init tomoyo_interface_init(void)
 {
 	struct tomoyo_domain_info *domain;
 	struct dentry *tomoyo_dir;
@@ -269,5 +269,3 @@ static int __init tomoyo_interface_init(void)
 	tomoyo_load_builtin_policy();
 	return 0;
 }
-
-fs_initcall(tomoyo_interface_init);
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index ed0f7b052a85..a015cf0c4a00 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -617,4 +617,5 @@ DEFINE_LSM(tomoyo) = {
 	.flags = LSM_FLAG_LEGACY_MAJOR,
 	.blobs = &tomoyo_blob_sizes,
 	.init = tomoyo_init,
+	.initcall_fs = tomoyo_interface_init,
 };
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 22/29] safesetid: move initcalls to the LSM framework
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (20 preceding siblings ...)
  2025-04-09 18:50 ` [RFC PATCH 21/29] tomoyo: " Paul Moore
@ 2025-04-09 18:50 ` Paul Moore
  2025-04-09 23:43   ` Kees Cook
  2025-05-14 12:18   ` John Johansen
  2025-04-09 18:50 ` [RFC PATCH 23/29] apparmor: " Paul Moore
                   ` (7 subsequent siblings)
  29 siblings, 2 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:50 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 security/safesetid/lsm.c        | 1 +
 security/safesetid/lsm.h        | 2 ++
 security/safesetid/securityfs.c | 3 +--
 3 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/security/safesetid/lsm.c b/security/safesetid/lsm.c
index 9a7c68d4e642..d5fb949050dd 100644
--- a/security/safesetid/lsm.c
+++ b/security/safesetid/lsm.c
@@ -289,4 +289,5 @@ static int __init safesetid_security_init(void)
 DEFINE_LSM(safesetid_security_init) = {
 	.id = &safesetid_lsmid,
 	.init = safesetid_security_init,
+	.initcall_fs = safesetid_init_securityfs,
 };
diff --git a/security/safesetid/lsm.h b/security/safesetid/lsm.h
index d346f4849cea..bf5172e2c3f7 100644
--- a/security/safesetid/lsm.h
+++ b/security/safesetid/lsm.h
@@ -70,4 +70,6 @@ enum sid_policy_type _setid_policy_lookup(struct setid_ruleset *policy,
 extern struct setid_ruleset __rcu *safesetid_setuid_rules;
 extern struct setid_ruleset __rcu *safesetid_setgid_rules;
 
+int safesetid_init_securityfs(void);
+
 #endif /* _SAFESETID_H */
diff --git a/security/safesetid/securityfs.c b/security/safesetid/securityfs.c
index 8e1ffd70b18a..ece259f75b0d 100644
--- a/security/safesetid/securityfs.c
+++ b/security/safesetid/securityfs.c
@@ -308,7 +308,7 @@ static const struct file_operations safesetid_gid_file_fops = {
 	.write = safesetid_gid_file_write,
 };
 
-static int __init safesetid_init_securityfs(void)
+int __init safesetid_init_securityfs(void)
 {
 	int ret;
 	struct dentry *policy_dir;
@@ -345,4 +345,3 @@ static int __init safesetid_init_securityfs(void)
 	securityfs_remove(policy_dir);
 	return ret;
 }
-fs_initcall(safesetid_init_securityfs);
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 23/29] apparmor: move initcalls to the LSM framework
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (21 preceding siblings ...)
  2025-04-09 18:50 ` [RFC PATCH 22/29] safesetid: " Paul Moore
@ 2025-04-09 18:50 ` Paul Moore
  2025-04-09 23:44   ` Kees Cook
  2025-05-14 13:33   ` John Johansen
  2025-04-09 18:50 ` [RFC PATCH 24/29] lockdown: " Paul Moore
                   ` (6 subsequent siblings)
  29 siblings, 2 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:50 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 security/apparmor/apparmorfs.c         | 4 +---
 security/apparmor/crypto.c             | 4 +---
 security/apparmor/include/apparmorfs.h | 2 ++
 security/apparmor/include/crypto.h     | 1 +
 security/apparmor/lsm.c                | 9 ++++++++-
 5 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 6039afae4bfc..0a7550a5bceb 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -2632,7 +2632,7 @@ static const struct inode_operations policy_link_iops = {
  *
  * Returns: error on failure
  */
-static int __init aa_create_aafs(void)
+int __init aa_create_aafs(void)
 {
 	struct dentry *dent;
 	int error;
@@ -2711,5 +2711,3 @@ static int __init aa_create_aafs(void)
 	AA_ERROR("Error creating AppArmor securityfs\n");
 	return error;
 }
-
-fs_initcall(aa_create_aafs);
diff --git a/security/apparmor/crypto.c b/security/apparmor/crypto.c
index aad486b2fca6..e4395c1bfac5 100644
--- a/security/apparmor/crypto.c
+++ b/security/apparmor/crypto.c
@@ -99,7 +99,7 @@ int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start,
 	return error;
 }
 
-static int __init init_profile_hash(void)
+int __init init_profile_hash(void)
 {
 	struct crypto_shash *tfm;
 
@@ -119,5 +119,3 @@ static int __init init_profile_hash(void)
 
 	return 0;
 }
-
-late_initcall(init_profile_hash);
diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h
index 1e94904f68d9..dd580594dfb7 100644
--- a/security/apparmor/include/apparmorfs.h
+++ b/security/apparmor/include/apparmorfs.h
@@ -104,6 +104,8 @@ enum aafs_prof_type {
 #define prof_dir(X) ((X)->dents[AAFS_PROF_DIR])
 #define prof_child_dir(X) ((X)->dents[AAFS_PROF_PROFS])
 
+int aa_create_aafs(void);
+
 void __aa_bump_ns_revision(struct aa_ns *ns);
 void __aafs_profile_rmdir(struct aa_profile *profile);
 void __aafs_profile_migrate_dents(struct aa_profile *old,
diff --git a/security/apparmor/include/crypto.h b/security/apparmor/include/crypto.h
index 636a04e20d91..f3ffd388cc58 100644
--- a/security/apparmor/include/crypto.h
+++ b/security/apparmor/include/crypto.h
@@ -13,6 +13,7 @@
 #include "policy.h"
 
 #ifdef CONFIG_SECURITY_APPARMOR_HASH
+int init_profile_hash(void);
 unsigned int aa_hash_size(void);
 char *aa_calc_hash(void *data, size_t len);
 int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start,
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index a7f6a3274682..2fefaab6349f 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -31,6 +31,7 @@
 #include "include/audit.h"
 #include "include/capability.h"
 #include "include/cred.h"
+#include "include/crypto.h"
 #include "include/file.h"
 #include "include/ipc.h"
 #include "include/net.h"
@@ -2146,7 +2147,6 @@ static int __init apparmor_nf_ip_init(void)
 
 	return 0;
 }
-__initcall(apparmor_nf_ip_init);
 #endif
 
 static char nulldfa_src[] = {
@@ -2277,4 +2277,11 @@ DEFINE_LSM(apparmor) = {
 	.enabled = &apparmor_enabled,
 	.blobs = &apparmor_blob_sizes,
 	.init = apparmor_init,
+	.initcall_fs = aa_create_aafs,
+#if defined(CONFIG_NETFILTER) && defined(CONFIG_NETWORK_SECMARK)
+	.initcall_device = apparmor_nf_ip_init,
+#endif
+#ifdef CONFIG_SECURITY_APPARMOR_HASH
+	.initcall_late = init_profile_hash,
+#endif
 };
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 24/29] lockdown: move initcalls to the LSM framework
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (22 preceding siblings ...)
  2025-04-09 18:50 ` [RFC PATCH 23/29] apparmor: " Paul Moore
@ 2025-04-09 18:50 ` Paul Moore
  2025-04-09 23:44   ` Kees Cook
  2025-05-14 13:31   ` John Johansen
  2025-04-09 18:50 ` [RFC PATCH 25/29] ima,evm: " Paul Moore
                   ` (5 subsequent siblings)
  29 siblings, 2 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:50 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 security/lockdown/lockdown.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/security/lockdown/lockdown.c b/security/lockdown/lockdown.c
index 4813f168ff93..8d46886d2cca 100644
--- a/security/lockdown/lockdown.c
+++ b/security/lockdown/lockdown.c
@@ -161,8 +161,6 @@ static int __init lockdown_secfs_init(void)
 	return PTR_ERR_OR_ZERO(dentry);
 }
 
-core_initcall(lockdown_secfs_init);
-
 #ifdef CONFIG_SECURITY_LOCKDOWN_LSM_EARLY
 DEFINE_EARLY_LSM(lockdown) = {
 #else
@@ -170,4 +168,5 @@ DEFINE_LSM(lockdown) = {
 #endif
 	.id = &lockdown_lsmid,
 	.init = lockdown_lsm_init,
+	.initcall_core = lockdown_secfs_init,
 };
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 25/29] ima,evm: move initcalls to the LSM framework
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (23 preceding siblings ...)
  2025-04-09 18:50 ` [RFC PATCH 24/29] lockdown: " Paul Moore
@ 2025-04-09 18:50 ` Paul Moore
  2025-05-14 13:06   ` John Johansen
  2025-05-30 22:03   ` Mimi Zohar
  2025-04-09 18:50 ` [RFC PATCH 26/29] selinux: " Paul Moore
                   ` (4 subsequent siblings)
  29 siblings, 2 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:50 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

This patch converts IMA and EVM to use the LSM frameworks's initcall
mechanism.  There were two challenges to doing this conversion: the
first simply being the number of initcalls across IMA and EVM, and the
second was the number of resources shared between the two related,
yet independent LSMs.

The first problem was resolved by the creation of two new functions,
integrity_device_init() and integrity_late_init(), with each focused on
calling all of the various IMA/EVM initcalls for a single initcall type.
The second problem was resolved by registering both of these new
functions as initcalls for each LSM and including code in each
registered initcall to ensure it only executes once.

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 security/integrity/Makefile                   |  2 +-
 security/integrity/evm/evm_main.c             |  7 +-
 security/integrity/iint.c                     |  4 +-
 security/integrity/ima/ima_main.c             |  7 +-
 security/integrity/ima/ima_mok.c              |  4 +-
 security/integrity/initcalls.c                | 97 +++++++++++++++++++
 security/integrity/initcalls.h                | 23 +++++
 .../integrity/platform_certs/load_ipl_s390.c  |  4 +-
 .../integrity/platform_certs/load_powerpc.c   |  4 +-
 security/integrity/platform_certs/load_uefi.c |  4 +-
 .../platform_certs/machine_keyring.c          |  4 +-
 .../platform_certs/platform_keyring.c         | 14 ++-
 12 files changed, 147 insertions(+), 27 deletions(-)
 create mode 100644 security/integrity/initcalls.c
 create mode 100644 security/integrity/initcalls.h

diff --git a/security/integrity/Makefile b/security/integrity/Makefile
index 92b63039c654..6ea330ea88b1 100644
--- a/security/integrity/Makefile
+++ b/security/integrity/Makefile
@@ -5,7 +5,7 @@
 
 obj-$(CONFIG_INTEGRITY) += integrity.o
 
-integrity-y := iint.o
+integrity-y := iint.o initcalls.o
 integrity-$(CONFIG_INTEGRITY_AUDIT) += integrity_audit.o
 integrity-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
 integrity-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index db8e324ed4e6..770d0411da2b 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -25,6 +25,7 @@
 #include <crypto/hash.h>
 #include <crypto/hash_info.h>
 #include <crypto/utils.h>
+#include "../initcalls.h"
 #include "evm.h"
 
 int evm_initialized;
@@ -1112,7 +1113,7 @@ void __init evm_load_x509(void)
 }
 #endif
 
-static int __init init_evm(void)
+int __init init_evm(void)
 {
 	int error;
 	struct list_head *pos, *q;
@@ -1179,6 +1180,6 @@ DEFINE_LSM(evm) = {
 	.init = init_evm_lsm,
 	.order = LSM_ORDER_LAST,
 	.blobs = &evm_blob_sizes,
+	.initcall_device = integrity_device_init,
+	.initcall_late = integrity_late_init,
 };
-
-late_initcall(init_evm);
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
index 068ac6c2ae1e..a4b88d67ff43 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -11,6 +11,7 @@
  */
 #include <linux/security.h>
 #include "integrity.h"
+#include "initcalls.h"
 
 struct dentry *integrity_dir;
 
@@ -42,7 +43,7 @@ void __init integrity_load_keys(void)
 		evm_load_x509();
 }
 
-static int __init integrity_fs_init(void)
+int __init integrity_fs_init(void)
 {
 	integrity_dir = securityfs_create_dir("integrity", NULL);
 	if (IS_ERR(integrity_dir)) {
@@ -58,4 +59,3 @@ static int __init integrity_fs_init(void)
 	return 0;
 }
 
-late_initcall(integrity_fs_init)
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 55a4f08a2565..1687badafb48 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -27,6 +27,7 @@
 #include <linux/fs.h>
 #include <linux/iversion.h>
 #include <linux/evm.h>
+#include "../initcalls.h"
 
 #include "ima.h"
 
@@ -1180,7 +1181,7 @@ static int ima_kernel_module_request(char *kmod_name)
 
 #endif /* CONFIG_INTEGRITY_ASYMMETRIC_KEYS */
 
-static int __init init_ima(void)
+int __init init_ima(void)
 {
 	int error;
 
@@ -1255,6 +1256,6 @@ DEFINE_LSM(ima) = {
 	.init = init_ima_lsm,
 	.order = LSM_ORDER_LAST,
 	.blobs = &ima_blob_sizes,
+	.initcall_device = integrity_device_init,
+	.initcall_late = integrity_late_init,
 };
-
-late_initcall(init_ima);	/* Start IMA after the TPM is available */
diff --git a/security/integrity/ima/ima_mok.c b/security/integrity/ima/ima_mok.c
index 95cc31525c57..4374fb6cc66d 100644
--- a/security/integrity/ima/ima_mok.c
+++ b/security/integrity/ima/ima_mok.c
@@ -14,6 +14,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <keys/system_keyring.h>
+#include "../initcalls.h"
 
 
 struct key *ima_blacklist_keyring;
@@ -21,7 +22,7 @@ struct key *ima_blacklist_keyring;
 /*
  * Allocate the IMA blacklist keyring
  */
-static __init int ima_mok_init(void)
+int __init ima_mok_init(void)
 {
 	struct key_restriction *restriction;
 
@@ -46,4 +47,3 @@ static __init int ima_mok_init(void)
 		panic("Can't allocate IMA blacklist keyring.");
 	return 0;
 }
-device_initcall(ima_mok_init);
diff --git a/security/integrity/initcalls.c b/security/integrity/initcalls.c
new file mode 100644
index 000000000000..de39754a1c2c
--- /dev/null
+++ b/security/integrity/initcalls.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Platform certificate / keyring initcalls
+ *
+ */
+
+#include <linux/init.h>
+
+#include "initcalls.h"
+
+/**
+ * integrity_device_init - device_initcalls for IMA/EVM
+ *
+ * This helper function wraps all of the device_initcalls for both IMA and EVM.
+ * It can be called multiple times, e.g. once from IMA and once from EVM,
+ * without problem as it maintains an internal static state variable which
+ * ensures that any setup/initialization is only done once.
+ */
+int __init integrity_device_init(void)
+{
+	int rc = 0, rc_tmp;
+	static bool setup = false;
+
+	if (setup)
+		return 0;
+	setup = true;
+
+#if defined(CONFIG_INTEGRITY_PLATFORM_KEYRING)
+	rc_tmp = platform_keyring_init();
+	if (!rc && rc_tmp)
+		rc = rc_tmp;
+#endif
+
+#if defined(CONFIG_INTEGRITY_MACHINE_KEYRING)
+	rc_tmp = machine_keyring_init();
+	if (!rc && rc_tmp)
+		rc = rc_tmp;
+#endif
+
+#if defined(CONFIG_IMA_BLACKLIST_KEYRING)
+	rc_tmp = ima_mok_init();
+	if (!rc && rc_tmp)
+		rc = rc_tmp;
+#endif
+
+	return rc;
+}
+
+/**
+ * integrity_late_init - late_initcalls for IMA/EVM
+ *
+ * This helper function wraps all of the late_initcalls for both IMA and EVM.
+ * It can be called multiple times, e.g. once from IMA and once from EVM,
+ * without problem as it maintains an internal static state variable which
+ * ensures that any setup/initialization is only done once.
+ */
+int __init integrity_late_init(void)
+{
+	int rc = 0, rc_tmp;
+	static bool setup = false;
+
+	if (setup)
+		return 0;
+	setup = true;
+
+#if defined(CONFIG_LOAD_UEFI_KEYS)
+	rc_tmp = load_uefi_certs();
+	if (!rc && rc_tmp)
+		rc = rc_tmp;
+#endif
+
+#if defined(CONFIG_LOAD_IPL_KEYS)
+	rc_tmp = load_ipl_certs();
+	if (!rc && rc_tmp)
+		rc = rc_tmp;
+#endif
+
+#if defined(CONFIG_LOAD_PPC_KEYS)
+	rc_tmp = load_powerpc_certs();
+	if (!rc && rc_tmp)
+		rc = rc_tmp;
+#endif
+
+	rc_tmp = integrity_fs_init();
+	if (!rc && rc_tmp)
+		rc = rc_tmp;
+
+	rc_tmp = init_ima();
+	if (!rc && rc_tmp)
+		rc = rc_tmp;
+
+	rc_tmp = init_evm();
+	if (!rc && rc_tmp)
+		rc = rc_tmp;
+
+	return rc;
+}
diff --git a/security/integrity/initcalls.h b/security/integrity/initcalls.h
new file mode 100644
index 000000000000..dce16abb3b8a
--- /dev/null
+++ b/security/integrity/initcalls.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef PLATFORM_CERTS_INITCALLS_H
+#define PLATFORM_CERTS_INITCALLS_H
+
+int machine_keyring_init(void);
+int platform_keyring_init(void);
+
+int load_uefi_certs(void);
+int load_ipl_certs(void);
+int load_powerpc_certs(void);
+
+int integrity_fs_init(void);
+
+int init_ima(void);
+int init_evm(void);
+
+int ima_mok_init(void);
+
+int integrity_device_init(void);
+int integrity_late_init(void);
+
+#endif
diff --git a/security/integrity/platform_certs/load_ipl_s390.c b/security/integrity/platform_certs/load_ipl_s390.c
index c7c381a9ddaa..3bf91d925614 100644
--- a/security/integrity/platform_certs/load_ipl_s390.c
+++ b/security/integrity/platform_certs/load_ipl_s390.c
@@ -10,12 +10,13 @@
 #include <keys/system_keyring.h>
 #include <asm/boot_data.h>
 #include "../integrity.h"
+#include "../initcalls.h"
 
 /*
  * Load the certs contained in the IPL report created by the machine loader
  * into the platform trusted keyring.
  */
-static int __init load_ipl_certs(void)
+int __init load_ipl_certs(void)
 {
 	void *ptr, *end;
 	unsigned int len;
@@ -33,4 +34,3 @@ static int __init load_ipl_certs(void)
 	}
 	return 0;
 }
-late_initcall(load_ipl_certs);
diff --git a/security/integrity/platform_certs/load_powerpc.c b/security/integrity/platform_certs/load_powerpc.c
index c85febca3343..2904559e485b 100644
--- a/security/integrity/platform_certs/load_powerpc.c
+++ b/security/integrity/platform_certs/load_powerpc.c
@@ -14,6 +14,7 @@
 #include <asm/secvar.h>
 #include "keyring_handler.h"
 #include "../integrity.h"
+#include "../initcalls.h"
 
 #define extract_esl(db, data, size, offset)	\
 	do { db = data + offset; size = size - offset; } while (0)
@@ -56,7 +57,7 @@ static __init void *get_cert_list(u8 *key, unsigned long keylen, u64 *size)
  * keyring and the blacklisted X.509 cert SHA256 hashes into the blacklist
  * keyring.
  */
-static int __init load_powerpc_certs(void)
+int __init load_powerpc_certs(void)
 {
 	void *db = NULL, *dbx = NULL, *data = NULL;
 	void *trustedca;
@@ -156,4 +157,3 @@ static int __init load_powerpc_certs(void)
 
 	return rc;
 }
-late_initcall(load_powerpc_certs);
diff --git a/security/integrity/platform_certs/load_uefi.c b/security/integrity/platform_certs/load_uefi.c
index d1fdd113450a..52c180704674 100644
--- a/security/integrity/platform_certs/load_uefi.c
+++ b/security/integrity/platform_certs/load_uefi.c
@@ -12,6 +12,7 @@
 #include <keys/system_keyring.h>
 #include "../integrity.h"
 #include "keyring_handler.h"
+#include "../initcalls.h"
 
 /*
  * On T2 Macs reading the db and dbx efi variables to load UEFI Secure Boot
@@ -157,7 +158,7 @@ static int __init load_moklist_certs(void)
  * keyring and the UEFI blacklisted X.509 cert SHA256 hashes into the blacklist
  * keyring.
  */
-static int __init load_uefi_certs(void)
+int __init load_uefi_certs(void)
 {
 	efi_guid_t secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
 	efi_guid_t mok_var = EFI_SHIM_LOCK_GUID;
@@ -235,4 +236,3 @@ static int __init load_uefi_certs(void)
 
 	return rc;
 }
-late_initcall(load_uefi_certs);
diff --git a/security/integrity/platform_certs/machine_keyring.c b/security/integrity/platform_certs/machine_keyring.c
index a401640a63cd..b49eb2bab7a2 100644
--- a/security/integrity/platform_certs/machine_keyring.c
+++ b/security/integrity/platform_certs/machine_keyring.c
@@ -7,8 +7,9 @@
 
 #include <linux/efi.h>
 #include "../integrity.h"
+#include "../initcalls.h"
 
-static __init int machine_keyring_init(void)
+int __init machine_keyring_init(void)
 {
 	int rc;
 
@@ -19,7 +20,6 @@ static __init int machine_keyring_init(void)
 	pr_notice("Machine keyring initialized\n");
 	return 0;
 }
-device_initcall(machine_keyring_init);
 
 void __init add_to_machine_keyring(const char *source, const void *data, size_t len)
 {
diff --git a/security/integrity/platform_certs/platform_keyring.c b/security/integrity/platform_certs/platform_keyring.c
index bcafd7387729..84a8e4309f06 100644
--- a/security/integrity/platform_certs/platform_keyring.c
+++ b/security/integrity/platform_certs/platform_keyring.c
@@ -13,6 +13,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include "../integrity.h"
+#include "../initcalls.h"
 
 /**
  * add_to_platform_keyring - Add to platform keyring without validation.
@@ -37,10 +38,12 @@ void __init add_to_platform_keyring(const char *source, const void *data,
 		pr_info("Error adding keys to platform keyring %s\n", source);
 }
 
-/*
- * Create the trusted keyrings.
+/**
+ * platform_keyring_init - Create the trusted keyrings.
+ *
+ * Must be initialised before we try and load the keys into the keyring.
  */
-static __init int platform_keyring_init(void)
+int __init platform_keyring_init(void)
 {
 	int rc;
 
@@ -51,8 +54,3 @@ static __init int platform_keyring_init(void)
 	pr_notice("Platform Keyring initialized\n");
 	return 0;
 }
-
-/*
- * Must be initialised before we try and load the keys into the keyring.
- */
-device_initcall(platform_keyring_init);
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 26/29] selinux: move initcalls to the LSM framework
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (24 preceding siblings ...)
  2025-04-09 18:50 ` [RFC PATCH 25/29] ima,evm: " Paul Moore
@ 2025-04-09 18:50 ` Paul Moore
  2025-04-10 16:33   ` Stephen Smalley
  2025-05-23 15:12   ` Casey Schaufler
  2025-04-09 18:50 ` [RFC PATCH 27/29] lsm: consolidate all of the LSM framework initcalls Paul Moore
                   ` (3 subsequent siblings)
  29 siblings, 2 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:50 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

SELinux currently has a number of initcalls so we've created a new
function, selinux_initcall(), which wraps all of these initcalls so
that we have a single initcall function that can be registered with the
LSM framework.

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 security/selinux/Makefile            |  2 +-
 security/selinux/hooks.c             |  9 +++--
 security/selinux/ibpkey.c            |  5 ++-
 security/selinux/include/audit.h     |  5 +++
 security/selinux/include/initcalls.h | 19 +++++++++++
 security/selinux/initcalls.c         | 50 ++++++++++++++++++++++++++++
 security/selinux/netif.c             |  5 ++-
 security/selinux/netlink.c           |  5 ++-
 security/selinux/netnode.c           |  5 ++-
 security/selinux/netport.c           |  5 ++-
 security/selinux/selinuxfs.c         |  5 ++-
 security/selinux/ss/services.c       | 26 ++++-----------
 12 files changed, 101 insertions(+), 40 deletions(-)
 create mode 100644 security/selinux/include/initcalls.h
 create mode 100644 security/selinux/initcalls.c

diff --git a/security/selinux/Makefile b/security/selinux/Makefile
index 66e56e9011df..72d3baf7900c 100644
--- a/security/selinux/Makefile
+++ b/security/selinux/Makefile
@@ -15,7 +15,7 @@ ccflags-y := -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
 ccflags-$(CONFIG_SECURITY_SELINUX_DEBUG) += -DDEBUG
 
 selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \
-	     netnode.o netport.o status.o \
+	     netnode.o netport.o status.o initcalls.o \
 	     ss/ebitmap.o ss/hashtab.o ss/symtab.o ss/sidtab.o ss/avtab.o \
 	     ss/policydb.o ss/services.o ss/conditional.o ss/mls.o ss/context.o
 
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f28a12a0a1c8..95b2399b1f4d 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -95,6 +95,7 @@
 #include <linux/io_uring/cmd.h>
 #include <uapi/linux/lsm.h>
 
+#include "initcalls.h"
 #include "avc.h"
 #include "objsec.h"
 #include "netif.h"
@@ -7535,6 +7536,10 @@ static __init int selinux_init(void)
 	if (avc_add_callback(selinux_lsm_notifier_avc_callback, AVC_CALLBACK_RESET))
 		panic("SELinux: Unable to register AVC LSM notifier callback\n");
 
+	if (avc_add_callback(selinux_audit_rule_avc_callback,
+			     AVC_CALLBACK_RESET))
+		panic("SELinux: Unable to register AVC audit callback\n");
+
 	if (selinux_enforcing_boot)
 		pr_debug("SELinux:  Starting in enforcing mode\n");
 	else
@@ -7567,6 +7572,7 @@ DEFINE_LSM(selinux) = {
 	.enabled = &selinux_enabled_boot,
 	.blobs = &selinux_blob_sizes,
 	.init = selinux_init,
+	.initcall_device = selinux_initcall,
 };
 
 #if defined(CONFIG_NETFILTER)
@@ -7628,7 +7634,7 @@ static struct pernet_operations selinux_net_ops = {
 	.exit = selinux_nf_unregister,
 };
 
-static int __init selinux_nf_ip_init(void)
+int __init selinux_nf_ip_init(void)
 {
 	int err;
 
@@ -7643,5 +7649,4 @@ static int __init selinux_nf_ip_init(void)
 
 	return 0;
 }
-__initcall(selinux_nf_ip_init);
 #endif /* CONFIG_NETFILTER */
diff --git a/security/selinux/ibpkey.c b/security/selinux/ibpkey.c
index 48f537b41c58..2609913f338a 100644
--- a/security/selinux/ibpkey.c
+++ b/security/selinux/ibpkey.c
@@ -23,6 +23,7 @@
 #include <linux/list.h>
 #include <linux/spinlock.h>
 
+#include "initcalls.h"
 #include "ibpkey.h"
 #include "objsec.h"
 
@@ -219,7 +220,7 @@ void sel_ib_pkey_flush(void)
 	spin_unlock_irqrestore(&sel_ib_pkey_lock, flags);
 }
 
-static __init int sel_ib_pkey_init(void)
+int __init sel_ib_pkey_init(void)
 {
 	int iter;
 
@@ -233,5 +234,3 @@ static __init int sel_ib_pkey_init(void)
 
 	return 0;
 }
-
-subsys_initcall(sel_ib_pkey_init);
diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h
index d5b0425055e4..5989f8dd1e86 100644
--- a/security/selinux/include/audit.h
+++ b/security/selinux/include/audit.h
@@ -15,6 +15,11 @@
 #include <linux/audit.h>
 #include <linux/types.h>
 
+/**
+ * XXX
+ */
+int selinux_audit_rule_avc_callback(u32 event);
+
 /**
  * selinux_audit_rule_init - alloc/init an selinux audit rule structure.
  * @field: the field this rule refers to
diff --git a/security/selinux/include/initcalls.h b/security/selinux/include/initcalls.h
new file mode 100644
index 000000000000..6674cf489473
--- /dev/null
+++ b/security/selinux/include/initcalls.h
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SELinux initcalls
+ */
+
+#ifndef _SELINUX_INITCALLS_H
+#define _SELINUX_INITCALLS_H
+
+int init_sel_fs(void);
+int sel_netport_init(void);
+int sel_netnode_init(void);
+int sel_netif_init(void);
+int sel_netlink_init(void);
+int sel_ib_pkey_init(void);
+int selinux_nf_ip_init(void);
+
+int selinux_initcall(void);
+
+#endif
diff --git a/security/selinux/initcalls.c b/security/selinux/initcalls.c
new file mode 100644
index 000000000000..81f01f8ad215
--- /dev/null
+++ b/security/selinux/initcalls.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SELinux initcalls
+ */
+
+#include <linux/init.h>
+
+#include "initcalls.h"
+
+/**
+ * selinux_initcall - Perform the SELinux initcalls
+ *
+ * Used as a device initcall in the SELinux LSM definition.
+ */
+int __init selinux_initcall(void)
+{
+	int rc = 0, rc_tmp = 0;
+
+	rc_tmp = init_sel_fs();
+	if (!rc && rc_tmp)
+		rc = rc_tmp;
+
+	rc_tmp = sel_netport_init();
+	if (!rc && rc_tmp)
+		rc = rc_tmp;
+
+	rc_tmp = sel_netnode_init();
+	if (!rc && rc_tmp)
+		rc = rc_tmp;
+
+	rc_tmp = sel_netif_init();
+	if (!rc && rc_tmp)
+		rc = rc_tmp;
+
+	rc_tmp = sel_netlink_init();
+	if (!rc && rc_tmp)
+		rc = rc_tmp;
+
+	rc_tmp = sel_ib_pkey_init();
+	if (!rc && rc_tmp)
+		rc = rc_tmp;
+
+#if defined(CONFIG_NETFILTER)
+	rc_tmp = selinux_nf_ip_init();
+	if (!rc && rc_tmp)
+		rc = rc_tmp;
+#endif
+
+	return rc;
+}
diff --git a/security/selinux/netif.c b/security/selinux/netif.c
index 43a0d3594b72..69f660721dc8 100644
--- a/security/selinux/netif.c
+++ b/security/selinux/netif.c
@@ -22,6 +22,7 @@
 #include <linux/rcupdate.h>
 #include <net/net_namespace.h>
 
+#include "initcalls.h"
 #include "security.h"
 #include "objsec.h"
 #include "netif.h"
@@ -261,7 +262,7 @@ static struct notifier_block sel_netif_netdev_notifier = {
 	.notifier_call = sel_netif_netdev_notifier_handler,
 };
 
-static __init int sel_netif_init(void)
+int __init sel_netif_init(void)
 {
 	int i;
 
@@ -276,5 +277,3 @@ static __init int sel_netif_init(void)
 	return 0;
 }
 
-__initcall(sel_netif_init);
-
diff --git a/security/selinux/netlink.c b/security/selinux/netlink.c
index 1760aee712fd..eb40e4603475 100644
--- a/security/selinux/netlink.c
+++ b/security/selinux/netlink.c
@@ -17,6 +17,7 @@
 #include <net/net_namespace.h>
 #include <net/netlink.h>
 
+#include "initcalls.h"
 #include "security.h"
 
 static struct sock *selnl __ro_after_init;
@@ -105,7 +106,7 @@ void selnl_notify_policyload(u32 seqno)
 	selnl_notify(SELNL_MSG_POLICYLOAD, &seqno);
 }
 
-static int __init selnl_init(void)
+int __init sel_netlink_init(void)
 {
 	struct netlink_kernel_cfg cfg = {
 		.groups	= SELNLGRP_MAX,
@@ -117,5 +118,3 @@ static int __init selnl_init(void)
 		panic("SELinux:  Cannot create netlink socket.");
 	return 0;
 }
-
-__initcall(selnl_init);
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c
index 5c8c77e50aad..11b5eac30641 100644
--- a/security/selinux/netnode.c
+++ b/security/selinux/netnode.c
@@ -30,6 +30,7 @@
 #include <net/ip.h>
 #include <net/ipv6.h>
 
+#include "initcalls.h"
 #include "netnode.h"
 #include "objsec.h"
 
@@ -287,7 +288,7 @@ void sel_netnode_flush(void)
 	spin_unlock_bh(&sel_netnode_lock);
 }
 
-static __init int sel_netnode_init(void)
+int __init sel_netnode_init(void)
 {
 	int iter;
 
@@ -301,5 +302,3 @@ static __init int sel_netnode_init(void)
 
 	return 0;
 }
-
-__initcall(sel_netnode_init);
diff --git a/security/selinux/netport.c b/security/selinux/netport.c
index 2e22ad9c2bd0..d1c12f58a628 100644
--- a/security/selinux/netport.c
+++ b/security/selinux/netport.c
@@ -29,6 +29,7 @@
 #include <net/ip.h>
 #include <net/ipv6.h>
 
+#include "initcalls.h"
 #include "netport.h"
 #include "objsec.h"
 
@@ -220,7 +221,7 @@ void sel_netport_flush(void)
 	spin_unlock_bh(&sel_netport_lock);
 }
 
-static __init int sel_netport_init(void)
+int __init sel_netport_init(void)
 {
 	int iter;
 
@@ -234,5 +235,3 @@ static __init int sel_netport_init(void)
 
 	return 0;
 }
-
-__initcall(sel_netport_init);
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 47480eb2189b..88d16c1dbb5a 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -35,6 +35,7 @@
 /* selinuxfs pseudo filesystem for exporting the security policy API.
    Based on the proc code and the fs/nfsd/nfsctl.c code. */
 
+#include "initcalls.h"
 #include "flask.h"
 #include "avc.h"
 #include "avc_ss.h"
@@ -2131,7 +2132,7 @@ static struct file_system_type sel_fs_type = {
 
 struct path selinux_null __ro_after_init;
 
-static int __init init_sel_fs(void)
+int __init init_sel_fs(void)
 {
 	struct qstr null_name = QSTR_INIT(NULL_FILE_NAME,
 					  sizeof(NULL_FILE_NAME)-1);
@@ -2175,5 +2176,3 @@ static int __init init_sel_fs(void)
 
 	return err;
 }
-
-__initcall(init_sel_fs);
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index e431772c6168..d84a496e5f7f 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -3534,6 +3534,13 @@ struct selinux_audit_rule {
 	struct context au_ctxt;
 };
 
+int selinux_audit_rule_avc_callback(u32 event)
+{
+	if (event == AVC_CALLBACK_RESET)
+		return audit_update_lsm_rules();
+	return 0;
+}
+
 void selinux_audit_rule_free(void *vrule)
 {
 	struct selinux_audit_rule *rule = vrule;
@@ -3784,25 +3791,6 @@ int selinux_audit_rule_match(struct lsm_prop *prop, u32 field, u32 op, void *vru
 	return match;
 }
 
-static int aurule_avc_callback(u32 event)
-{
-	if (event == AVC_CALLBACK_RESET)
-		return audit_update_lsm_rules();
-	return 0;
-}
-
-static int __init aurule_init(void)
-{
-	int err;
-
-	err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET);
-	if (err)
-		panic("avc_add_callback() failed, error %d\n", err);
-
-	return err;
-}
-__initcall(aurule_init);
-
 #ifdef CONFIG_NETLABEL
 /**
  * security_netlbl_cache_add - Add an entry to the NetLabel cache
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 27/29] lsm: consolidate all of the LSM framework initcalls
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (25 preceding siblings ...)
  2025-04-09 18:50 ` [RFC PATCH 26/29] selinux: " Paul Moore
@ 2025-04-09 18:50 ` Paul Moore
  2025-04-09 23:52   ` Kees Cook
  2025-05-14 13:38   ` John Johansen
  2025-04-09 18:50 ` [RFC PATCH 28/29] lsm: add a LSM_STARTED_ALL notification event Paul Moore
                   ` (2 subsequent siblings)
  29 siblings, 2 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:50 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

The LSM framework itself registers a small number of initcalls, this
patch converts these initcalls into the new initcall mechanism.

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 security/inode.c    |  3 +--
 security/lsm.h      |  4 ++++
 security/lsm_init.c | 14 ++++++++++++--
 security/min_addr.c |  5 +++--
 4 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/security/inode.c b/security/inode.c
index f687e22e6809..671c66c147bc 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -375,7 +375,7 @@ static const struct file_operations lsm_ops = {
 };
 #endif
 
-static int __init securityfs_init(void)
+int __init securityfs_init(void)
 {
 	int retval;
 
@@ -394,4 +394,3 @@ static int __init securityfs_init(void)
 #endif
 	return 0;
 }
-core_initcall(securityfs_init);
diff --git a/security/lsm.h b/security/lsm.h
index 8ecb66896646..c432dc0c5e30 100644
--- a/security/lsm.h
+++ b/security/lsm.h
@@ -35,4 +35,8 @@ extern struct kmem_cache *lsm_inode_cache;
 int lsm_cred_alloc(struct cred *cred, gfp_t gfp);
 int lsm_task_alloc(struct task_struct *task);
 
+/* LSM framework initializers */
+int securityfs_init(void);
+int min_addr_init(void);
+
 #endif /* _LSM_H_ */
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 75eb0cc82869..c0881407ca3f 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -485,7 +485,12 @@ int __init security_init(void)
  */
 static int __init security_initcall_pure(void)
 {
-	return lsm_initcall(pure);
+	int rc_adr, rc_lsm;
+
+	rc_adr = min_addr_init();
+	rc_lsm = lsm_initcall(pure);
+
+	return (rc_adr ? rc_adr : rc_lsm);
 }
 pure_initcall(security_initcall_pure);
 
@@ -503,7 +508,12 @@ early_initcall(security_initcall_early);
  */
 static int __init security_initcall_core(void)
 {
-	return lsm_initcall(core);
+	int rc_sfs, rc_lsm;
+
+	rc_sfs = securityfs_init();
+	rc_lsm = lsm_initcall(core);
+
+	return (rc_sfs ? rc_sfs : rc_lsm);
 }
 core_initcall(security_initcall_core);
 
diff --git a/security/min_addr.c b/security/min_addr.c
index df1bc643d886..40714bdeefbe 100644
--- a/security/min_addr.c
+++ b/security/min_addr.c
@@ -4,6 +4,8 @@
 #include <linux/security.h>
 #include <linux/sysctl.h>
 
+#include "lsm.h"
+
 /* amount of vm to protect from userspace access by both DAC and the LSM*/
 unsigned long mmap_min_addr;
 /* amount of vm to protect from userspace using CAP_SYS_RAWIO (DAC) */
@@ -54,11 +56,10 @@ static const struct ctl_table min_addr_sysctl_table[] = {
 	},
 };
 
-static int __init init_mmap_min_addr(void)
+int __init min_addr_init(void)
 {
 	register_sysctl_init("vm", min_addr_sysctl_table);
 	update_mmap_min_addr();
 
 	return 0;
 }
-pure_initcall(init_mmap_min_addr);
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 28/29] lsm: add a LSM_STARTED_ALL notification event
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (26 preceding siblings ...)
  2025-04-09 18:50 ` [RFC PATCH 27/29] lsm: consolidate all of the LSM framework initcalls Paul Moore
@ 2025-04-09 18:50 ` Paul Moore
  2025-04-09 23:53   ` Kees Cook
  2025-05-14 13:34   ` John Johansen
  2025-04-09 18:50 ` [RFC PATCH 29/29] lsm: add support for counting lsm_prop support among LSMs Paul Moore
  2025-04-10 14:13 ` [RFC PATCH 0/29] Rework the LSM initialization Casey Schaufler
  29 siblings, 2 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:50 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

Add a new LSM notifier event, LSM_STARTED_ALL, which is fired once at
boot when all of the LSMs have been started.

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 include/linux/security.h | 1 +
 security/lsm_init.c      | 1 +
 2 files changed, 2 insertions(+)

diff --git a/include/linux/security.h b/include/linux/security.h
index 8aac21787a9f..a0ff4fc69375 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -85,6 +85,7 @@ struct timezone;
 
 enum lsm_event {
 	LSM_POLICY_CHANGE,
+	LSM_STARTED_ALL,
 };
 
 struct dm_verity_digest {
diff --git a/security/lsm_init.c b/security/lsm_init.c
index c0881407ca3f..cad6d243a2a6 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -553,6 +553,7 @@ static int __init security_initcall_late(void)
 
 	rc = lsm_initcall(late);
 	lsm_pr_dbg("all enabled LSMs fully activated\n");
+	call_blocking_lsm_notifier(LSM_STARTED_ALL, NULL);
 
 	return rc;
 }
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* [RFC PATCH 29/29] lsm: add support for counting lsm_prop support among LSMs
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (27 preceding siblings ...)
  2025-04-09 18:50 ` [RFC PATCH 28/29] lsm: add a LSM_STARTED_ALL notification event Paul Moore
@ 2025-04-09 18:50 ` Paul Moore
  2025-05-13 16:39   ` Casey Schaufler
  2025-04-10 14:13 ` [RFC PATCH 0/29] Rework the LSM initialization Casey Schaufler
  29 siblings, 1 reply; 126+ messages in thread
From: Paul Moore @ 2025-04-09 18:50 UTC (permalink / raw)
  To: linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Casey Schaufler, Tetsuo Handa

Add two new variables, lsm_count_prop_subj and lsm_count_prop_obj, to
count the number of lsm_prop entries for subjects and objects across all
of the enabled LSMs.  Future patches will use this to continue the
conversion towards the lsm_prop struct.

Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 include/linux/lsm_hooks.h         | 6 ++++++
 security/apparmor/lsm.c           | 1 +
 security/bpf/hooks.c              | 1 +
 security/commoncap.c              | 1 +
 security/integrity/evm/evm_main.c | 1 +
 security/integrity/ima/ima_main.c | 1 +
 security/ipe/ipe.c                | 1 +
 security/landlock/setup.c         | 1 +
 security/loadpin/loadpin.c        | 1 +
 security/lockdown/lockdown.c      | 1 +
 security/lsm.h                    | 4 ++++
 security/lsm_init.c               | 6 ++++++
 security/safesetid/lsm.c          | 1 +
 security/security.c               | 3 +++
 security/selinux/hooks.c          | 1 +
 security/smack/smack_lsm.c        | 1 +
 security/tomoyo/tomoyo.c          | 1 +
 security/yama/yama_lsm.c          | 1 +
 18 files changed, 33 insertions(+)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 0d2c2a017ffc..5bc144c5f685 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -71,16 +71,22 @@ struct lsm_static_calls_table {
 	#undef LSM_HOOK
 } __packed __randomize_layout;
 
+#define LSM_ID_FLG_NONE			0x00000000
+#define LSM_ID_FLG_PROP_SUBJ		0x00000001
+#define LSM_ID_FLG_PROP_OBJ		0x00000002
+
 /**
  * struct lsm_id - Identify a Linux Security Module.
  * @lsm: name of the LSM, must be approved by the LSM maintainers
  * @id: LSM ID number from uapi/linux/lsm.h
+ * @flags: LSM flags, see LSM_ID_FLG_XXX
  *
  * Contains the information that identifies the LSM.
  */
 struct lsm_id {
 	const char *name;
 	u64 id;
+	u32 flags;
 };
 
 /*
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 2fefaab6349f..db8592bed189 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -1428,6 +1428,7 @@ struct lsm_blob_sizes apparmor_blob_sizes __ro_after_init = {
 static const struct lsm_id apparmor_lsmid = {
 	.name = "apparmor",
 	.id = LSM_ID_APPARMOR,
+	.flags = LSM_ID_FLG_PROP_SUBJ,
 };
 
 static struct security_hook_list apparmor_hooks[] __ro_after_init = {
diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c
index 40efde233f3a..c72df6ff69f7 100644
--- a/security/bpf/hooks.c
+++ b/security/bpf/hooks.c
@@ -18,6 +18,7 @@ static struct security_hook_list bpf_lsm_hooks[] __ro_after_init = {
 static const struct lsm_id bpf_lsmid = {
 	.name = "bpf",
 	.id = LSM_ID_BPF,
+	.flags = LSM_ID_FLG_PROP_SUBJ | LSM_ID_FLG_PROP_OBJ,
 };
 
 static int __init bpf_lsm_init(void)
diff --git a/security/commoncap.c b/security/commoncap.c
index e04aa4f50eaf..fab692104c87 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -1479,6 +1479,7 @@ int cap_mmap_addr(unsigned long addr)
 static const struct lsm_id capability_lsmid = {
 	.name = "capability",
 	.id = LSM_ID_CAPABILITY,
+	.flags = LSM_ID_FLG_NONE,
 };
 
 static struct security_hook_list capability_hooks[] __ro_after_init = {
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 770d0411da2b..b3a3324f48b1 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -1162,6 +1162,7 @@ static struct security_hook_list evm_hooks[] __ro_after_init = {
 static const struct lsm_id evm_lsmid = {
 	.name = "evm",
 	.id = LSM_ID_EVM,
+	.flags = LSM_ID_FLG_NONE,
 };
 
 static int __init init_evm_lsm(void)
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 1687badafb48..d98e7815175b 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -1237,6 +1237,7 @@ static struct security_hook_list ima_hooks[] __ro_after_init = {
 static const struct lsm_id ima_lsmid = {
 	.name = "ima",
 	.id = LSM_ID_IMA,
+	.flags = LSM_ID_FLG_NONE,
 };
 
 static int __init init_ima_lsm(void)
diff --git a/security/ipe/ipe.c b/security/ipe/ipe.c
index 71644748ed56..7d9cdbc3d23a 100644
--- a/security/ipe/ipe.c
+++ b/security/ipe/ipe.c
@@ -24,6 +24,7 @@ static struct lsm_blob_sizes ipe_blobs __ro_after_init = {
 static const struct lsm_id ipe_lsmid = {
 	.name = "ipe",
 	.id = LSM_ID_IPE,
+	.flags = LSM_ID_FLG_NONE,
 };
 
 struct ipe_superblock *ipe_sb(const struct super_block *sb)
diff --git a/security/landlock/setup.c b/security/landlock/setup.c
index 47dac1736f10..5c8d5693c4c7 100644
--- a/security/landlock/setup.c
+++ b/security/landlock/setup.c
@@ -25,6 +25,7 @@ bool landlock_initialized __ro_after_init = false;
 const struct lsm_id landlock_lsmid = {
 	.name = LANDLOCK_NAME,
 	.id = LSM_ID_LANDLOCK,
+	.flags = LSM_ID_FLG_NONE,
 };
 
 struct lsm_blob_sizes landlock_blob_sizes __ro_after_init = {
diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c
index 273ffbd6defe..05a842c36fd8 100644
--- a/security/loadpin/loadpin.c
+++ b/security/loadpin/loadpin.c
@@ -211,6 +211,7 @@ static int loadpin_load_data(enum kernel_load_data_id id, bool contents)
 static const struct lsm_id loadpin_lsmid = {
 	.name = "loadpin",
 	.id = LSM_ID_LOADPIN,
+	.flags = LSM_ID_FLG_NONE,
 };
 
 static struct security_hook_list loadpin_hooks[] __ro_after_init = {
diff --git a/security/lockdown/lockdown.c b/security/lockdown/lockdown.c
index 8d46886d2cca..a2396b67bfe4 100644
--- a/security/lockdown/lockdown.c
+++ b/security/lockdown/lockdown.c
@@ -79,6 +79,7 @@ static struct security_hook_list lockdown_hooks[] __ro_after_init = {
 static const struct lsm_id lockdown_lsmid = {
 	.name = "lockdown",
 	.id = LSM_ID_LOCKDOWN,
+	.flags = LSM_ID_FLG_NONE,
 };
 
 static int __init lockdown_lsm_init(void)
diff --git a/security/lsm.h b/security/lsm.h
index c432dc0c5e30..d1d54540da98 100644
--- a/security/lsm.h
+++ b/security/lsm.h
@@ -24,6 +24,10 @@ extern bool lsm_debug;
 extern unsigned int lsm_count;
 extern const struct lsm_id *lsm_idlist[];
 
+/* LSM property configuration */
+extern unsigned int lsm_count_prop_subj;
+extern unsigned int lsm_count_prop_obj;
+
 /* LSM blob configuration */
 extern struct lsm_blob_sizes blob_sizes;
 
diff --git a/security/lsm_init.c b/security/lsm_init.c
index cad6d243a2a6..c2ef4db055db 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -6,6 +6,7 @@
 #define pr_fmt(fmt) "LSM: " fmt
 
 #include <linux/init.h>
+#include <linux/lsm_count.h>
 #include <linux/lsm_hooks.h>
 
 #include "lsm.h"
@@ -189,6 +190,11 @@ static void __init lsm_order_append(struct lsm_info *lsm, const char *src)
 	lsm_order[lsm_count] = lsm;
 	lsm_idlist[lsm_count++] = lsm->id;
 
+	if (lsm->id->flags & LSM_ID_FLG_PROP_SUBJ)
+		lsm_count_prop_subj++;
+	if (lsm->id->flags & LSM_ID_FLG_PROP_OBJ)
+		lsm_count_prop_obj++;
+
 	lsm_pr_dbg("enabling LSM %s:%s\n", src, lsm->id->name);
 }
 
diff --git a/security/safesetid/lsm.c b/security/safesetid/lsm.c
index d5fb949050dd..ac25674376fe 100644
--- a/security/safesetid/lsm.c
+++ b/security/safesetid/lsm.c
@@ -265,6 +265,7 @@ static int safesetid_task_fix_setgroups(struct cred *new, const struct cred *old
 static const struct lsm_id safesetid_lsmid = {
 	.name = "safesetid",
 	.id = LSM_ID_SAFESETID,
+	.flags = LSM_ID_FLG_NONE,
 };
 
 static struct security_hook_list safesetid_security_hooks[] = {
diff --git a/security/security.c b/security/security.c
index cbd544d71093..2b9dde02f4de 100644
--- a/security/security.c
+++ b/security/security.c
@@ -78,6 +78,9 @@ bool lsm_debug __ro_after_init;
 unsigned int lsm_count __ro_after_init;
 const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
 
+unsigned int lsm_count_prop_subj __ro_after_init;
+unsigned int lsm_count_prop_obj __ro_after_init;
+
 struct lsm_blob_sizes blob_sizes;
 
 struct kmem_cache *lsm_file_cache;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 95b2399b1f4d..1dc4b3987af4 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -7200,6 +7200,7 @@ static int selinux_uring_allowed(void)
 static const struct lsm_id selinux_lsmid = {
 	.name = "selinux",
 	.id = LSM_ID_SELINUX,
+	.flags = LSM_ID_FLG_PROP_SUBJ | LSM_ID_FLG_PROP_OBJ,
 };
 
 /*
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 80b129a0c92c..d04667a42f91 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -5042,6 +5042,7 @@ struct lsm_blob_sizes smack_blob_sizes __ro_after_init = {
 static const struct lsm_id smack_lsmid = {
 	.name = "smack",
 	.id = LSM_ID_SMACK,
+	.flags = LSM_ID_FLG_PROP_SUBJ | LSM_ID_FLG_PROP_OBJ,
 };
 
 static struct security_hook_list smack_hooks[] __ro_after_init = {
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index a015cf0c4a00..0a030cbdf424 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -547,6 +547,7 @@ static void tomoyo_task_free(struct task_struct *task)
 static const struct lsm_id tomoyo_lsmid = {
 	.name = "tomoyo",
 	.id = LSM_ID_TOMOYO,
+	.flags = LSM_ID_FLG_NONE,
 };
 
 /* tomoyo_hooks is used for registering TOMOYO. */
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c
index 38b21ee0c560..e4a6cf663177 100644
--- a/security/yama/yama_lsm.c
+++ b/security/yama/yama_lsm.c
@@ -419,6 +419,7 @@ static int yama_ptrace_traceme(struct task_struct *parent)
 static const struct lsm_id yama_lsmid = {
 	.name = "yama",
 	.id = LSM_ID_YAMA,
+	.flags = LSM_ID_FLG_NONE,
 };
 
 static struct security_hook_list yama_hooks[] __ro_after_init = {
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 17/29] lsm: introduce an initcall mechanism into the LSM framework
  2025-04-09 18:50 ` [RFC PATCH 17/29] lsm: introduce an initcall mechanism into the LSM framework Paul Moore
@ 2025-04-09 21:16   ` Kees Cook
  2025-04-10 20:52     ` Paul Moore
  2025-05-14 11:59   ` John Johansen
  1 sibling, 1 reply; 126+ messages in thread
From: Kees Cook @ 2025-04-09 21:16 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 09, 2025 at 02:50:02PM -0400, Paul Moore wrote:
> Currently the individual LSMs register their own initcalls, and while
> this should be harmless, it can be wasteful in the case where a LSM
> is disabled at boot as the initcall will still be executed.  This
> patch introduces support for managing the initcalls in the LSM
> framework, and future patches will convert the existing LSMs over to
> this new mechanism.
> 
> Only initcall types which are used by the current in-tree LSMs are
> supported, additional initcall types can easily be added in the future
> if needed.
> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
>  include/linux/lsm_hooks.h | 33 ++++++++++++---
>  security/lsm_init.c       | 89 +++++++++++++++++++++++++++++++++++++++
>  2 files changed, 117 insertions(+), 5 deletions(-)
> 
> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
> index a7ecb0791a0f..0d2c2a017ffc 100644
> --- a/include/linux/lsm_hooks.h
> +++ b/include/linux/lsm_hooks.h
> @@ -148,13 +148,36 @@ enum lsm_order {
>  	LSM_ORDER_LAST = 1,	/* This is only for integrity. */
>  };
>  
> +/**
> + * struct lsm_info - Define an individual LSM for the LSM framework.
> + * @id: LSM name/ID info
> + * @order: ordering with respect to other LSMs, optional
> + * @flags: descriptive flags, optional
> + * @blobs: LSM blob sharing, optional
> + * @enabled: controlled by CONFIG_LSM, optional
> + * @init: LSM specific initialization routine
> + * @initcall_pure: LSM callback for initcall_pure() setup, optional
> + * @initcall_early: LSM callback for early_initcall setup, optional
> + * @initcall_core: LSM callback for core_initcall() setup, optional
> + * @initcall_subsys: LSM callback for subsys_initcall() setup, optional
> + * @initcall_fs: LSM callback for fs_initcall setup, optional
> + * @nitcall_device: LSM callback for device_initcall() setup, optional
> + * @initcall_late: LSM callback for late_initcall() setup, optional
> + */

Yay! Proper kerndoc. :)

>  struct lsm_info {
>  	const struct lsm_id *id;
> -	enum lsm_order order;	/* Optional: default is LSM_ORDER_MUTABLE */
> -	unsigned long flags;	/* Optional: flags describing LSM */
> -	int *enabled;		/* Optional: controlled by CONFIG_LSM */
> -	int (*init)(void);	/* Required. */
> -	struct lsm_blob_sizes *blobs; /* Optional: for blob sharing. */
> +	enum lsm_order order;
> +	unsigned long flags;
> +	struct lsm_blob_sizes *blobs;
> +	int *enabled;
> +	int (*init)(void);
> +	int (*initcall_pure)(void);
> +	int (*initcall_early)(void);
> +	int (*initcall_core)(void);
> +	int (*initcall_subsys)(void);
> +	int (*initcall_fs)(void);
> +	int (*initcall_device)(void);
> +	int (*initcall_late)(void);
>  };
>  
>  #define DEFINE_LSM(lsm)							\
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 8e00afeb84cf..75eb0cc82869 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -39,6 +39,27 @@ static __initdata struct lsm_info *lsm_order[MAX_LSM_COUNT + 1];
>  	for ((iter) = __start_early_lsm_info;				\
>  	     (iter) < __end_early_lsm_info; (iter)++)
>  
> +#define lsm_initcall(level)						\
> +	({ 								\
> +		int _r, _rc = 0;					\
> +		struct lsm_info **_lp, *_l; 				\
> +		lsm_order_for_each(_lp) { 				\
> +			_l = *_lp; 					\
> +			if (!_l->initcall_##level) 			\
> +				continue;				\
> +			lsm_pr_dbg("running %s %s initcall",		\
> +				   _l->id->name, #level);		\
> +			_r = _l->initcall_##level();			\
> +			if (_r) {					\
> +				pr_warn("failed LSM %s %s initcall with errno %d\n", \
> +					_l->id->name, #level, _r);	\
> +				if (!_rc)				\
> +					_rc = _r;			\
> +			}						\
> +		}							\
> +		_rc;							\
> +	})
> +
>  /**
>   * lsm_choose_security - Legacy "major" LSM selection
>   * @str: kernel command line parameter
> @@ -458,3 +479,71 @@ int __init security_init(void)
>  
>  	return 0;
>  }
> +
> +/**
> + * security_initcall_pure - Run the LSM pure initcalls
> + */
> +static int __init security_initcall_pure(void)
> +{
> +	return lsm_initcall(pure);
> +}
> +pure_initcall(security_initcall_pure);
> +
> +/**
> + * security_initcall_early - Run the LSM early initcalls
> + */
> +static int __init security_initcall_early(void)
> +{
> +	return lsm_initcall(early);
> +}
> +early_initcall(security_initcall_early);
> +
> +/**
> + * security_initcall_core - Run the LSM core initcalls
> + */
> +static int __init security_initcall_core(void)
> +{
> +	return lsm_initcall(core);
> +}
> +core_initcall(security_initcall_core);
> +
> +/**
> + * security_initcall_subsys - Run the LSM subsys initcalls
> + */
> +static int __init security_initcall_subsys(void)
> +{
> +	return lsm_initcall(subsys);
> +}
> +subsys_initcall(security_initcall_subsys);
> +
> +/**
> + * security_initcall_fs - Run the LSM fs initcalls
> + */
> +static int __init security_initcall_fs(void)
> +{
> +	return lsm_initcall(fs);
> +}
> +fs_initcall(security_initcall_fs);
> +
> +/**
> + * security_initcall_device - Run the LSM device initcalls
> + */
> +static int __init security_initcall_device(void)
> +{
> +	return lsm_initcall(device);
> +}
> +device_initcall(security_initcall_device);
> +
> +/**
> + * security_initcall_late - Run the LSM late initcalls
> + */
> +static int __init security_initcall_late(void)
> +{
> +	int rc;
> +
> +	rc = lsm_initcall(late);
> +	lsm_pr_dbg("all enabled LSMs fully activated\n");
> +
> +	return rc;
> +}
> +late_initcall(security_initcall_late);

You'd need a new place for the lsm_pr_dbg, but these are all just
copy/paste. These could be macro-ified too?

#define define_lsm_initcall(level)			\
static int __init security_initcall_##level(void)	\
{							\
	return lsm_initcall(level);			\
}							\
level##_initcall(security_initcall_##level)

define_lsm_initcall(pure);
define_lsm_initcall(early);
define_lsm_initcall(core);
define_lsm_initcall(subsys);
define_lsm_initcall(fs);
define_lsm_initcall(device);
define_lsm_initcall(late);

I'm not sure exposing the kerndoc for them is worth open-coding them?

And, actually, it's just a macro calling a macro. You could just combine
them? i.e. turn lsm_initcall() into:

#define define_lsm_initcall(level)				\
static int __init security_initcall_##level(void)		\
{	 							\
	int _r, _rc = 0;					\
	struct lsm_info **_lp, *_l; 				\
	...
	return _rc;						\
}								\
level##_initcall(security_initcall_##level)


But, I like it either way.

Reviewed-by: Kees Cook <kees@kernel.org>

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 01/29] lsm: split the notifier code out into lsm_notifier.c
  2025-04-09 18:49 ` [RFC PATCH 01/29] lsm: split the notifier code out into lsm_notifier.c Paul Moore
@ 2025-04-09 21:17   ` Kees Cook
  2025-04-15 12:14   ` John Johansen
  1 sibling, 0 replies; 126+ messages in thread
From: Kees Cook @ 2025-04-09 21:17 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 09, 2025 at 02:49:46PM -0400, Paul Moore wrote:
> In an effort to decompose security/security.c somewhat to make it less
> twisted and unwieldy, pull out the LSM notifier code into a new file
> as it is fairly well self-contained.
> 
> No code changes.
> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>

Yeah, seems good.

Reviewed-by: Kees Cook <kees@kernel.org>

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 02/29] lsm: split the init code out into lsm_init.c
  2025-04-09 18:49 ` [RFC PATCH 02/29] lsm: split the init code out into lsm_init.c Paul Moore
@ 2025-04-09 21:18   ` Kees Cook
  2025-04-15 22:01   ` John Johansen
  1 sibling, 0 replies; 126+ messages in thread
From: Kees Cook @ 2025-04-09 21:18 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 09, 2025 at 02:49:47PM -0400, Paul Moore wrote:
> Continue to pull code out of security/security.c to help improve
> readability by pulling all of the LSM framework initialization
> code out into a new file.
> 
> No code changes.

No behavioral changes, but this allows for the section arrays to avoid
being exposed in a common header. I think the reorganization it worth it
for this alone! :)

> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>

Reviewed-by: Kees Cook <kees@kernel.org>

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 03/29] lsm: simplify prepare_lsm() and rename to lsm_prep_single()
  2025-04-09 18:49 ` [RFC PATCH 03/29] lsm: simplify prepare_lsm() and rename to lsm_prep_single() Paul Moore
@ 2025-04-09 21:30   ` Kees Cook
  2025-04-09 21:54     ` Paul Moore
  2025-04-15 22:10   ` John Johansen
  1 sibling, 1 reply; 126+ messages in thread
From: Kees Cook @ 2025-04-09 21:30 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 09, 2025 at 02:49:48PM -0400, Paul Moore wrote:
> One part of a larger effort to cleanup the LSM framework initialization
> code.

This commit log needs improvement. i.e. explain what and why:

The execution flow through lsm_allowed(), prepare_lsm(), and
lsm_set_blob_sizes() is a bit convoluted. Merge the logic of all three
into a single new function, lsm_prep_single().

> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
>  security/lsm_init.c | 103 ++++++++++++++++++--------------------------
>  1 file changed, 43 insertions(+), 60 deletions(-)
> 
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 70e7d4207dae..dffa8dc2da36 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -123,22 +123,6 @@ static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
>  		   is_enabled(lsm) ? "enabled" : "disabled");
>  }
>  
> -/* Is an LSM allowed to be initialized? */
> -static bool __init lsm_allowed(struct lsm_info *lsm)
> -{
> -	/* Skip if the LSM is disabled. */
> -	if (!is_enabled(lsm))
> -		return false;
> -
> -	/* Not allowed if another exclusive LSM already initialized. */
> -	if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
> -		init_debug("exclusive disabled: %s\n", lsm->name);
> -		return false;
> -	}
> -
> -	return true;
> -}
> -
>  static void __init lsm_set_blob_size(int *need, int *lbs)
>  {
>  	int offset;
> @@ -151,51 +135,50 @@ static void __init lsm_set_blob_size(int *need, int *lbs)
>  	*need = offset;
>  }
>  
> -static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
> +/**
> + * lsm_prep_single - Prepare the LSM framework for a new LSM
> + * @lsm: LSM definition
> + */
> +static void __init lsm_prep_single(struct lsm_info *lsm)

Nit-pick on naming: why shorten "prepare"?

>  {
> -	if (!needed)
> +	struct lsm_blob_sizes *blobs;
> +
> +	if (!is_enabled(lsm)) {
> +		set_enabled(lsm, false);
> +		return;
> +	} else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
> +		init_debug("exclusive disabled: %s\n", lsm->name);
> +		set_enabled(lsm, false);
>  		return;
> -
> -	lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
> -	lsm_set_blob_size(&needed->lbs_file, &blob_sizes.lbs_file);
> -	lsm_set_blob_size(&needed->lbs_ib, &blob_sizes.lbs_ib);
> -	/*
> -	 * The inode blob gets an rcu_head in addition to
> -	 * what the modules might need.
> -	 */
> -	if (needed->lbs_inode && blob_sizes.lbs_inode == 0)
> -		blob_sizes.lbs_inode = sizeof(struct rcu_head);
> -	lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
> -	lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
> -	lsm_set_blob_size(&needed->lbs_key, &blob_sizes.lbs_key);
> -	lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
> -	lsm_set_blob_size(&needed->lbs_perf_event, &blob_sizes.lbs_perf_event);
> -	lsm_set_blob_size(&needed->lbs_sock, &blob_sizes.lbs_sock);
> -	lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
> -	lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
> -	lsm_set_blob_size(&needed->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
> -	lsm_set_blob_size(&needed->lbs_xattr_count,
> -			  &blob_sizes.lbs_xattr_count);
> -	lsm_set_blob_size(&needed->lbs_bdev, &blob_sizes.lbs_bdev);
> -}
> -
> -/* Prepare LSM for initialization. */
> -static void __init prepare_lsm(struct lsm_info *lsm)
> -{
> -	int enabled = lsm_allowed(lsm);
> -
> -	/* Record enablement (to handle any following exclusive LSMs). */
> -	set_enabled(lsm, enabled);
> -
> -	/* If enabled, do pre-initialization work. */
> -	if (enabled) {
> -		if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
> -			exclusive = lsm;
> -			init_debug("exclusive chosen:   %s\n", lsm->name);
> -		}
> -
> -		lsm_set_blob_sizes(lsm->blobs);
>  	}
> +
> +	/* Mark the LSM as enabled. */
> +	set_enabled(lsm, true);
> +	if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
> +		init_debug("exclusive chosen:   %s\n", lsm->name);
> +		exclusive = lsm;
> +	}
> +
> +	/* Register the LSM blob sizes. */
> +	blobs = lsm->blobs;
> +	lsm_set_blob_size(&blobs->lbs_cred, &blob_sizes.lbs_cred);
> +	lsm_set_blob_size(&blobs->lbs_file, &blob_sizes.lbs_file);
> +	lsm_set_blob_size(&blobs->lbs_ib, &blob_sizes.lbs_ib);
> +	/* inode blob gets an rcu_head in addition to LSM blobs. */
> +	if (blobs->lbs_inode && blob_sizes.lbs_inode == 0)
> +		blob_sizes.lbs_inode = sizeof(struct rcu_head);
> +	lsm_set_blob_size(&blobs->lbs_inode, &blob_sizes.lbs_inode);
> +	lsm_set_blob_size(&blobs->lbs_ipc, &blob_sizes.lbs_ipc);
> +	lsm_set_blob_size(&blobs->lbs_key, &blob_sizes.lbs_key);
> +	lsm_set_blob_size(&blobs->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
> +	lsm_set_blob_size(&blobs->lbs_perf_event, &blob_sizes.lbs_perf_event);
> +	lsm_set_blob_size(&blobs->lbs_sock, &blob_sizes.lbs_sock);
> +	lsm_set_blob_size(&blobs->lbs_superblock, &blob_sizes.lbs_superblock);
> +	lsm_set_blob_size(&blobs->lbs_task, &blob_sizes.lbs_task);
> +	lsm_set_blob_size(&blobs->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
> +	lsm_set_blob_size(&blobs->lbs_xattr_count,
> +			  &blob_sizes.lbs_xattr_count);
> +	lsm_set_blob_size(&blobs->lbs_bdev, &blob_sizes.lbs_bdev);

Another refactoring idea I saw recently from the sysctl subsystem was
turning these named "same things" into an array with enum names, so
instead of &blobs->lbs_ipc, &blobs->lbs_key, they can still have useful
names but also be iterated in a loop:

enum lsm_blob_types {
	LSM_BLOB_IPC,
	LSM_BLOB_KEY,
	...
	LSM_BLOB_MAX
};
...
	for (i = 0; i < ARRAY_SIZE(blobs->lbs); i++) {
		lsm_set_blob_size(&blobs->lbs[i], &blob_sizes[i]);

>  }
>  
>  /* Initialize a given LSM, if it is enabled. */
> @@ -358,7 +341,7 @@ static void __init ordered_lsm_init(void)
>  		ordered_lsm_parse(builtin_lsm_order, "builtin");
>  
>  	for (lsm = ordered_lsms; *lsm; lsm++)
> -		prepare_lsm(*lsm);
> +		lsm_prep_single(*lsm);
>  
>  	report_lsm_order();
>  
> @@ -499,7 +482,7 @@ int __init early_security_init(void)
>  	for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
>  		if (!lsm->enabled)
>  			lsm->enabled = &lsm_enabled_true;
> -		prepare_lsm(lsm);
> +		lsm_prep_single(lsm);
>  		initialize_lsm(lsm);
>  	}

Regardless, this looks correct to me. With or without renaming the
function:

Reviewed-by: Kees Cook <kees@kernel.org>

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 07/29] lsm: rework lsm_active_cnt and lsm_idlist[]
  2025-04-09 18:49 ` [RFC PATCH 07/29] lsm: rework lsm_active_cnt and lsm_idlist[] Paul Moore
@ 2025-04-09 21:38   ` Casey Schaufler
  2025-04-10 21:58     ` Paul Moore
  2025-04-09 23:06   ` Kees Cook
  1 sibling, 1 reply; 126+ messages in thread
From: Casey Schaufler @ 2025-04-09 21:38 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Tetsuo Handa, Casey Schaufler

On 4/9/2025 11:49 AM, Paul Moore wrote:
> Move the LSM count and lsm_id list declarations out of a header that is
> visible across the kernel and into a header that is limited to the LSM
> framework.  This not only helps keep the include/linux headers smaller
> and cleaner, it helps prevent misuse of these variables.
>
> During the move, lsm_active_cnt was renamed to lsm_count for the sake
> of brevity.

lsm_count could be mistaken to be the number of LSMs compiled in
as opposed to the number that are active. Hence lsm_active_cnt.

>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
>  include/linux/security.h | 2 --
>  security/lsm.h           | 5 +++++
>  security/lsm_init.c      | 8 +-------
>  security/lsm_syscalls.c  | 8 +++++---
>  security/security.c      | 3 +++
>  5 files changed, 14 insertions(+), 12 deletions(-)
>
> diff --git a/include/linux/security.h b/include/linux/security.h
> index cc9b54d95d22..8aac21787a9f 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -167,8 +167,6 @@ struct lsm_prop {
>  };
>  
>  extern const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1];
> -extern u32 lsm_active_cnt;
> -extern const struct lsm_id *lsm_idlist[];
>  
>  /* These functions are in security/commoncap.c */
>  extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
> diff --git a/security/lsm.h b/security/lsm.h
> index 0e1731bad4a7..af343072199d 100644
> --- a/security/lsm.h
> +++ b/security/lsm.h
> @@ -7,6 +7,11 @@
>  #define _LSM_H_
>  
>  #include <linux/lsm_hooks.h>
> +#include <linux/lsm_count.h>
> +
> +/* List of configured LSMs */
> +extern unsigned int lsm_count;
> +extern const struct lsm_id *lsm_idlist[];
>  
>  /* LSM blob configuration */
>  extern struct lsm_blob_sizes blob_sizes;
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index edf2f4140eaa..981ddb20f48e 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -22,8 +22,8 @@ static __initdata const char *lsm_order_cmdline;
>  static __initdata const char *lsm_order_legacy;
>  
>  /* Ordered list of LSMs to initialize. */
> -static __initdata struct lsm_info *lsm_order[MAX_LSM_COUNT + 1];
>  static __initdata struct lsm_info *lsm_exclusive;
> +static __initdata struct lsm_info *lsm_order[MAX_LSM_COUNT + 1];
>  
>  static __initdata bool debug;
>  #define init_debug(...)							\
> @@ -211,12 +211,6 @@ static void __init initialize_lsm(struct lsm_info *lsm)
>  	}
>  }
>  
> -/*
> - * Current index to use while initializing the lsm id list.
> - */
> -u32 lsm_active_cnt __ro_after_init;
> -const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
> -
>  /* Populate ordered LSMs list from comma-separated LSM name list. */
>  static void __init ordered_lsm_parse(const char *order, const char *origin)
>  {
> diff --git a/security/lsm_syscalls.c b/security/lsm_syscalls.c
> index 8440948a690c..3fb0d77ae65c 100644
> --- a/security/lsm_syscalls.c
> +++ b/security/lsm_syscalls.c
> @@ -17,6 +17,8 @@
>  #include <linux/lsm_hooks.h>
>  #include <uapi/linux/lsm.h>
>  
> +#include "lsm.h"
> +
>  /**
>   * lsm_name_to_attr - map an LSM attribute name to its ID
>   * @name: name of the attribute
> @@ -96,7 +98,7 @@ SYSCALL_DEFINE4(lsm_get_self_attr, unsigned int, attr, struct lsm_ctx __user *,
>  SYSCALL_DEFINE3(lsm_list_modules, u64 __user *, ids, u32 __user *, size,
>  		u32, flags)
>  {
> -	u32 total_size = lsm_active_cnt * sizeof(*ids);
> +	u32 total_size = lsm_count * sizeof(*ids);
>  	u32 usize;
>  	int i;
>  
> @@ -112,9 +114,9 @@ SYSCALL_DEFINE3(lsm_list_modules, u64 __user *, ids, u32 __user *, size,
>  	if (usize < total_size)
>  		return -E2BIG;
>  
> -	for (i = 0; i < lsm_active_cnt; i++)
> +	for (i = 0; i < lsm_count; i++)
>  		if (put_user(lsm_idlist[i]->id, ids++))
>  			return -EFAULT;
>  
> -	return lsm_active_cnt;
> +	return lsm_count;
>  }
> diff --git a/security/security.c b/security/security.c
> index 8d370a4c5e74..a3e8dd640b39 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -73,6 +73,9 @@ const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX + 1] = {
>  	[LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality",
>  };
>  
> +unsigned int lsm_count __ro_after_init;
> +const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
> +
>  struct lsm_blob_sizes blob_sizes;
>  
>  struct kmem_cache *lsm_file_cache;

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 04/29] lsm: simplify ordered_lsm_init() and rename to lsm_init_ordered()
  2025-04-09 18:49 ` [RFC PATCH 04/29] lsm: simplify ordered_lsm_init() and rename to lsm_init_ordered() Paul Moore
@ 2025-04-09 21:38   ` Kees Cook
  2025-04-09 22:31     ` Paul Moore
  0 siblings, 1 reply; 126+ messages in thread
From: Kees Cook @ 2025-04-09 21:38 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 09, 2025 at 02:49:49PM -0400, Paul Moore wrote:
> One part of a larger effort to cleanup the LSM framework initialization
> code.

Again, needs a better commit log.

> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
>  security/lsm_init.c | 94 +++++++++++++++++----------------------------
>  1 file changed, 36 insertions(+), 58 deletions(-)
> 
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index dffa8dc2da36..407429688f1b 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -32,6 +32,12 @@ static __initdata bool debug;
>  			pr_info(__VA_ARGS__);				\
>  	} while (0)
>  
> +#define lsm_order_for_each(iter)					\
> +	for ((iter) = ordered_lsms; *(iter); (iter)++)
> +#define lsm_early_for_each_raw(iter)					\
> +	for ((iter) = __start_early_lsm_info;				\
> +	     (iter) < __end_early_lsm_info; (iter)++)

The longer I look at this patch the longer I think it needs to be broken
up into a few separate patches, but they would be relatively small, like
this one: replace iter loops with iter macros.

> +
>  static int lsm_append(const char *new, char **result);
>  
>  /* Save user chosen LSM */
> @@ -96,9 +102,10 @@ static bool __init exists_ordered_lsm(struct lsm_info *lsm)
>  {
>  	struct lsm_info **check;
>  
> -	for (check = ordered_lsms; *check; check++)
> +	lsm_order_for_each(check) {
>  		if (*check == lsm)
>  			return true;
> +	}
>  
>  	return false;
>  }
> @@ -279,56 +286,13 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
>  	kfree(sep);
>  }
>  
> -static void __init report_lsm_order(void)
> -{
> -	struct lsm_info **lsm, *early;
> -	int first = 0;
> -
> -	pr_info("initializing lsm=");
> -
> -	/* Report each enabled LSM name, comma separated. */
> -	for (early = __start_early_lsm_info;
> -	     early < __end_early_lsm_info; early++)
> -		if (is_enabled(early))
> -			pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
> -	for (lsm = ordered_lsms; *lsm; lsm++)
> -		if (is_enabled(*lsm))
> -			pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
> -
> -	pr_cont("\n");
> -}
> -
>  /**
> - * lsm_early_cred - during initialization allocate a composite cred blob
> - * @cred: the cred that needs a blob
> - *
> - * Allocate the cred blob for all the modules
> + * lsm_init_ordered - Initialize the ordered LSMs
>   */
> -static void __init lsm_early_cred(struct cred *cred)
> -{
> -	int rc = lsm_cred_alloc(cred, GFP_KERNEL);
> -
> -	if (rc)
> -		panic("%s: Early cred alloc failed.\n", __func__);
> -}
> -
> -/**
> - * lsm_early_task - during initialization allocate a composite task blob
> - * @task: the task that needs a blob
> - *
> - * Allocate the task blob for all the modules
> - */
> -static void __init lsm_early_task(struct task_struct *task)
> -{
> -	int rc = lsm_task_alloc(task);
> -
> -	if (rc)
> -		panic("%s: Early task alloc failed.\n", __func__);
> -}
> -
> -static void __init ordered_lsm_init(void)
> +static void __init lsm_init_ordered(void)
>  {
>  	struct lsm_info **lsm;
> +	struct lsm_info *early;
>  
>  	if (chosen_lsm_order) {
>  		if (chosen_major_lsm) {
> @@ -340,10 +304,23 @@ static void __init ordered_lsm_init(void)
>  	} else
>  		ordered_lsm_parse(builtin_lsm_order, "builtin");
>  
> -	for (lsm = ordered_lsms; *lsm; lsm++)
> +	lsm_order_for_each(lsm) {
>  		lsm_prep_single(*lsm);
> +	}
>  
> -	report_lsm_order();
> +	pr_info("initializing lsm=");
> +	lsm_early_for_each_raw(early) {
> +		if (is_enabled(early))
> +			pr_cont("%s%s",
> +				early == __start_early_lsm_info ? "" : ",",
> +				early->name);
> +	}
> +	lsm_order_for_each(lsm) {
> +		if (is_enabled(*lsm))
> +			pr_cont("%s%s",
> +				lsm == ordered_lsms ? "" : ",", (*lsm)->name);
> +	}

report_lsm_order()'s use of "first" needs to stay here or you don't get
the right comma/no-comma behavior. It's not about the lsm, it's about
whether "first" got incremented. Perhaps "count" might be a better name
for "first".

> +	pr_cont("\n");
>  
>  	init_debug("cred blob size       = %d\n", blob_sizes.lbs_cred);
>  	init_debug("file blob size       = %d\n", blob_sizes.lbs_file);
> @@ -362,9 +339,6 @@ static void __init ordered_lsm_init(void)
>  	init_debug("xattr slots          = %d\n", blob_sizes.lbs_xattr_count);
>  	init_debug("bdev blob size       = %d\n", blob_sizes.lbs_bdev);
>  
> -	/*
> -	 * Create any kmem_caches needed for blobs
> -	 */
>  	if (blob_sizes.lbs_file)
>  		lsm_file_cache = kmem_cache_create("lsm_file_cache",
>  						   blob_sizes.lbs_file, 0,
> @@ -374,10 +348,14 @@ static void __init ordered_lsm_init(void)
>  						    blob_sizes.lbs_inode, 0,
>  						    SLAB_PANIC, NULL);
>  
> -	lsm_early_cred((struct cred *) current->cred);
> -	lsm_early_task(current);
> -	for (lsm = ordered_lsms; *lsm; lsm++)
> +	if (lsm_cred_alloc((struct cred *)current->cred, GFP_KERNEL))
> +		panic("%s: early cred alloc failed.\n", __func__);
> +	if (lsm_task_alloc(current))
> +		panic("%s: early task alloc failed.\n", __func__);
> +
> +	lsm_order_for_each(lsm) {
>  		initialize_lsm(*lsm);
> +	}
>  }
>  
>  static bool match_last_lsm(const char *list, const char *lsm)
> @@ -479,7 +457,7 @@ int __init early_security_init(void)
>  {
>  	struct lsm_info *lsm;
>  
> -	for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
> +	lsm_early_for_each_raw(lsm) {
>  		if (!lsm->enabled)
>  			lsm->enabled = &lsm_enabled_true;
>  		lsm_prep_single(lsm);
> @@ -506,7 +484,7 @@ int __init security_init(void)
>  	 * Append the names of the early LSM modules now that kmalloc() is
>  	 * available
>  	 */
> -	for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
> +	lsm_early_for_each_raw(lsm) {
>  		init_debug("  early started: %s (%s)\n", lsm->name,
>  			   is_enabled(lsm) ? "enabled" : "disabled");
>  		if (lsm->enabled)
> @@ -514,7 +492,7 @@ int __init security_init(void)
>  	}
>  
>  	/* Load LSMs in specified order. */
> -	ordered_lsm_init();
> +	lsm_init_ordered();
>  
>  	return 0;
>  }
> -- 
> 2.49.0
> 

Other stuff seems good.

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 05/29] lsm: replace the name field with a pointer to the lsm_id struct
  2025-04-09 18:49 ` [RFC PATCH 05/29] lsm: replace the name field with a pointer to the lsm_id struct Paul Moore
@ 2025-04-09 21:40   ` Kees Cook
  2025-04-15 22:20   ` John Johansen
  1 sibling, 0 replies; 126+ messages in thread
From: Kees Cook @ 2025-04-09 21:40 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 09, 2025 at 02:49:50PM -0400, Paul Moore wrote:
> Reduce the duplication between the lsm_id struct and the DEFINE_LSM()
> definition by linking the lsm_id struct directly into the individual
> LSM's DEFINE_LSM() instance.
> 
> Linking the lsm_id into the LSM definition also allows us to simplify
> the security_add_hooks() function by removing the code which populates
> the lsm_idlist[] array and moving it into the normal LSM startup code
> where the LSM list is parsed and the individual LSMs are enabled,
> making for a cleaner implementation with less overhead at boot.
> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>

Love it! Much cleaner.

Reviewed-by: Kees Cook <kees@kernel.org>

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 03/29] lsm: simplify prepare_lsm() and rename to lsm_prep_single()
  2025-04-09 21:30   ` Kees Cook
@ 2025-04-09 21:54     ` Paul Moore
  0 siblings, 0 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 21:54 UTC (permalink / raw)
  To: Kees Cook
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 9, 2025 at 5:30 PM Kees Cook <kees@kernel.org> wrote:
> On Wed, Apr 09, 2025 at 02:49:48PM -0400, Paul Moore wrote:
> > One part of a larger effort to cleanup the LSM framework initialization
> > code.
>
> This commit log needs improvement. i.e. explain what and why:

Yeah, it's bad, see the cover letter, the commit descriptions were
explicitly mentioned as needing improvement.  You'll likely see a few
other patches with let's just say "less than good" commit
descriptions.  I basically go through and add/edit/fix-up commit
descriptions while things are compiling, tests are running, etc. and
with the number of patches in this patchset I didn't make enough
passes through the list to get beyond some generic text in a lot of
the patches.

I simply wanted to get this patchset out as a RFC as it had been
mentioned to a few people offline and I wanted to get some feedback
from the individual LSM maintainers who might be affected by moving
the initcalls out of the individual LSMs and into the framework.

> The execution flow through lsm_allowed(), prepare_lsm(), and
> lsm_set_blob_sizes() is a bit convoluted. Merge the logic of all three
> into a single new function, lsm_prep_single().
>
> >
> > Signed-off-by: Paul Moore <paul@paul-moore.com>
> > ---
> >  security/lsm_init.c | 103 ++++++++++++++++++--------------------------
> >  1 file changed, 43 insertions(+), 60 deletions(-)

...

> > @@ -151,51 +135,50 @@ static void __init lsm_set_blob_size(int *need, int *lbs)
> >       *need = offset;
> >  }
> >
> > -static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
> > +/**
> > + * lsm_prep_single - Prepare the LSM framework for a new LSM
> > + * @lsm: LSM definition
> > + */
> > +static void __init lsm_prep_single(struct lsm_info *lsm)
>
> Nit-pick on naming: why shorten "prepare"?

My fingers are lazy?

> > +     /* Register the LSM blob sizes. */
> > +     blobs = lsm->blobs;
> > +     lsm_set_blob_size(&blobs->lbs_cred, &blob_sizes.lbs_cred);
> > +     lsm_set_blob_size(&blobs->lbs_file, &blob_sizes.lbs_file);
> > +     lsm_set_blob_size(&blobs->lbs_ib, &blob_sizes.lbs_ib);
> > +     /* inode blob gets an rcu_head in addition to LSM blobs. */
> > +     if (blobs->lbs_inode && blob_sizes.lbs_inode == 0)
> > +             blob_sizes.lbs_inode = sizeof(struct rcu_head);
> > +     lsm_set_blob_size(&blobs->lbs_inode, &blob_sizes.lbs_inode);
> > +     lsm_set_blob_size(&blobs->lbs_ipc, &blob_sizes.lbs_ipc);
> > +     lsm_set_blob_size(&blobs->lbs_key, &blob_sizes.lbs_key);
> > +     lsm_set_blob_size(&blobs->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
> > +     lsm_set_blob_size(&blobs->lbs_perf_event, &blob_sizes.lbs_perf_event);
> > +     lsm_set_blob_size(&blobs->lbs_sock, &blob_sizes.lbs_sock);
> > +     lsm_set_blob_size(&blobs->lbs_superblock, &blob_sizes.lbs_superblock);
> > +     lsm_set_blob_size(&blobs->lbs_task, &blob_sizes.lbs_task);
> > +     lsm_set_blob_size(&blobs->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
> > +     lsm_set_blob_size(&blobs->lbs_xattr_count,
> > +                       &blob_sizes.lbs_xattr_count);
> > +     lsm_set_blob_size(&blobs->lbs_bdev, &blob_sizes.lbs_bdev);
>
> Another refactoring idea I saw recently from the sysctl subsystem was
> turning these named "same things" into an array with enum names, so
> instead of &blobs->lbs_ipc, &blobs->lbs_key, they can still have useful
> names but also be iterated in a loop:
>
> enum lsm_blob_types {
>         LSM_BLOB_IPC,
>         LSM_BLOB_KEY,
>         ...
>         LSM_BLOB_MAX
> };
> ...
>         for (i = 0; i < ARRAY_SIZE(blobs->lbs); i++) {
>                 lsm_set_blob_size(&blobs->lbs[i], &blob_sizes[i]);

Cool idea, but let's leave that as future work since it is going to
start stretching across security.c for the allocators (and in xattr
count stuff) and this patchset is already more expansive than I would
like.

> > @@ -499,7 +482,7 @@ int __init early_security_init(void)
> >       for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
> >               if (!lsm->enabled)
> >                       lsm->enabled = &lsm_enabled_true;
> > -             prepare_lsm(lsm);
> > +             lsm_prep_single(lsm);
> >               initialize_lsm(lsm);
> >       }
>
> Regardless, this looks correct to me. With or without renaming the
> function:

Thanks, I appreciate the review.

> Reviewed-by: Kees Cook <kees@kernel.org>
>
> --
> Kees Cook

--
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 04/29] lsm: simplify ordered_lsm_init() and rename to lsm_init_ordered()
  2025-04-09 21:38   ` Kees Cook
@ 2025-04-09 22:31     ` Paul Moore
  0 siblings, 0 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-09 22:31 UTC (permalink / raw)
  To: Kees Cook
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 9, 2025 at 5:38 PM Kees Cook <kees@kernel.org> wrote:
>
> On Wed, Apr 09, 2025 at 02:49:49PM -0400, Paul Moore wrote:
> > One part of a larger effort to cleanup the LSM framework initialization
> > code.
>
> Again, needs a better commit log.

See my previous comments as well as the cover letter for the reason why.

> > diff --git a/security/lsm_init.c b/security/lsm_init.c
> > index dffa8dc2da36..407429688f1b 100644
> > --- a/security/lsm_init.c
> > +++ b/security/lsm_init.c
> > @@ -32,6 +32,12 @@ static __initdata bool debug;
> >                       pr_info(__VA_ARGS__);                           \
> >       } while (0)
> >
> > +#define lsm_order_for_each(iter)                                     \
> > +     for ((iter) = ordered_lsms; *(iter); (iter)++)
> > +#define lsm_early_for_each_raw(iter)                                 \
> > +     for ((iter) = __start_early_lsm_info;                           \
> > +          (iter) < __end_early_lsm_info; (iter)++)
>
> The longer I look at this patch the longer I think it needs to be broken
> up into a few separate patches, but they would be relatively small, like
> this one: replace iter loops with iter macros.

Fair point, done.

> > @@ -340,10 +304,23 @@ static void __init ordered_lsm_init(void)
> >       } else
> >               ordered_lsm_parse(builtin_lsm_order, "builtin");
> >
> > -     for (lsm = ordered_lsms; *lsm; lsm++)
> > +     lsm_order_for_each(lsm) {
> >               lsm_prep_single(*lsm);
> > +     }
> >
> > -     report_lsm_order();
> > +     pr_info("initializing lsm=");
> > +     lsm_early_for_each_raw(early) {
> > +             if (is_enabled(early))
> > +                     pr_cont("%s%s",
> > +                             early == __start_early_lsm_info ? "" : ",",
> > +                             early->name);
> > +     }
> > +     lsm_order_for_each(lsm) {
> > +             if (is_enabled(*lsm))
> > +                     pr_cont("%s%s",
> > +                             lsm == ordered_lsms ? "" : ",", (*lsm)->name);
> > +     }
>
> report_lsm_order()'s use of "first" needs to stay here or you don't get
> the right comma/no-comma behavior. It's not about the lsm, it's about
> whether "first" got incremented. Perhaps "count" might be a better name
> for "first".

Sure, I'll just put the "first" code back, it all gets changed later
in the patchset anyway, no need to worry about long term stuff in this
snippet.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 06/29] lsm: cleanup and normalize the LSM order symbols naming
  2025-04-09 18:49 ` [RFC PATCH 06/29] lsm: cleanup and normalize the LSM order symbols naming Paul Moore
@ 2025-04-09 23:00   ` Kees Cook
  2025-04-15 22:23   ` John Johansen
  1 sibling, 0 replies; 126+ messages in thread
From: Kees Cook @ 2025-04-09 23:00 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 09, 2025 at 02:49:51PM -0400, Paul Moore wrote:
> One part of a larger effort to cleanup the LSM framework initialization
> code.
> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>

Sure, seems fine. With a commit log listed what was renamed (and what
noun/adjective/verb ordering was chosen):

Reviewed-by: Kees Cook <kees@kernel.org>

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 07/29] lsm: rework lsm_active_cnt and lsm_idlist[]
  2025-04-09 18:49 ` [RFC PATCH 07/29] lsm: rework lsm_active_cnt and lsm_idlist[] Paul Moore
  2025-04-09 21:38   ` Casey Schaufler
@ 2025-04-09 23:06   ` Kees Cook
  2025-04-10 22:04     ` Paul Moore
  1 sibling, 1 reply; 126+ messages in thread
From: Kees Cook @ 2025-04-09 23:06 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 09, 2025 at 02:49:52PM -0400, Paul Moore wrote:
> Move the LSM count and lsm_id list declarations out of a header that is
> visible across the kernel and into a header that is limited to the LSM
> framework.  This not only helps keep the include/linux headers smaller
> and cleaner, it helps prevent misuse of these variables.

Yay for private headers!

> During the move, lsm_active_cnt was renamed to lsm_count for the sake
> of brevity.

I would echo Casey's comment. Other places deal with a count based on
the compile-in count of "all" LSMs. This one is for the active list.
If you really want two words, perhaps "lsms_active"?


> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
>  include/linux/security.h | 2 --
>  security/lsm.h           | 5 +++++
>  security/lsm_init.c      | 8 +-------
>  security/lsm_syscalls.c  | 8 +++++---
>  security/security.c      | 3 +++
>  5 files changed, 14 insertions(+), 12 deletions(-)
> 
> diff --git a/include/linux/security.h b/include/linux/security.h
> index cc9b54d95d22..8aac21787a9f 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -167,8 +167,6 @@ struct lsm_prop {
>  };
>  
>  extern const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1];
> -extern u32 lsm_active_cnt;
> -extern const struct lsm_id *lsm_idlist[];
>  
>  /* These functions are in security/commoncap.c */
>  extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
> diff --git a/security/lsm.h b/security/lsm.h
> index 0e1731bad4a7..af343072199d 100644
> --- a/security/lsm.h
> +++ b/security/lsm.h
> @@ -7,6 +7,11 @@
>  #define _LSM_H_
>  
>  #include <linux/lsm_hooks.h>
> +#include <linux/lsm_count.h>
> +
> +/* List of configured LSMs */
> +extern unsigned int lsm_count;
> +extern const struct lsm_id *lsm_idlist[];
>  
>  /* LSM blob configuration */
>  extern struct lsm_blob_sizes blob_sizes;
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index edf2f4140eaa..981ddb20f48e 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -22,8 +22,8 @@ static __initdata const char *lsm_order_cmdline;
>  static __initdata const char *lsm_order_legacy;
>  
>  /* Ordered list of LSMs to initialize. */
> -static __initdata struct lsm_info *lsm_order[MAX_LSM_COUNT + 1];
>  static __initdata struct lsm_info *lsm_exclusive;
> +static __initdata struct lsm_info *lsm_order[MAX_LSM_COUNT + 1];

I don't care either way, but why re-order these? Just local reverse
xmas-tree?

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 08/29] lsm: get rid of the lsm_names list and do some cleanup
  2025-04-09 18:49 ` [RFC PATCH 08/29] lsm: get rid of the lsm_names list and do some cleanup Paul Moore
@ 2025-04-09 23:13   ` Kees Cook
  2025-04-10 22:47     ` Paul Moore
  2025-05-22 21:26   ` Casey Schaufler
  1 sibling, 1 reply; 126+ messages in thread
From: Kees Cook @ 2025-04-09 23:13 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 09, 2025 at 02:49:53PM -0400, Paul Moore wrote:
> The LSM currently has a lot of code to maintain a list of the
> currently active LSMs in a human readable string, with the only
> user being the "/sys/kernel/security/lsm" code.  Let's drop all
> of that code and generate the string on an as-needed basis when
> userspace reads "/sys/kernel/security/lsm".
> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
>  include/linux/lsm_hooks.h |  1 -
>  security/inode.c          | 27 +++++++++++++++++++--
>  security/lsm_init.c       | 49 ---------------------------------------
>  3 files changed, 25 insertions(+), 52 deletions(-)
> 
> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
> index 4cd17c9a229f..bc477fb20d02 100644
> --- a/include/linux/lsm_hooks.h
> +++ b/include/linux/lsm_hooks.h
> @@ -169,7 +169,6 @@ struct lsm_info {
>  
>  
>  /* DO NOT tamper with these variables outside of the LSM framework */
> -extern char *lsm_names;
>  extern struct lsm_static_calls_table static_calls_table __ro_after_init;
>  
>  /**
> diff --git a/security/inode.c b/security/inode.c
> index da3ab44c8e57..49bc3578bd23 100644
> --- a/security/inode.c
> +++ b/security/inode.c
> @@ -22,6 +22,8 @@
>  #include <linux/lsm_hooks.h>
>  #include <linux/magic.h>
>  
> +#include "lsm.h"
> +
>  static struct vfsmount *mount;
>  static int mount_count;
>  
> @@ -343,8 +345,29 @@ static struct dentry *lsm_dentry;
>  static ssize_t lsm_read(struct file *filp, char __user *buf, size_t count,
>  			loff_t *ppos)
>  {
> -	return simple_read_from_buffer(buf, count, ppos, lsm_names,
> -		strlen(lsm_names));
> +	int i;
> +	char *str;
> +	ssize_t rc, len = 0;
> +
> +	for (i = 0; i < lsm_count; i++)
> +		/* the '+ 1' accounts for either a comma or a NUL terminator */
> +		len += strlen(lsm_order[i]->id->name) + 1;
> +
> +	str = kmalloc(len, GFP_KERNEL);
> +	if (!str)
> +		return -ENOMEM;
> +	str[0] = '\0';
> +
> +	i = 0;
> +	while (i < lsm_count) {
> +		strcat(str, lsm_order[i]->id->name);
> +		if (++i < lsm_count)
> +			strcat(str, ",");
> +	}
> +
> +	rc = simple_read_from_buffer(buf, count, ppos, str, len);
> +	kfree(str);
> +	return rc;

Hrm, at least cache it?

static char *lsm_names;
static ssize_t lsm_names_len;

static ssize_t lsm_read(struct file *filp, char __user *buf, size_t count,
			loff_t *ppos)
{
	if (!lsm_names) {
		int i;
		char *str;
		ssize_t len = 0;
		...
		lsm_names = str;
	}

	return simple_read_from_buffer(buf, count, ppos, lsm_names, lsm_names_len);
}

Better yet, do this whole thing in a initcall after LSMs are loaded, and
both can gain __ro_after_init...

>  
>  static const struct file_operations lsm_ops = {
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 981ddb20f48e..978bb81b58fa 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -10,8 +10,6 @@
>  
>  #include "lsm.h"
>  
> -char *lsm_names;
> -
>  /* Pointers to LSM sections defined in include/asm-generic/vmlinux.lds.h */
>  extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
>  extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
> @@ -363,42 +361,6 @@ static void __init lsm_init_ordered(void)
>  	}
>  }
>  
> -static bool match_last_lsm(const char *list, const char *lsm)
> -{
> -	const char *last;
> -
> -	if (WARN_ON(!list || !lsm))
> -		return false;
> -	last = strrchr(list, ',');
> -	if (last)
> -		/* Pass the comma, strcmp() will check for '\0' */
> -		last++;
> -	else
> -		last = list;
> -	return !strcmp(last, lsm);
> -}
> -
> -static int lsm_append(const char *new, char **result)
> -{
> -	char *cp;
> -
> -	if (*result == NULL) {
> -		*result = kstrdup(new, GFP_KERNEL);
> -		if (*result == NULL)
> -			return -ENOMEM;
> -	} else {
> -		/* Check if it is the last registered name */
> -		if (match_last_lsm(*result, new))
> -			return 0;
> -		cp = kasprintf(GFP_KERNEL, "%s,%s", *result, new);
> -		if (cp == NULL)
> -			return -ENOMEM;
> -		kfree(*result);
> -		*result = cp;
> -	}
> -	return 0;
> -}
> -
>  static void __init lsm_static_call_init(struct security_hook_list *hl)
>  {
>  	struct lsm_static_call *scall = hl->scalls;
> @@ -435,15 +397,6 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
>  		hooks[i].lsmid = lsmid;
>  		lsm_static_call_init(&hooks[i]);
>  	}
> -
> -	/*
> -	 * Don't try to append during early_security_init(), we'll come back
> -	 * and fix this up afterwards.
> -	 */
> -	if (slab_is_available()) {
> -		if (lsm_append(lsmid->name, &lsm_names) < 0)
> -			panic("%s - Cannot get early memory.\n", __func__);
> -	}
>  }
>  
>  int __init early_security_init(void)
> @@ -480,8 +433,6 @@ int __init security_init(void)
>  	lsm_early_for_each_raw(lsm) {
>  		init_debug("  early started: %s (%s)\n", lsm->id->name,
>  			   is_enabled(lsm) ? "enabled" : "disabled");
> -		if (lsm->enabled)
> -			lsm_append(lsm->id->name, &lsm_names);
>  	}
>  
>  	/* Load LSMs in specified order. */
> -- 
> 2.49.0
> 

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 10/29] lsm: cleanup the LSM blob size code
  2025-04-09 18:49 ` [RFC PATCH 10/29] lsm: cleanup the LSM blob size code Paul Moore
@ 2025-04-09 23:29   ` Kees Cook
  2025-04-15 23:02   ` John Johansen
  2025-04-19  2:42   ` Fan Wu
  2 siblings, 0 replies; 126+ messages in thread
From: Kees Cook @ 2025-04-09 23:29 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 09, 2025 at 02:49:55PM -0400, Paul Moore wrote:
> Convert the lsm_blob_size fields to unsigned integers as there is no
> current need for them to be negative, change "lsm_set_blob_size()" to
> "lsm_blob_size_update()" to better reflect reality, and perform some
> other minor cleanups to the associated code.
> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>

Seems okay.

Reviewed-by: Kees Cook <kees@kernel.org>

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 11/29] lsm: cleanup initialize_lsm() and rename to lsm_init_single()
  2025-04-09 18:49 ` [RFC PATCH 11/29] lsm: cleanup initialize_lsm() and rename to lsm_init_single() Paul Moore
@ 2025-04-09 23:30   ` Kees Cook
  2025-04-15 23:04   ` John Johansen
  1 sibling, 0 replies; 126+ messages in thread
From: Kees Cook @ 2025-04-09 23:30 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 09, 2025 at 02:49:56PM -0400, Paul Moore wrote:
> One part of a larger effort to cleanup the LSM framework initialization
> code.
> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>

Yup, better structure for "exit on fail" instead of indented normal code
flow. :)

Reviewed-by: Kees Cook <kees@kernel.org>

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 18/29] loadpin: move initcalls to the LSM framework
  2025-04-09 18:50 ` [RFC PATCH 18/29] loadpin: move initcalls to " Paul Moore
@ 2025-04-09 23:39   ` Kees Cook
  2025-04-11  1:15     ` Paul Moore
  2025-05-14 11:57   ` John Johansen
  1 sibling, 1 reply; 126+ messages in thread
From: Kees Cook @ 2025-04-09 23:39 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 09, 2025 at 02:50:03PM -0400, Paul Moore wrote:
> Signed-off-by: Paul Moore <paul@paul-moore.com>

Reviewed-by: Kees Cook <kees@kernel.org>

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 19/29] ipe: move initcalls to the LSM framework
  2025-04-09 18:50 ` [RFC PATCH 19/29] ipe: " Paul Moore
@ 2025-04-09 23:40   ` Kees Cook
  2025-04-14 21:19   ` Fan Wu
  2025-05-14 12:02   ` John Johansen
  2 siblings, 0 replies; 126+ messages in thread
From: Kees Cook @ 2025-04-09 23:40 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 09, 2025 at 02:50:04PM -0400, Paul Moore wrote:
> Signed-off-by: Paul Moore <paul@paul-moore.com>

Reviewed-by: Kees Cook <kees@kernel.org>

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 20/29] smack: move initcalls to the LSM framework
  2025-04-09 18:50 ` [RFC PATCH 20/29] smack: " Paul Moore
@ 2025-04-09 23:42   ` Kees Cook
  2025-04-11  2:30     ` Paul Moore
  2025-04-10 17:30   ` Casey Schaufler
  2025-04-14 21:04   ` Fan Wu
  2 siblings, 1 reply; 126+ messages in thread
From: Kees Cook @ 2025-04-09 23:42 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 09, 2025 at 02:50:05PM -0400, Paul Moore wrote:
> As the LSM framework only supports one LSM initcall callback for each
> initcall type, the init_smk_fs() and smack_nf_ip_init() functions were
> wrapped with a new function, smack_initcall() that is registered with
> the LSM framework.
> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
>  security/smack/smack.h           |  6 ++++++
>  security/smack/smack_lsm.c       | 16 ++++++++++++++++
>  security/smack/smack_netfilter.c |  4 +---
>  security/smack/smackfs.c         |  4 +---
>  4 files changed, 24 insertions(+), 6 deletions(-)
> 
> diff --git a/security/smack/smack.h b/security/smack/smack.h
> index bf6a6ed3946c..709e0d6cd5e1 100644
> --- a/security/smack/smack.h
> +++ b/security/smack/smack.h
> @@ -275,6 +275,12 @@ struct smk_audit_info {
>  #endif
>  };
>  
> +/*
> + * Initialization
> + */
> +int init_smk_fs(void);
> +int smack_nf_ip_init(void);
> +
>  /*
>   * These functions are in smack_access.c
>   */
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index e09b33fed5f0..80b129a0c92c 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -5277,6 +5277,21 @@ static __init int smack_init(void)
>  	return 0;
>  }
>  
> +static int smack_initcall(void)
> +{
> +	int rc, rc_tmp;
> +
> +	rc_tmp = init_smk_fs();
> +	if (rc_tmp)
> +		rc = rc_tmp;
> +
> +	rc_tmp = smack_nf_ip_init();
> +	if (!rc && rc_tmp)
> +		rc = rc_tmp;
> +
> +	return rc;
> +}

This retains the existing behavior, but I think it'd be better to
evaluate if the init_smk_fs() call can be tied to the fs init hook
instead, yes? Then no new helper is needed, etc.

-Kees

> +
>  /*
>   * Smack requires early initialization in order to label
>   * all processes and objects when they are created.
> @@ -5286,4 +5301,5 @@ DEFINE_LSM(smack) = {
>  	.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
>  	.blobs = &smack_blob_sizes,
>  	.init = smack_init,
> +	.initcall_device = smack_initcall,
>  };
> diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c
> index 8fd747b3653a..17ba578b1308 100644
> --- a/security/smack/smack_netfilter.c
> +++ b/security/smack/smack_netfilter.c
> @@ -68,7 +68,7 @@ static struct pernet_operations smack_net_ops = {
>  	.exit = smack_nf_unregister,
>  };
>  
> -static int __init smack_nf_ip_init(void)
> +int __init smack_nf_ip_init(void)
>  {
>  	if (smack_enabled == 0)
>  		return 0;
> @@ -76,5 +76,3 @@ static int __init smack_nf_ip_init(void)
>  	printk(KERN_DEBUG "Smack: Registering netfilter hooks\n");
>  	return register_pernet_subsys(&smack_net_ops);
>  }
> -
> -__initcall(smack_nf_ip_init);
> diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
> index 90a67e410808..d33dd0368807 100644
> --- a/security/smack/smackfs.c
> +++ b/security/smack/smackfs.c
> @@ -2980,7 +2980,7 @@ static struct vfsmount *smackfs_mount;
>   * Returns true if we were not chosen on boot or if
>   * we were chosen and filesystem registration succeeded.
>   */
> -static int __init init_smk_fs(void)
> +int __init init_smk_fs(void)
>  {
>  	int err;
>  	int rc;
> @@ -3023,5 +3023,3 @@ static int __init init_smk_fs(void)
>  
>  	return err;
>  }
> -
> -__initcall(init_smk_fs);
> -- 
> 2.49.0
> 

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 21/29] tomoyo: move initcalls to the LSM framework
  2025-04-09 18:50 ` [RFC PATCH 21/29] tomoyo: " Paul Moore
@ 2025-04-09 23:43   ` Kees Cook
  2025-05-14 12:05   ` John Johansen
  1 sibling, 0 replies; 126+ messages in thread
From: Kees Cook @ 2025-04-09 23:43 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 09, 2025 at 02:50:06PM -0400, Paul Moore wrote:
> Signed-off-by: Paul Moore <paul@paul-moore.com>

Reviewed-by: Kees Cook <kees@kernel.org>

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 22/29] safesetid: move initcalls to the LSM framework
  2025-04-09 18:50 ` [RFC PATCH 22/29] safesetid: " Paul Moore
@ 2025-04-09 23:43   ` Kees Cook
  2025-04-11 19:20     ` Micah Morton
  2025-05-14 12:18   ` John Johansen
  1 sibling, 1 reply; 126+ messages in thread
From: Kees Cook @ 2025-04-09 23:43 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 09, 2025 at 02:50:07PM -0400, Paul Moore wrote:
> Signed-off-by: Paul Moore <paul@paul-moore.com>

Reviewed-by: Kees Cook <kees@kernel.org>

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 23/29] apparmor: move initcalls to the LSM framework
  2025-04-09 18:50 ` [RFC PATCH 23/29] apparmor: " Paul Moore
@ 2025-04-09 23:44   ` Kees Cook
  2025-05-14 13:33   ` John Johansen
  1 sibling, 0 replies; 126+ messages in thread
From: Kees Cook @ 2025-04-09 23:44 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 09, 2025 at 02:50:08PM -0400, Paul Moore wrote:
> Signed-off-by: Paul Moore <paul@paul-moore.com>

Reviewed-by: Kees Cook <kees@kernel.org>

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 24/29] lockdown: move initcalls to the LSM framework
  2025-04-09 18:50 ` [RFC PATCH 24/29] lockdown: " Paul Moore
@ 2025-04-09 23:44   ` Kees Cook
  2025-05-14 13:31   ` John Johansen
  1 sibling, 0 replies; 126+ messages in thread
From: Kees Cook @ 2025-04-09 23:44 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 09, 2025 at 02:50:09PM -0400, Paul Moore wrote:
> Signed-off-by: Paul Moore <paul@paul-moore.com>

Reviewed-by: Kees Cook <kees@kernel.org>

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 27/29] lsm: consolidate all of the LSM framework initcalls
  2025-04-09 18:50 ` [RFC PATCH 27/29] lsm: consolidate all of the LSM framework initcalls Paul Moore
@ 2025-04-09 23:52   ` Kees Cook
  2025-04-11  1:21     ` Paul Moore
  2025-05-14 13:38   ` John Johansen
  1 sibling, 1 reply; 126+ messages in thread
From: Kees Cook @ 2025-04-09 23:52 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 09, 2025 at 02:50:12PM -0400, Paul Moore wrote:
> The LSM framework itself registers a small number of initcalls, this
> patch converts these initcalls into the new initcall mechanism.
> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
>  security/inode.c    |  3 +--
>  security/lsm.h      |  4 ++++
>  security/lsm_init.c | 14 ++++++++++++--
>  security/min_addr.c |  5 +++--
>  4 files changed, 20 insertions(+), 6 deletions(-)
> 
> diff --git a/security/inode.c b/security/inode.c
> index f687e22e6809..671c66c147bc 100644
> --- a/security/inode.c
> +++ b/security/inode.c
> @@ -375,7 +375,7 @@ static const struct file_operations lsm_ops = {
>  };
>  #endif
>  
> -static int __init securityfs_init(void)
> +int __init securityfs_init(void)
>  {
>  	int retval;
>  
> @@ -394,4 +394,3 @@ static int __init securityfs_init(void)
>  #endif
>  	return 0;
>  }
> -core_initcall(securityfs_init);
> diff --git a/security/lsm.h b/security/lsm.h
> index 8ecb66896646..c432dc0c5e30 100644
> --- a/security/lsm.h
> +++ b/security/lsm.h
> @@ -35,4 +35,8 @@ extern struct kmem_cache *lsm_inode_cache;
>  int lsm_cred_alloc(struct cred *cred, gfp_t gfp);
>  int lsm_task_alloc(struct task_struct *task);
>  
> +/* LSM framework initializers */
> +int securityfs_init(void);
> +int min_addr_init(void);
> +
>  #endif /* _LSM_H_ */
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 75eb0cc82869..c0881407ca3f 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -485,7 +485,12 @@ int __init security_init(void)
>   */
>  static int __init security_initcall_pure(void)
>  {
> -	return lsm_initcall(pure);
> +	int rc_adr, rc_lsm;
> +
> +	rc_adr = min_addr_init();
> +	rc_lsm = lsm_initcall(pure);
> +
> +	return (rc_adr ? rc_adr : rc_lsm);
>  }
>  pure_initcall(security_initcall_pure);
>  
> @@ -503,7 +508,12 @@ early_initcall(security_initcall_early);
>   */
>  static int __init security_initcall_core(void)
>  {
> -	return lsm_initcall(core);
> +	int rc_sfs, rc_lsm;
> +
> +	rc_sfs = securityfs_init();
> +	rc_lsm = lsm_initcall(core);
> +
> +	return (rc_sfs ? rc_sfs : rc_lsm);
>  }
>  core_initcall(security_initcall_core);

Hrm. Given these aren't really _lsm_ hooks, maybe just leave this out. I
worry about confusing the lsm inits with the lsm subsystem's core inits.
Or we need a new stacking type for "required"? But that seems ... heavy.

-Kees

>  
> diff --git a/security/min_addr.c b/security/min_addr.c
> index df1bc643d886..40714bdeefbe 100644
> --- a/security/min_addr.c
> +++ b/security/min_addr.c
> @@ -4,6 +4,8 @@
>  #include <linux/security.h>
>  #include <linux/sysctl.h>
>  
> +#include "lsm.h"
> +
>  /* amount of vm to protect from userspace access by both DAC and the LSM*/
>  unsigned long mmap_min_addr;
>  /* amount of vm to protect from userspace using CAP_SYS_RAWIO (DAC) */
> @@ -54,11 +56,10 @@ static const struct ctl_table min_addr_sysctl_table[] = {
>  	},
>  };
>  
> -static int __init init_mmap_min_addr(void)
> +int __init min_addr_init(void)
>  {
>  	register_sysctl_init("vm", min_addr_sysctl_table);
>  	update_mmap_min_addr();
>  
>  	return 0;
>  }
> -pure_initcall(init_mmap_min_addr);
> -- 
> 2.49.0
> 

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 28/29] lsm: add a LSM_STARTED_ALL notification event
  2025-04-09 18:50 ` [RFC PATCH 28/29] lsm: add a LSM_STARTED_ALL notification event Paul Moore
@ 2025-04-09 23:53   ` Kees Cook
  2025-05-14 13:34   ` John Johansen
  1 sibling, 0 replies; 126+ messages in thread
From: Kees Cook @ 2025-04-09 23:53 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 09, 2025 at 02:50:13PM -0400, Paul Moore wrote:
> Add a new LSM notifier event, LSM_STARTED_ALL, which is fired once at
> boot when all of the LSMs have been started.

This is where the lsm_names string could be built too...

Reviewed-by: Kees Cook <kees@kernel.org>


> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
>  include/linux/security.h | 1 +
>  security/lsm_init.c      | 1 +
>  2 files changed, 2 insertions(+)
> 
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 8aac21787a9f..a0ff4fc69375 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -85,6 +85,7 @@ struct timezone;
>  
>  enum lsm_event {
>  	LSM_POLICY_CHANGE,
> +	LSM_STARTED_ALL,
>  };
>  
>  struct dm_verity_digest {
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index c0881407ca3f..cad6d243a2a6 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -553,6 +553,7 @@ static int __init security_initcall_late(void)
>  
>  	rc = lsm_initcall(late);
>  	lsm_pr_dbg("all enabled LSMs fully activated\n");
> +	call_blocking_lsm_notifier(LSM_STARTED_ALL, NULL);
>  
>  	return rc;
>  }
> -- 
> 2.49.0
> 

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 09/29] lsm: cleanup and normalize the LSM enabled functions
  2025-04-09 18:49 ` [RFC PATCH 09/29] lsm: cleanup and normalize the LSM enabled functions Paul Moore
@ 2025-04-10  0:11   ` Kees Cook
  2025-04-11  1:50     ` Paul Moore
  0 siblings, 1 reply; 126+ messages in thread
From: Kees Cook @ 2025-04-10  0:11 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 09, 2025 at 02:49:54PM -0400, Paul Moore wrote:
> One part of a larger effort to cleanup the LSM framework initialization
> code.
> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
>  security/inode.c    |   9 ++--
>  security/lsm_init.c | 110 ++++++++++++++++++++++++--------------------
>  2 files changed, 63 insertions(+), 56 deletions(-)
> 
> diff --git a/security/inode.c b/security/inode.c
> index 49bc3578bd23..f687e22e6809 100644
> --- a/security/inode.c
> +++ b/security/inode.c
> @@ -351,18 +351,17 @@ static ssize_t lsm_read(struct file *filp, char __user *buf, size_t count,
>  
>  	for (i = 0; i < lsm_count; i++)
>  		/* the '+ 1' accounts for either a comma or a NUL terminator */
> -		len += strlen(lsm_order[i]->id->name) + 1;
> +		len += strlen(lsm_idlist[i]->name) + 1;
>  
>  	str = kmalloc(len, GFP_KERNEL);
>  	if (!str)
>  		return -ENOMEM;
>  	str[0] = '\0';
>  
> -	i = 0;
> -	while (i < lsm_count) {
> -		strcat(str, lsm_order[i]->id->name);
> -		if (++i < lsm_count)
> +	for (i = 0; i < lsm_count; i++) {
> +		if (i > 0)
>  			strcat(str, ",");
> +		strcat(str, lsm_idlist[i]->name);
>  	}
>  
>  	rc = simple_read_from_buffer(buf, count, ppos, str, len);

This chunk needs to be folded into the lsm_names changing patch, I
think. I missed this on the first pass, but lsm_order can never be used
here because lsm_order is initdata -- it will be thrown away after init
is done.

> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 978bb81b58fa..7f2bc8c22ce9 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -10,6 +10,10 @@
>  
>  #include "lsm.h"
>  
> +/* LSM enabled constants. */
> +int lsm_enabled_true = 1;
> +int lsm_enabled_false = 0;

Why are these losing static and __initdata? It looks like they're
staying assigned to the __init-marked lsm_info instances.

> +
>  /* Pointers to LSM sections defined in include/asm-generic/vmlinux.lds.h */
>  extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
>  extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
> @@ -72,41 +76,42 @@ static int __init lsm_debug_enable(char *str)
>  }
>  __setup("lsm.debug", lsm_debug_enable);
>  
> -/* Mark an LSM's enabled flag. */
> -static int lsm_enabled_true __initdata = 1;
> -static int lsm_enabled_false __initdata = 0;
> -static void __init set_enabled(struct lsm_info *lsm, bool enabled)
> +/**
> + * lsm_enabled_set - Mark a LSM as enabled
> + * @lsm: LSM definition
> + * @enabled: enabled flag
> + */
> +static void __init lsm_enabled_set(struct lsm_info *lsm, bool enabled)
>  {
>  	/*
>  	 * When an LSM hasn't configured an enable variable, we can use
>  	 * a hard-coded location for storing the default enabled state.
>  	 */
> -	if (!lsm->enabled) {
> -		if (enabled)
> -			lsm->enabled = &lsm_enabled_true;
> -		else
> -			lsm->enabled = &lsm_enabled_false;
> -	} else if (lsm->enabled == &lsm_enabled_true) {
> -		if (!enabled)
> -			lsm->enabled = &lsm_enabled_false;
> -	} else if (lsm->enabled == &lsm_enabled_false) {
> -		if (enabled)
> -			lsm->enabled = &lsm_enabled_true;
> +	if (!lsm->enabled ||
> +	    lsm->enabled == &lsm_enabled_true ||
> +	    lsm->enabled == &lsm_enabled_false) {
> +		lsm->enabled = enabled ? &lsm_enabled_true : &lsm_enabled_false;
>  	} else {
>  		*lsm->enabled = enabled;
>  	}
>  }

Good logic folding.

>  
> -static inline bool is_enabled(struct lsm_info *lsm)
> +/**
> + * lsm_is_enabled - Determine if a LSM is enabled
> + * @lsm: LSM definition
> + */
> +static inline bool lsm_is_enabled(struct lsm_info *lsm)
>  {
>  	if (!lsm->enabled)
>  		return false;
> -
>  	return *lsm->enabled;
>  }

This could be one-lined, actually:

	return lsm->enabled ? *lsm->enabled : false;

>  
> -/* Is an LSM already listed in the ordered LSMs list? */
> -static bool __init exists_ordered_lsm(struct lsm_info *lsm)
> +/**
> + * lsm_order_exists - Determine if a LSM exists in the ordered list
> + * @lsm: LSM definition
> + */
> +static bool __init lsm_order_exists(struct lsm_info *lsm)
>  {
>  	struct lsm_info **check;
>  
> @@ -118,25 +123,29 @@ static bool __init exists_ordered_lsm(struct lsm_info *lsm)
>  	return false;
>  }
>  
> -/* Append an LSM to the list of ordered LSMs to initialize. */
> -static int last_lsm __initdata;
> -static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
> +/**
> + * lsm_order_append - Append a LSM to the ordered list
> + * @lsm: LSM definition
> + * @src: source of the addition
> + */
> +static void __init lsm_order_append(struct lsm_info *lsm, const char *src)
>  {
>  	/* Ignore duplicate selections. */
> -	if (exists_ordered_lsm(lsm))
> +	if (lsm_order_exists(lsm))
>  		return;
>  
> -	if (WARN(last_lsm == MAX_LSM_COUNT, "%s: out of LSM static calls!?\n", from))
> -		return;
> +	/* Skip explicitly disabled LSMs. */
> +	if (lsm->enabled && !lsm_is_enabled(lsm)) {
> +		if (WARN(lsm_count == MAX_LSM_COUNT,
> +			 "%s: out of LSM static calls!?\n", src))
> +			return;
> +		lsm_enabled_set(lsm, true);
> +		lsm_order[lsm_count] = lsm;
> +		lsm_idlist[lsm_count++] = lsm->id;
> +	}
>  
> -	/* Enable this LSM, if it is not already set. */
> -	if (!lsm->enabled)
> -		lsm->enabled = &lsm_enabled_true;
> -	lsm_order[last_lsm] = lsm;
> -	lsm_idlist[last_lsm++] = lsm->id;

I don't understand the logic change here. I may be missing something (it
feels like a lot of logic changes mixed together again), but this logic:

     /* Enable this LSM, if it is not already set. */
     if (!lsm->enabled)
             lsm->enabled = &lsm_enabled_true;

seems like it has gone missing now? And I think the last_lsm/lsm_count
changes need to be in the "lsm: rework lsm_active_cnt and lsm_idlist[]"
patch? I'm really struggling to follow this patch, but maybe I am EOD.
:P


> -
> -	init_debug("%s ordered: %s (%s)\n", from, lsm->id->name,
> -		   is_enabled(lsm) ? "enabled" : "disabled");
> +	init_debug("%s ordered: %s (%s)\n", src, lsm->id->name,
> +		   lsm_is_enabled(lsm) ? "enabled" : "disabled");
>  }
>  
>  static void __init lsm_set_blob_size(int *need, int *lbs)
> @@ -159,17 +168,17 @@ static void __init lsm_prep_single(struct lsm_info *lsm)
>  {
>  	struct lsm_blob_sizes *blobs;
>  
> -	if (!is_enabled(lsm)) {
> -		set_enabled(lsm, false);
> +	if (!lsm_is_enabled(lsm)) {
> +		lsm_enabled_set(lsm, false);
>  		return;
>  	} else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && lsm_exclusive) {
>  		init_debug("exclusive disabled: %s\n", lsm->id->name);
> -		set_enabled(lsm, false);
> +		lsm_enabled_set(lsm, false);
>  		return;
>  	}
>  
>  	/* Mark the LSM as enabled. */
> -	set_enabled(lsm, true);
> +	lsm_enabled_set(lsm, true);
>  	if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !lsm_exclusive) {
>  		init_debug("exclusive chosen:   %s\n", lsm->id->name);
>  		lsm_exclusive = lsm;
> @@ -200,7 +209,7 @@ static void __init lsm_prep_single(struct lsm_info *lsm)
>  /* Initialize a given LSM, if it is enabled. */
>  static void __init initialize_lsm(struct lsm_info *lsm)
>  {
> -	if (is_enabled(lsm)) {
> +	if (lsm_is_enabled(lsm)) {
>  		int ret;
>  
>  		init_debug("initializing %s\n", lsm->id->name);
> @@ -218,7 +227,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
>  	/* LSM_ORDER_FIRST is always first. */
>  	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
>  		if (lsm->order == LSM_ORDER_FIRST)
> -			append_ordered_lsm(lsm, "  first");
> +			lsm_order_append(lsm, "  first");
>  	}
>  
>  	/* Process "security=", if given. */
> @@ -235,7 +244,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
>  		     major++) {
>  			if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
>  			    strcmp(major->id->name, lsm_order_legacy) != 0) {
> -				set_enabled(major, false);
> +				lsm_enabled_set(major, false);
>  				init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
>  					   lsm_order_legacy, major->id->name);
>  			}
> @@ -251,7 +260,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
>  		for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
>  			if (strcmp(lsm->id->name, name) == 0) {
>  				if (lsm->order == LSM_ORDER_MUTABLE)
> -					append_ordered_lsm(lsm, origin);
> +					lsm_order_append(lsm, origin);
>  				found = true;
>  			}
>  		}
> @@ -264,24 +273,24 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
>  	/* Process "security=", if given. */
>  	if (lsm_order_legacy) {
>  		for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
> -			if (exists_ordered_lsm(lsm))
> +			if (lsm_order_exists(lsm))
>  				continue;
>  			if (strcmp(lsm->id->name, lsm_order_legacy) == 0)
> -				append_ordered_lsm(lsm, "security=");
> +				lsm_order_append(lsm, "security=");
>  		}
>  	}
>  
>  	/* LSM_ORDER_LAST is always last. */
>  	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
>  		if (lsm->order == LSM_ORDER_LAST)
> -			append_ordered_lsm(lsm, "   last");
> +			lsm_order_append(lsm, "   last");
>  	}
>  
>  	/* Disable all LSMs not in the ordered list. */
>  	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
> -		if (exists_ordered_lsm(lsm))
> +		if (lsm_order_exists(lsm))
>  			continue;
> -		set_enabled(lsm, false);
> +		lsm_enabled_set(lsm, false);
>  		init_debug("%s skipped: %s (not in requested order)\n",
>  			   origin, lsm->id->name);
>  	}
> @@ -313,13 +322,13 @@ static void __init lsm_init_ordered(void)
>  
>  	pr_info("initializing lsm=");
>  	lsm_early_for_each_raw(early) {
> -		if (is_enabled(early))
> +		if (lsm_is_enabled(early))
>  			pr_cont("%s%s",
>  				early == __start_early_lsm_info ? "" : ",",
>  				early->id->name);
>  	}
>  	lsm_order_for_each(lsm) {
> -		if (is_enabled(*lsm))
> +		if (lsm_is_enabled(*lsm))
>  			pr_cont("%s%s",
>  				lsm == lsm_order ? "" : ",", (*lsm)->id->name);
>  	}
> @@ -404,8 +413,7 @@ int __init early_security_init(void)
>  	struct lsm_info *lsm;
>  
>  	lsm_early_for_each_raw(lsm) {
> -		if (!lsm->enabled)
> -			lsm->enabled = &lsm_enabled_true;
> +		lsm_enabled_set(lsm, true);
>  		lsm_prep_single(lsm);
>  		initialize_lsm(lsm);
>  	}
> @@ -432,7 +440,7 @@ int __init security_init(void)
>  	 */
>  	lsm_early_for_each_raw(lsm) {
>  		init_debug("  early started: %s (%s)\n", lsm->id->name,
> -			   is_enabled(lsm) ? "enabled" : "disabled");
> +			   lsm_is_enabled(lsm) ? "enabled" : "disabled");
>  	}
>  
>  	/* Load LSMs in specified order. */
> -- 
> 2.49.0

The simple renamings looks fine, but would be nicer if they got split
out.

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 0/29] Rework the LSM initialization
  2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
                   ` (28 preceding siblings ...)
  2025-04-09 18:50 ` [RFC PATCH 29/29] lsm: add support for counting lsm_prop support among LSMs Paul Moore
@ 2025-04-10 14:13 ` Casey Schaufler
  2025-04-10 16:31   ` Kees Cook
  2025-04-11  2:28   ` Paul Moore
  29 siblings, 2 replies; 126+ messages in thread
From: Casey Schaufler @ 2025-04-10 14:13 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Tetsuo Handa, Casey Schaufler

On 4/9/2025 11:49 AM, Paul Moore wrote:
> This is one of those patchsets that started out small and then quickly
> expanded to what you see here.  I will warn you that some of the
> individual patches are a bit ugly to look at, but I believe the end
> result is much cleaner than what we have now, fixes some odd/undesirable
> behavior on boot, and enables some new functionality.
>
> The most obvious changes are the extraction of the LSM notifier and
> initialization code out of security/security.c and into their own files,
> security/lsm_notifier.c and security/lsm_init.c.  While not strictly
> necessary, I think we can all agree that security/security.c has grown
> to be a bit of a mess, and these are two bits of functionality which
> can be extracted out into their own files without too much fuss.  I
> personally find this to be a nice quality-of-life improvement, and while
> I'm open to keeping everything in security.c, the argument for doing so
> is going to need to be *very* persuasive.

It's something I've considered doing as part of the stacking work,
but that I have eschewed in the spirit of churn reduction. I've no
problem with it.

> The other significant change is moving all of the LSM initcalls into the
> LSM framework.  While I've always pushed to keep the LSM framework as
> minimal as possible, there are some things that we really can't defer to
> the individual LSMs and with the LSM framework responsible for enabling
> or disabling the individual LSMs at boot, I believe management and
> execution of the LSM initcalls needs to be handled in the framework as
> well.  Not only does this move ensure that we aren't running initcalls
> for LSMs which are disabled, it also provides us with a convenient spot
> to signal when all of the LSMs have been actived (see the LSM_STARTED_ALL
> patch towards the end of the patchset).  This is not a feature we
> currently need, but I'm aware of some future work that does require this
> so I thought it would be good to think about it now while doing this
> work.
>
> Related to the LSM_STARTED_ALL patch, the final patch in this series
> adds support for LSMs to indicate if they provide lsm_prop values for
> subjects and/or objects.  Casey needs this functionality for his recent
> audit changes, and I personally find the counting approach presented
> here to be ... less ugly I guess?

The flags approach works for me. I was going to propose adding a call
audit_lsm_secctx() that LSMs would call to identify that a secctx was
being supported, but I had considered the flag approach as well. As for
ugly, I can't say one way or the other.

> This patchset is marked as a RFC for a number of reasons: additional
> testing is required, the commit descriptions could benefit from some
> extra attention, and I still have hopes that some of the individual
> patches could be cleaned up a bit (I still like the end result, but how
> we get there could be improved).  I would really appreciate if the
> individual LSM maintainers could give this a quick look, especially
> the individual LSM patches that move the initcalls into the LSM
> framework as some of those are non-trivial.

General comments:

Adjacent patches with no more commit message than "cleanup" should
be combined, as that message is telling me "these aren't the changes
you're looking for".

And about that. I believe that missing or uninformative commit messages
are on your list of things that displease you. You will need to improve
them to get them past yourself. :)

There's a lot of churn here due to unnecessary name changes. I can't
say they're unjustified, but the patch set is bigger than it needs to
be, and more disruptive.

I haven't tested it, but I don't see any substantial problems so far.

>   Mimi and Roberto, the
> IMA/EVM work here was particularly "fun"; from what I've seen thus far
> it appears to work correctly, but I have no idea if that code is good
> or bad from you perspective.  It's perfectly okay if you want to
> reject the approach taken in IMA/EVM, but we do need to move the
> initcalls up to the LSM framework, so please suggest some code that
> would allow us to do that for IMA/EVM.
>
> --
> Paul Moore (29):
>       lsm: split the notifier code out into lsm_notifier.c
>       lsm: split the init code out into lsm_init.c
>       lsm: simplify prepare_lsm() and rename to lsm_prep_single()
>       lsm: simplify ordered_lsm_init() and rename to lsm_init_ordered()
>       lsm: replace the name field with a pointer to the lsm_id struct
>       lsm: cleanup and normalize the LSM order symbols naming
>       lsm: rework lsm_active_cnt and lsm_idlist[]
>       lsm: get rid of the lsm_names list and do some cleanup
>       lsm: cleanup and normalize the LSM enabled functions
>       lsm: cleanup the LSM blob size code
>       lsm: cleanup initialize_lsm() and rename to lsm_init_single()
>       lsm: cleanup the LSM ordered parsing
>       lsm: fold lsm_init_ordered() into security_init()
>       lsm: add missing function header comment blocks in lsm_init.c
>       lsm: cleanup the debug and console output in lsm_init.c
>       lsm: output available LSMs when debugging
>       lsm: introduce an initcall mechanism into the LSM framework
>       loadpin: move initcalls to the LSM framework
>       ipe: move initcalls to the LSM framework
>       smack: move initcalls to the LSM framework
>       tomoyo: move initcalls to the LSM framework
>       safesetid: move initcalls to the LSM framework
>       apparmor: move initcalls to the LSM framework
>       lockdown: move initcalls to the LSM framework
>       ima,evm: move initcalls to the LSM framework
>       selinux: move initcalls to the LSM framework
>       lsm: consolidate all of the LSM framework initcalls
>       lsm: add a LSM_STARTED_ALL notification event
>       lsm: add support for counting lsm_prop support among LSMs
>
>  include/linux/lsm_hooks.h                            |   73 -
>  include/linux/security.h                             |    3 
>  security/Makefile                                    |    2 
>  security/apparmor/apparmorfs.c                       |    4 
>  security/apparmor/crypto.c                           |    4 
>  security/apparmor/include/apparmorfs.h               |    2 
>  security/apparmor/include/crypto.h                   |    1 
>  security/apparmor/lsm.c                              |   12 
>  security/bpf/hooks.c                                 |    3 
>  security/commoncap.c                                 |    3 
>  security/inode.c                                     |   29 
>  security/integrity/Makefile                          |    2 
>  security/integrity/evm/evm_main.c                    |   10 
>  security/integrity/iint.c                            |    4 
>  security/integrity/ima/ima_main.c                    |   10 
>  security/integrity/ima/ima_mok.c                     |    4 
>  security/integrity/initcalls.c                       |   97 +
>  security/integrity/initcalls.h                       |   23 
>  security/integrity/platform_certs/load_ipl_s390.c    |    4 
>  security/integrity/platform_certs/load_powerpc.c     |    4 
>  security/integrity/platform_certs/load_uefi.c        |    4 
>  security/integrity/platform_certs/machine_keyring.c  |    4 
>  security/integrity/platform_certs/platform_keyring.c |   14 
>  security/ipe/fs.c                                    |    4 
>  security/ipe/ipe.c                                   |    4 
>  security/ipe/ipe.h                                   |    2 
>  security/landlock/setup.c                            |    3 
>  security/loadpin/loadpin.c                           |   16 
>  security/lockdown/lockdown.c                         |    6 
>  security/lsm.h                                       |   46 
>  security/lsm_init.c                                  |  566 ++++++++++
>  security/lsm_notifier.c                              |   31 
>  security/lsm_syscalls.c                              |    8 
>  security/min_addr.c                                  |    5 
>  security/safesetid/lsm.c                             |    4 
>  security/safesetid/lsm.h                             |    2 
>  security/safesetid/securityfs.c                      |    3 
>  security/security.c                                  |  620 -----------
>  security/selinux/Makefile                            |    2 
>  security/selinux/hooks.c                             |   12 
>  security/selinux/ibpkey.c                            |    5 
>  security/selinux/include/audit.h                     |    5 
>  security/selinux/include/initcalls.h                 |   19 
>  security/selinux/initcalls.c                         |   50 
>  security/selinux/netif.c                             |    5 
>  security/selinux/netlink.c                           |    5 
>  security/selinux/netnode.c                           |    5 
>  security/selinux/netport.c                           |    5 
>  security/selinux/selinuxfs.c                         |    5 
>  security/selinux/ss/services.c                       |   26 
>  security/smack/smack.h                               |    6 
>  security/smack/smack_lsm.c                           |   19 
>  security/smack/smack_netfilter.c                     |    4 
>  security/smack/smackfs.c                             |    4 
>  security/tomoyo/common.h                             |    2 
>  security/tomoyo/securityfs_if.c                      |    4 
>  security/tomoyo/tomoyo.c                             |    4 
>  security/yama/yama_lsm.c                             |    3 
>  58 files changed, 1102 insertions(+), 724 deletions(-)
>

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 0/29] Rework the LSM initialization
  2025-04-10 14:13 ` [RFC PATCH 0/29] Rework the LSM initialization Casey Schaufler
@ 2025-04-10 16:31   ` Kees Cook
  2025-04-11  2:28   ` Paul Moore
  1 sibling, 0 replies; 126+ messages in thread
From: Kees Cook @ 2025-04-10 16:31 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: Paul Moore, linux-security-module, linux-integrity, selinux,
	John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Micah Morton,
	Tetsuo Handa

On Thu, Apr 10, 2025 at 07:13:11AM -0700, Casey Schaufler wrote:
> On 4/9/2025 11:49 AM, Paul Moore wrote:
> > This is one of those patchsets that started out small and then quickly
> > expanded to what you see here.  I will warn you that some of the
> > individual patches are a bit ugly to look at, but I believe the end
> > result is much cleaner than what we have now, fixes some odd/undesirable
> > behavior on boot, and enables some new functionality.
> >
> > The most obvious changes are the extraction of the LSM notifier and
> > initialization code out of security/security.c and into their own files,
> > security/lsm_notifier.c and security/lsm_init.c.  While not strictly
> > necessary, I think we can all agree that security/security.c has grown
> > to be a bit of a mess, and these are two bits of functionality which
> > can be extracted out into their own files without too much fuss.  I
> > personally find this to be a nice quality-of-life improvement, and while
> > I'm open to keeping everything in security.c, the argument for doing so
> > is going to need to be *very* persuasive.
> 
> It's something I've considered doing as part of the stacking work,
> but that I have eschewed in the spirit of churn reduction. I've no
> problem with it.

Yeah, to be clear, I'm a fan of these refactorings. :)

> There's a lot of churn here due to unnecessary name changes. I can't
> say they're unjustified, but the patch set is bigger than it needs to
> be, and more disruptive.

If renamings are desired, sure, let's do it, but I'd love to see them
very distinctly separated from logical changes.

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 26/29] selinux: move initcalls to the LSM framework
  2025-04-09 18:50 ` [RFC PATCH 26/29] selinux: " Paul Moore
@ 2025-04-10 16:33   ` Stephen Smalley
  2025-04-11  3:24     ` Paul Moore
  2025-05-23 15:12   ` Casey Schaufler
  1 sibling, 1 reply; 126+ messages in thread
From: Stephen Smalley @ 2025-04-10 16:33 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On Wed, Apr 9, 2025 at 2:55 PM Paul Moore <paul@paul-moore.com> wrote:
>
> SELinux currently has a number of initcalls so we've created a new
> function, selinux_initcall(), which wraps all of these initcalls so
> that we have a single initcall function that can be registered with the
> LSM framework.
>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---

> diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h
> index d5b0425055e4..5989f8dd1e86 100644
> --- a/security/selinux/include/audit.h
> +++ b/security/selinux/include/audit.h
> @@ -15,6 +15,11 @@
>  #include <linux/audit.h>
>  #include <linux/types.h>
>
> +/**
> + * XXX
> + */

Assuming this will be fixed before merge.

> +int selinux_audit_rule_avc_callback(u32 event);
> +
>  /**
>   * selinux_audit_rule_init - alloc/init an selinux audit rule structure.
>   * @field: the field this rule refers to
> diff --git a/security/selinux/include/initcalls.h b/security/selinux/include/initcalls.h
> new file mode 100644
> index 000000000000..6674cf489473
> --- /dev/null
> +++ b/security/selinux/include/initcalls.h
> @@ -0,0 +1,19 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * SELinux initcalls
> + */
> +
> +#ifndef _SELINUX_INITCALLS_H
> +#define _SELINUX_INITCALLS_H
> +
> +int init_sel_fs(void);
> +int sel_netport_init(void);
> +int sel_netnode_init(void);
> +int sel_netif_init(void);
> +int sel_netlink_init(void);
> +int sel_ib_pkey_init(void);
> +int selinux_nf_ip_init(void);

The last two only exist if certain Kconfig options are set.

> +
> +int selinux_initcall(void);
> +
> +#endif
> diff --git a/security/selinux/initcalls.c b/security/selinux/initcalls.c
> new file mode 100644
> index 000000000000..81f01f8ad215
> --- /dev/null
> +++ b/security/selinux/initcalls.c
> @@ -0,0 +1,50 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * SELinux initcalls
> + */
> +
> +#include <linux/init.h>
> +
> +#include "initcalls.h"
> +
> +/**
> + * selinux_initcall - Perform the SELinux initcalls
> + *
> + * Used as a device initcall in the SELinux LSM definition.
> + */
> +int __init selinux_initcall(void)
> +{
> +       int rc = 0, rc_tmp = 0;
> +
> +       rc_tmp = init_sel_fs();
> +       if (!rc && rc_tmp)
> +               rc = rc_tmp;
> +
> +       rc_tmp = sel_netport_init();
> +       if (!rc && rc_tmp)
> +               rc = rc_tmp;
> +
> +       rc_tmp = sel_netnode_init();
> +       if (!rc && rc_tmp)
> +               rc = rc_tmp;
> +
> +       rc_tmp = sel_netif_init();
> +       if (!rc && rc_tmp)
> +               rc = rc_tmp;
> +
> +       rc_tmp = sel_netlink_init();
> +       if (!rc && rc_tmp)
> +               rc = rc_tmp;
> +
> +       rc_tmp = sel_ib_pkey_init();

This one depends on CONFIG_SECURITY_INFINIBAND.

> +       if (!rc && rc_tmp)
> +               rc = rc_tmp;
> +
> +#if defined(CONFIG_NETFILTER)
> +       rc_tmp = selinux_nf_ip_init();
> +       if (!rc && rc_tmp)
> +               rc = rc_tmp;
> +#endif
> +
> +       return rc;
> +}

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 20/29] smack: move initcalls to the LSM framework
  2025-04-09 18:50 ` [RFC PATCH 20/29] smack: " Paul Moore
  2025-04-09 23:42   ` Kees Cook
@ 2025-04-10 17:30   ` Casey Schaufler
  2025-04-10 17:47     ` Casey Schaufler
  2025-04-11 20:09     ` Paul Moore
  2025-04-14 21:04   ` Fan Wu
  2 siblings, 2 replies; 126+ messages in thread
From: Casey Schaufler @ 2025-04-10 17:30 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Tetsuo Handa, Casey Schaufler

On 4/9/2025 11:50 AM, Paul Moore wrote:
> As the LSM framework only supports one LSM initcall callback for each
> initcall type, the init_smk_fs() and smack_nf_ip_init() functions were
> wrapped with a new function, smack_initcall() that is registered with
> the LSM framework.
>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
>  security/smack/smack.h           |  6 ++++++
>  security/smack/smack_lsm.c       | 16 ++++++++++++++++
>  security/smack/smack_netfilter.c |  4 +---
>  security/smack/smackfs.c         |  4 +---
>  4 files changed, 24 insertions(+), 6 deletions(-)
>
> diff --git a/security/smack/smack.h b/security/smack/smack.h
> index bf6a6ed3946c..709e0d6cd5e1 100644
> --- a/security/smack/smack.h
> +++ b/security/smack/smack.h
> @@ -275,6 +275,12 @@ struct smk_audit_info {
>  #endif
>  };
>  
> +/*
> + * Initialization
> + */
> +int init_smk_fs(void);
> +int smack_nf_ip_init(void);
> +
>  /*
>   * These functions are in smack_access.c
>   */
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index e09b33fed5f0..80b129a0c92c 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -5277,6 +5277,21 @@ static __init int smack_init(void)
>  	return 0;
>  }
>  
> +static int smack_initcall(void)
> +{
> +	int rc, rc_tmp;

separate lines for the declarations please.

> +
> +	rc_tmp = init_smk_fs();
> +	if (rc_tmp)
> +		rc = rc_tmp;

Replace these three lines with:

 +	rc = init_smk_fs();

> +
> +	rc_tmp = smack_nf_ip_init();
> +	if (!rc && rc_tmp)
> +		rc = rc_tmp;

Change this to

 +	rc_tmp = smack_nf_ip_init();
 +	return rc ? rc : rc_tmp;

Also change rc_tmp to rc_nf and rc to rc_fs.

> +
> +	return rc;
> +}
> +

Or:

static int smack_initcall(void)
{
	int rc_fs = init_smk_fs();
	int rc_nf = smack_nf_ip_init();

	return rc_fs ? rc_fs : rc:nf;
}

>  /*
>   * Smack requires early initialization in order to label
>   * all processes and objects when they are created.
> @@ -5286,4 +5301,5 @@ DEFINE_LSM(smack) = {
>  	.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
>  	.blobs = &smack_blob_sizes,
>  	.init = smack_init,
> +	.initcall_device = smack_initcall,
>  };
> diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c
> index 8fd747b3653a..17ba578b1308 100644
> --- a/security/smack/smack_netfilter.c
> +++ b/security/smack/smack_netfilter.c
> @@ -68,7 +68,7 @@ static struct pernet_operations smack_net_ops = {
>  	.exit = smack_nf_unregister,
>  };
>  
> -static int __init smack_nf_ip_init(void)
> +int __init smack_nf_ip_init(void)
>  {
>  	if (smack_enabled == 0)
>  		return 0;
> @@ -76,5 +76,3 @@ static int __init smack_nf_ip_init(void)
>  	printk(KERN_DEBUG "Smack: Registering netfilter hooks\n");
>  	return register_pernet_subsys(&smack_net_ops);
>  }
> -
> -__initcall(smack_nf_ip_init);
> diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
> index 90a67e410808..d33dd0368807 100644
> --- a/security/smack/smackfs.c
> +++ b/security/smack/smackfs.c
> @@ -2980,7 +2980,7 @@ static struct vfsmount *smackfs_mount;
>   * Returns true if we were not chosen on boot or if
>   * we were chosen and filesystem registration succeeded.
>   */
> -static int __init init_smk_fs(void)
> +int __init init_smk_fs(void)
>  {
>  	int err;
>  	int rc;
> @@ -3023,5 +3023,3 @@ static int __init init_smk_fs(void)
>  
>  	return err;
>  }
> -
> -__initcall(init_smk_fs);

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 20/29] smack: move initcalls to the LSM framework
  2025-04-10 17:30   ` Casey Schaufler
@ 2025-04-10 17:47     ` Casey Schaufler
  2025-04-11 20:09     ` Paul Moore
  1 sibling, 0 replies; 126+ messages in thread
From: Casey Schaufler @ 2025-04-10 17:47 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Tetsuo Handa, Casey Schaufler

On 4/10/2025 10:30 AM, Casey Schaufler wrote:
> On 4/9/2025 11:50 AM, Paul Moore wrote:
>> As the LSM framework only supports one LSM initcall callback for each
>> initcall type, the init_smk_fs() and smack_nf_ip_init() functions were
>> wrapped with a new function, smack_initcall() that is registered with
>> the LSM framework.
>>
>> Signed-off-by: Paul Moore <paul@paul-moore.com>
>> ---
>>  security/smack/smack.h           |  6 ++++++
>>  security/smack/smack_lsm.c       | 16 ++++++++++++++++
>>  security/smack/smack_netfilter.c |  4 +---
>>  security/smack/smackfs.c         |  4 +---
>>  4 files changed, 24 insertions(+), 6 deletions(-)
>>
>> diff --git a/security/smack/smack.h b/security/smack/smack.h
>> index bf6a6ed3946c..709e0d6cd5e1 100644
>> --- a/security/smack/smack.h
>> +++ b/security/smack/smack.h
>> @@ -275,6 +275,12 @@ struct smk_audit_info {
>>  #endif
>>  };
>>  
>> +/*
>> + * Initialization
>> + */
>> +int init_smk_fs(void);
>> +int smack_nf_ip_init(void);
>> +
>>  /*
>>   * These functions are in smack_access.c
>>   */
>> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
>> index e09b33fed5f0..80b129a0c92c 100644
>> --- a/security/smack/smack_lsm.c
>> +++ b/security/smack/smack_lsm.c
>> @@ -5277,6 +5277,21 @@ static __init int smack_init(void)
>>  	return 0;
>>  }
>>  
>> +static int smack_initcall(void)
>> +{
>> +	int rc, rc_tmp;
> separate lines for the declarations please.
>
>> +
>> +	rc_tmp = init_smk_fs();
>> +	if (rc_tmp)
>> +		rc = rc_tmp;
> Replace these three lines with:
>
>  +	rc = init_smk_fs();
>
>> +
>> +	rc_tmp = smack_nf_ip_init();
>> +	if (!rc && rc_tmp)
>> +		rc = rc_tmp;
> Change this to
>
>  +	rc_tmp = smack_nf_ip_init();
>  +	return rc ? rc : rc_tmp;
>
> Also change rc_tmp to rc_nf and rc to rc_fs.
>
>> +
>> +	return rc;
>> +}
>> +
> Or:
>
> static int smack_initcall(void)
> {
> 	int rc_fs = init_smk_fs();
> 	int rc_nf = smack_nf_ip_init();
>
> 	return rc_fs ? rc_fs : rc:nf;

Whoops - return rc_fs ? rc_fs : rc_nf;

> }
>
>>  /*
>>   * Smack requires early initialization in order to label
>>   * all processes and objects when they are created.
>> @@ -5286,4 +5301,5 @@ DEFINE_LSM(smack) = {
>>  	.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
>>  	.blobs = &smack_blob_sizes,
>>  	.init = smack_init,
>> +	.initcall_device = smack_initcall,
>>  };
>> diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c
>> index 8fd747b3653a..17ba578b1308 100644
>> --- a/security/smack/smack_netfilter.c
>> +++ b/security/smack/smack_netfilter.c
>> @@ -68,7 +68,7 @@ static struct pernet_operations smack_net_ops = {
>>  	.exit = smack_nf_unregister,
>>  };
>>  
>> -static int __init smack_nf_ip_init(void)
>> +int __init smack_nf_ip_init(void)
>>  {
>>  	if (smack_enabled == 0)
>>  		return 0;
>> @@ -76,5 +76,3 @@ static int __init smack_nf_ip_init(void)
>>  	printk(KERN_DEBUG "Smack: Registering netfilter hooks\n");
>>  	return register_pernet_subsys(&smack_net_ops);
>>  }
>> -
>> -__initcall(smack_nf_ip_init);
>> diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
>> index 90a67e410808..d33dd0368807 100644
>> --- a/security/smack/smackfs.c
>> +++ b/security/smack/smackfs.c
>> @@ -2980,7 +2980,7 @@ static struct vfsmount *smackfs_mount;
>>   * Returns true if we were not chosen on boot or if
>>   * we were chosen and filesystem registration succeeded.
>>   */
>> -static int __init init_smk_fs(void)
>> +int __init init_smk_fs(void)
>>  {
>>  	int err;
>>  	int rc;
>> @@ -3023,5 +3023,3 @@ static int __init init_smk_fs(void)
>>  
>>  	return err;
>>  }
>> -
>> -__initcall(init_smk_fs);

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 17/29] lsm: introduce an initcall mechanism into the LSM framework
  2025-04-09 21:16   ` Kees Cook
@ 2025-04-10 20:52     ` Paul Moore
  0 siblings, 0 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-10 20:52 UTC (permalink / raw)
  To: Kees Cook
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 9, 2025 at 5:16 PM Kees Cook <kees@kernel.org> wrote:
> On Wed, Apr 09, 2025 at 02:50:02PM -0400, Paul Moore wrote:
> > Currently the individual LSMs register their own initcalls, and while
> > this should be harmless, it can be wasteful in the case where a LSM
> > is disabled at boot as the initcall will still be executed.  This
> > patch introduces support for managing the initcalls in the LSM
> > framework, and future patches will convert the existing LSMs over to
> > this new mechanism.
> >
> > Only initcall types which are used by the current in-tree LSMs are
> > supported, additional initcall types can easily be added in the future
> > if needed.
> >
> > Signed-off-by: Paul Moore <paul@paul-moore.com>
> > ---
> >  include/linux/lsm_hooks.h | 33 ++++++++++++---
> >  security/lsm_init.c       | 89 +++++++++++++++++++++++++++++++++++++++
> >  2 files changed, 117 insertions(+), 5 deletions(-)
> >
> > diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
> > index a7ecb0791a0f..0d2c2a017ffc 100644
> > --- a/include/linux/lsm_hooks.h
> > +++ b/include/linux/lsm_hooks.h
> > @@ -148,13 +148,36 @@ enum lsm_order {
> >       LSM_ORDER_LAST = 1,     /* This is only for integrity. */
> >  };
> >
> > +/**
> > + * struct lsm_info - Define an individual LSM for the LSM framework.
> > + * @id: LSM name/ID info
> > + * @order: ordering with respect to other LSMs, optional
> > + * @flags: descriptive flags, optional
> > + * @blobs: LSM blob sharing, optional
> > + * @enabled: controlled by CONFIG_LSM, optional
> > + * @init: LSM specific initialization routine
> > + * @initcall_pure: LSM callback for initcall_pure() setup, optional
> > + * @initcall_early: LSM callback for early_initcall setup, optional
> > + * @initcall_core: LSM callback for core_initcall() setup, optional
> > + * @initcall_subsys: LSM callback for subsys_initcall() setup, optional
> > + * @initcall_fs: LSM callback for fs_initcall setup, optional
> > + * @nitcall_device: LSM callback for device_initcall() setup, optional
> > + * @initcall_late: LSM callback for late_initcall() setup, optional
> > + */
>
> Yay! Proper kerndoc. :)

 ;)

> > +/**
> > + * security_initcall_late - Run the LSM late initcalls
> > + */
> > +static int __init security_initcall_late(void)
> > +{
> > +     int rc;
> > +
> > +     rc = lsm_initcall(late);
> > +     lsm_pr_dbg("all enabled LSMs fully activated\n");
> > +
> > +     return rc;
> > +}
> > +late_initcall(security_initcall_late);
>
> You'd need a new place for the lsm_pr_dbg, but these are all just
> copy/paste. These could be macro-ified too?

If we didn't want to move the other LSM framework initcalls into these
initcalls (yes, I prefer it this way), or add the LSM_STARTED_ADD
event at the end, I would tend to agree with you.  Let's leave it
as-is for now, if something changes in the future wrt to any of things
above we can revisit this.

I'm also somewhat hopeful that this work will bring attention to the
different initcall types/levels that are in use by various LSMs, I
suspect there are a few LSMs which are currently using multiple
initcall types that could be consolidated into one.  That's not
something I wanted to tackle in this patchset, but if we could reduce
the number of initcall types that we use in the LSM subsystem as a
whole this may not really be an issue of any significance ...

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 07/29] lsm: rework lsm_active_cnt and lsm_idlist[]
  2025-04-09 21:38   ` Casey Schaufler
@ 2025-04-10 21:58     ` Paul Moore
  0 siblings, 0 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-10 21:58 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Tetsuo Handa

On Wed, Apr 9, 2025 at 5:38 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> On 4/9/2025 11:49 AM, Paul Moore wrote:
> > Move the LSM count and lsm_id list declarations out of a header that is
> > visible across the kernel and into a header that is limited to the LSM
> > framework.  This not only helps keep the include/linux headers smaller
> > and cleaner, it helps prevent misuse of these variables.
> >
> > During the move, lsm_active_cnt was renamed to lsm_count for the sake
> > of brevity.
>
> lsm_count could be mistaken to be the number of LSMs compiled in
> as opposed to the number that are active. Hence lsm_active_cnt.

Fair enough, I'll preserve the name.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 07/29] lsm: rework lsm_active_cnt and lsm_idlist[]
  2025-04-09 23:06   ` Kees Cook
@ 2025-04-10 22:04     ` Paul Moore
  2025-04-10 22:25       ` Kees Cook
  0 siblings, 1 reply; 126+ messages in thread
From: Paul Moore @ 2025-04-10 22:04 UTC (permalink / raw)
  To: Kees Cook
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 9, 2025 at 7:06 PM Kees Cook <kees@kernel.org> wrote:
> On Wed, Apr 09, 2025 at 02:49:52PM -0400, Paul Moore wrote:

...

> > diff --git a/security/lsm_init.c b/security/lsm_init.c
> > index edf2f4140eaa..981ddb20f48e 100644
> > --- a/security/lsm_init.c
> > +++ b/security/lsm_init.c
> > @@ -22,8 +22,8 @@ static __initdata const char *lsm_order_cmdline;
> >  static __initdata const char *lsm_order_legacy;
> >
> >  /* Ordered list of LSMs to initialize. */
> > -static __initdata struct lsm_info *lsm_order[MAX_LSM_COUNT + 1];
> >  static __initdata struct lsm_info *lsm_exclusive;
> > +static __initdata struct lsm_info *lsm_order[MAX_LSM_COUNT + 1];
>
> I don't care either way, but why re-order these? Just local reverse
> xmas-tree?

Sure?

Honestly can't say for certain, at this point in the development
process I had somewhat resigned myself to having a mess of a patchset
so I figured this was an opportunity to make it look "nice" (er?) in
my mind, and I suppose at that point that looked better to me ... ?

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 07/29] lsm: rework lsm_active_cnt and lsm_idlist[]
  2025-04-10 22:04     ` Paul Moore
@ 2025-04-10 22:25       ` Kees Cook
  2025-04-11  0:58         ` Casey Schaufler
  0 siblings, 1 reply; 126+ messages in thread
From: Kees Cook @ 2025-04-10 22:25 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Thu, Apr 10, 2025 at 06:04:38PM -0400, Paul Moore wrote:
> On Wed, Apr 9, 2025 at 7:06 PM Kees Cook <kees@kernel.org> wrote:
> > On Wed, Apr 09, 2025 at 02:49:52PM -0400, Paul Moore wrote:
> 
> ...
> 
> > > diff --git a/security/lsm_init.c b/security/lsm_init.c
> > > index edf2f4140eaa..981ddb20f48e 100644
> > > --- a/security/lsm_init.c
> > > +++ b/security/lsm_init.c
> > > @@ -22,8 +22,8 @@ static __initdata const char *lsm_order_cmdline;
> > >  static __initdata const char *lsm_order_legacy;
> > >
> > >  /* Ordered list of LSMs to initialize. */
> > > -static __initdata struct lsm_info *lsm_order[MAX_LSM_COUNT + 1];
> > >  static __initdata struct lsm_info *lsm_exclusive;
> > > +static __initdata struct lsm_info *lsm_order[MAX_LSM_COUNT + 1];
> >
> > I don't care either way, but why re-order these? Just local reverse
> > xmas-tree?
> 
> Sure?
> 
> Honestly can't say for certain, at this point in the development
> process I had somewhat resigned myself to having a mess of a patchset
> so I figured this was an opportunity to make it look "nice" (er?) in
> my mind, and I suppose at that point that looked better to me ... ?

Understood. I think I ordered the original way because I was hopefully
we'd remove "exclusive" soon, and it felt better to remove it from the
end of a list of variables. *shrug* yay code vibes

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 08/29] lsm: get rid of the lsm_names list and do some cleanup
  2025-04-09 23:13   ` Kees Cook
@ 2025-04-10 22:47     ` Paul Moore
  2025-04-11  2:15       ` Kees Cook
  2025-04-15 22:30       ` John Johansen
  0 siblings, 2 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-10 22:47 UTC (permalink / raw)
  To: Kees Cook
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 9, 2025 at 7:13 PM Kees Cook <kees@kernel.org> wrote:
>
> On Wed, Apr 09, 2025 at 02:49:53PM -0400, Paul Moore wrote:
> > The LSM currently has a lot of code to maintain a list of the
> > currently active LSMs in a human readable string, with the only
> > user being the "/sys/kernel/security/lsm" code.  Let's drop all
> > of that code and generate the string on an as-needed basis when
> > userspace reads "/sys/kernel/security/lsm".
> >
> > Signed-off-by: Paul Moore <paul@paul-moore.com>
> > ---
> >  include/linux/lsm_hooks.h |  1 -
> >  security/inode.c          | 27 +++++++++++++++++++--
> >  security/lsm_init.c       | 49 ---------------------------------------
> >  3 files changed, 25 insertions(+), 52 deletions(-)

...

> > @@ -343,8 +345,29 @@ static struct dentry *lsm_dentry;
> >  static ssize_t lsm_read(struct file *filp, char __user *buf, size_t count,
> >                       loff_t *ppos)
> >  {
> > -     return simple_read_from_buffer(buf, count, ppos, lsm_names,
> > -             strlen(lsm_names));
> > +     int i;
> > +     char *str;
> > +     ssize_t rc, len = 0;
> > +
> > +     for (i = 0; i < lsm_count; i++)
> > +             /* the '+ 1' accounts for either a comma or a NUL terminator */
> > +             len += strlen(lsm_order[i]->id->name) + 1;
> > +
> > +     str = kmalloc(len, GFP_KERNEL);
> > +     if (!str)
> > +             return -ENOMEM;
> > +     str[0] = '\0';
> > +
> > +     i = 0;
> > +     while (i < lsm_count) {
> > +             strcat(str, lsm_order[i]->id->name);
> > +             if (++i < lsm_count)
> > +                     strcat(str, ",");
> > +     }
> > +
> > +     rc = simple_read_from_buffer(buf, count, ppos, str, len);
> > +     kfree(str);
> > +     return rc;
>
> Hrm, at least cache it?

Are you aware of a performance critical use of this?

> Better yet, do this whole thing in a initcall after LSMs are loaded, and
> both can gain __ro_after_init...

I *really* disliked all the stuff we were having to do during boot,
and all the redundant global state we were keeping around.  I'll go
ahead and cache the lsm_read() result local to the function but that's
probably all I'm going to accept at this point in time.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 07/29] lsm: rework lsm_active_cnt and lsm_idlist[]
  2025-04-10 22:25       ` Kees Cook
@ 2025-04-11  0:58         ` Casey Schaufler
  0 siblings, 0 replies; 126+ messages in thread
From: Casey Schaufler @ 2025-04-11  0:58 UTC (permalink / raw)
  To: Kees Cook, Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Tetsuo Handa, Casey Schaufler

On 4/10/2025 3:25 PM, Kees Cook wrote:
> On Thu, Apr 10, 2025 at 06:04:38PM -0400, Paul Moore wrote:
>> On Wed, Apr 9, 2025 at 7:06 PM Kees Cook <kees@kernel.org> wrote:
>>> On Wed, Apr 09, 2025 at 02:49:52PM -0400, Paul Moore wrote:
>> ...
>>
>>>> diff --git a/security/lsm_init.c b/security/lsm_init.c
>>>> index edf2f4140eaa..981ddb20f48e 100644
>>>> --- a/security/lsm_init.c
>>>> +++ b/security/lsm_init.c
>>>> @@ -22,8 +22,8 @@ static __initdata const char *lsm_order_cmdline;
>>>>  static __initdata const char *lsm_order_legacy;
>>>>
>>>>  /* Ordered list of LSMs to initialize. */
>>>> -static __initdata struct lsm_info *lsm_order[MAX_LSM_COUNT + 1];
>>>>  static __initdata struct lsm_info *lsm_exclusive;
>>>> +static __initdata struct lsm_info *lsm_order[MAX_LSM_COUNT + 1];
>>> I don't care either way, but why re-order these? Just local reverse
>>> xmas-tree?
>> Sure?
>>
>> Honestly can't say for certain, at this point in the development
>> process I had somewhat resigned myself to having a mess of a patchset
>> so I figured this was an opportunity to make it look "nice" (er?) in
>> my mind, and I suppose at that point that looked better to me ... ?
> Understood. I think I ordered the original way because I was hopefully
> we'd remove "exclusive" soon,

In the pipeline. Small values of "soon".

>  and it felt better to remove it from the
> end of a list of variables. *shrug* yay code vibes
>

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 18/29] loadpin: move initcalls to the LSM framework
  2025-04-09 23:39   ` Kees Cook
@ 2025-04-11  1:15     ` Paul Moore
  2025-04-11  2:16       ` Kees Cook
  0 siblings, 1 reply; 126+ messages in thread
From: Paul Moore @ 2025-04-11  1:15 UTC (permalink / raw)
  To: Kees Cook
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 9, 2025 at 7:39 PM Kees Cook <kees@kernel.org> wrote:
> On Wed, Apr 09, 2025 at 02:50:03PM -0400, Paul Moore wrote:
> > Signed-off-by: Paul Moore <paul@paul-moore.com>
>
> Reviewed-by: Kees Cook <kees@kernel.org>

Do you mind if I convert this into an Acked-by?  Generally speaking I
put more weight behind a Reviewed-by tag, but in the case of Loadpin
you are the maintainer and I'd much prefer an Acked-by.  While I'm
always happy to get more reviews on a patch, the primary reason for
CC'ing you directly was to get ACKs on the LSMs you maintain :)

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 27/29] lsm: consolidate all of the LSM framework initcalls
  2025-04-09 23:52   ` Kees Cook
@ 2025-04-11  1:21     ` Paul Moore
  2025-04-11  2:16       ` Kees Cook
  0 siblings, 1 reply; 126+ messages in thread
From: Paul Moore @ 2025-04-11  1:21 UTC (permalink / raw)
  To: Kees Cook
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 9, 2025 at 7:52 PM Kees Cook <kees@kernel.org> wrote:
> On Wed, Apr 09, 2025 at 02:50:12PM -0400, Paul Moore wrote:
> > The LSM framework itself registers a small number of initcalls, this
> > patch converts these initcalls into the new initcall mechanism.
> >
> > Signed-off-by: Paul Moore <paul@paul-moore.com>
> > ---
> >  security/inode.c    |  3 +--
> >  security/lsm.h      |  4 ++++
> >  security/lsm_init.c | 14 ++++++++++++--
> >  security/min_addr.c |  5 +++--
> >  4 files changed, 20 insertions(+), 6 deletions(-)

...

> > @@ -503,7 +508,12 @@ early_initcall(security_initcall_early);
> >   */
> >  static int __init security_initcall_core(void)
> >  {
> > -     return lsm_initcall(core);
> > +     int rc_sfs, rc_lsm;
> > +
> > +     rc_sfs = securityfs_init();
> > +     rc_lsm = lsm_initcall(core);
> > +
> > +     return (rc_sfs ? rc_sfs : rc_lsm);
> >  }
> >  core_initcall(security_initcall_core);
>
> Hrm. Given these aren't really _lsm_ hooks, maybe just leave this out. I
> worry about confusing the lsm inits with the lsm subsystem's core inits.

I'm not too concerned about that, and I do prefer it this way.

> Or we need a new stacking type for "required"? But that seems ... heavy.

So I understand the motivation behind that, but that's a big hard "no"
from me at this point in time ;)

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 09/29] lsm: cleanup and normalize the LSM enabled functions
  2025-04-10  0:11   ` Kees Cook
@ 2025-04-11  1:50     ` Paul Moore
  2025-04-11  2:03       ` Paul Moore
  2025-04-11  2:14       ` Paul Moore
  0 siblings, 2 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-11  1:50 UTC (permalink / raw)
  To: Kees Cook
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 9, 2025 at 8:11 PM Kees Cook <kees@kernel.org> wrote:
> On Wed, Apr 09, 2025 at 02:49:54PM -0400, Paul Moore wrote:
> > One part of a larger effort to cleanup the LSM framework initialization
> > code.
> >
> > Signed-off-by: Paul Moore <paul@paul-moore.com>
> > ---
> >  security/inode.c    |   9 ++--
> >  security/lsm_init.c | 110 ++++++++++++++++++++++++--------------------
> >  2 files changed, 63 insertions(+), 56 deletions(-)
> >
> > diff --git a/security/inode.c b/security/inode.c
> > index 49bc3578bd23..f687e22e6809 100644
> > --- a/security/inode.c
> > +++ b/security/inode.c
> > @@ -351,18 +351,17 @@ static ssize_t lsm_read(struct file *filp, char __user *buf, size_t count,
> >
> >       for (i = 0; i < lsm_count; i++)
> >               /* the '+ 1' accounts for either a comma or a NUL terminator */
> > -             len += strlen(lsm_order[i]->id->name) + 1;
> > +             len += strlen(lsm_idlist[i]->name) + 1;
> >
> >       str = kmalloc(len, GFP_KERNEL);
> >       if (!str)
> >               return -ENOMEM;
> >       str[0] = '\0';
> >
> > -     i = 0;
> > -     while (i < lsm_count) {
> > -             strcat(str, lsm_order[i]->id->name);
> > -             if (++i < lsm_count)
> > +     for (i = 0; i < lsm_count; i++) {
> > +             if (i > 0)
> >                       strcat(str, ",");
> > +             strcat(str, lsm_idlist[i]->name);
> >       }
> >
> >       rc = simple_read_from_buffer(buf, count, ppos, str, len);
>
> This chunk needs to be folded into the lsm_names changing patch, I
> think. I missed this on the first pass, but lsm_order can never be used
> here because lsm_order is initdata -- it will be thrown away after init
> is done.

Yeah, I noticed this when I was reverting that
/lsm_active_cnt/lsm_count/ change and fixed it up to use lsm_idlist[]
which should address that problem.  Later patches convert over to
lsm_idlist[] anyway, which is likely why I didn't catch this in the
preliminary testing.

> > diff --git a/security/lsm_init.c b/security/lsm_init.c
> > index 978bb81b58fa..7f2bc8c22ce9 100644
> > --- a/security/lsm_init.c
> > +++ b/security/lsm_init.c
> > @@ -10,6 +10,10 @@
> >
> >  #include "lsm.h"
> >
> > +/* LSM enabled constants. */
> > +int lsm_enabled_true = 1;
> > +int lsm_enabled_false = 0;
>
> Why are these losing static and __initdata? It looks like they're
> staying assigned to the __init-marked lsm_info instances.

Good point.  I'm not sure what happened here, it may have been a
victim of an earlier change which I dropped.

> > +/**
> > + * lsm_is_enabled - Determine if a LSM is enabled
> > + * @lsm: LSM definition
> > + */
> > +static inline bool lsm_is_enabled(struct lsm_info *lsm)
> >  {
> >       if (!lsm->enabled)
> >               return false;
> > -
> >       return *lsm->enabled;
> >  }
>
> This could be one-lined, actually:
>
>         return lsm->enabled ? *lsm->enabled : false;

Sure.

> > -/* Is an LSM already listed in the ordered LSMs list? */
> > -static bool __init exists_ordered_lsm(struct lsm_info *lsm)
> > +/**
> > + * lsm_order_exists - Determine if a LSM exists in the ordered list
> > + * @lsm: LSM definition
> > + */
> > +static bool __init lsm_order_exists(struct lsm_info *lsm)
> >  {
> >       struct lsm_info **check;
> >
> > @@ -118,25 +123,29 @@ static bool __init exists_ordered_lsm(struct lsm_info *lsm)
> >       return false;
> >  }
> >
> > -/* Append an LSM to the list of ordered LSMs to initialize. */
> > -static int last_lsm __initdata;
> > -static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
> > +/**
> > + * lsm_order_append - Append a LSM to the ordered list
> > + * @lsm: LSM definition
> > + * @src: source of the addition
> > + */
> > +static void __init lsm_order_append(struct lsm_info *lsm, const char *src)
> >  {
> >       /* Ignore duplicate selections. */
> > -     if (exists_ordered_lsm(lsm))
> > +     if (lsm_order_exists(lsm))
> >               return;
> >
> > -     if (WARN(last_lsm == MAX_LSM_COUNT, "%s: out of LSM static calls!?\n", from))
> > -             return;
> > +     /* Skip explicitly disabled LSMs. */
> > +     if (lsm->enabled && !lsm_is_enabled(lsm)) {
> > +             if (WARN(lsm_count == MAX_LSM_COUNT,
> > +                      "%s: out of LSM static calls!?\n", src))
> > +                     return;
> > +             lsm_enabled_set(lsm, true);
> > +             lsm_order[lsm_count] = lsm;
> > +             lsm_idlist[lsm_count++] = lsm->id;
> > +     }
> >
> > -     /* Enable this LSM, if it is not already set. */
> > -     if (!lsm->enabled)
> > -             lsm->enabled = &lsm_enabled_true;
> > -     lsm_order[last_lsm] = lsm;
> > -     lsm_idlist[last_lsm++] = lsm->id;
>
> I don't understand the logic change here. I may be missing something (it
> feels like a lot of logic changes mixed together again), but this logic:
>
>      /* Enable this LSM, if it is not already set. */
>      if (!lsm->enabled)
>              lsm->enabled = &lsm_enabled_true;
>
> seems like it has gone missing now?

It's a little confusing as lsm_order_append() gets heavily reworked a
couple of patches later in "lsm: cleanup the LSM ordered parsing",
which is essentially this function's end state from a logic
perspective.  I think the best thing to do might be to squash those
two patches ... lemme see how ugly that ends up ...

> The simple renamings looks fine, but would be nicer if they got split
> out.

I can look into doing that, let me try the squashing first.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 09/29] lsm: cleanup and normalize the LSM enabled functions
  2025-04-11  1:50     ` Paul Moore
@ 2025-04-11  2:03       ` Paul Moore
  2025-04-11  2:14       ` Paul Moore
  1 sibling, 0 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-11  2:03 UTC (permalink / raw)
  To: Kees Cook
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Thu, Apr 10, 2025 at 9:50 PM Paul Moore <paul@paul-moore.com> wrote:
> On Wed, Apr 9, 2025 at 8:11 PM Kees Cook <kees@kernel.org> wrote:
> > On Wed, Apr 09, 2025 at 02:49:54PM -0400, Paul Moore wrote:

...

> > > -/* Append an LSM to the list of ordered LSMs to initialize. */
> > > -static int last_lsm __initdata;
> > > -static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
> > > +/**
> > > + * lsm_order_append - Append a LSM to the ordered list
> > > + * @lsm: LSM definition
> > > + * @src: source of the addition
> > > + */
> > > +static void __init lsm_order_append(struct lsm_info *lsm, const char *src)
> > >  {
> > >       /* Ignore duplicate selections. */
> > > -     if (exists_ordered_lsm(lsm))
> > > +     if (lsm_order_exists(lsm))
> > >               return;
> > >
> > > -     if (WARN(last_lsm == MAX_LSM_COUNT, "%s: out of LSM static calls!?\n", from))
> > > -             return;
> > > +     /* Skip explicitly disabled LSMs. */
> > > +     if (lsm->enabled && !lsm_is_enabled(lsm)) {
> > > +             if (WARN(lsm_count == MAX_LSM_COUNT,
> > > +                      "%s: out of LSM static calls!?\n", src))
> > > +                     return;
> > > +             lsm_enabled_set(lsm, true);
> > > +             lsm_order[lsm_count] = lsm;
> > > +             lsm_idlist[lsm_count++] = lsm->id;
> > > +     }
> > >
> > > -     /* Enable this LSM, if it is not already set. */
> > > -     if (!lsm->enabled)
> > > -             lsm->enabled = &lsm_enabled_true;
> > > -     lsm_order[last_lsm] = lsm;
> > > -     lsm_idlist[last_lsm++] = lsm->id;
> >
> > I don't understand the logic change here. I may be missing something (it
> > feels like a lot of logic changes mixed together again), but this logic:
> >
> >      /* Enable this LSM, if it is not already set. */
> >      if (!lsm->enabled)
> >              lsm->enabled = &lsm_enabled_true;
> >
> > seems like it has gone missing now?
>
> It's a little confusing as lsm_order_append() gets heavily reworked a
> couple of patches later in "lsm: cleanup the LSM ordered parsing",
> which is essentially this function's end state from a logic
> perspective.  I think the best thing to do might be to squash those
> two patches ... lemme see how ugly that ends up ...

Yeah, it looks *way* better now with those two patches squashed.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 09/29] lsm: cleanup and normalize the LSM enabled functions
  2025-04-11  1:50     ` Paul Moore
  2025-04-11  2:03       ` Paul Moore
@ 2025-04-11  2:14       ` Paul Moore
  2025-04-11  2:17         ` Kees Cook
  1 sibling, 1 reply; 126+ messages in thread
From: Paul Moore @ 2025-04-11  2:14 UTC (permalink / raw)
  To: Kees Cook
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Thu, Apr 10, 2025 at 9:50 PM Paul Moore <paul@paul-moore.com> wrote:
> On Wed, Apr 9, 2025 at 8:11 PM Kees Cook <kees@kernel.org> wrote:
> > On Wed, Apr 09, 2025 at 02:49:54PM -0400, Paul Moore wrote:

...

> > The simple renamings looks fine, but would be nicer if they got split
> > out.
>
> I can look into doing that, let me try the squashing first.

... and I pulled out the enabled/disable setter/getter functions into
their own patch.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 08/29] lsm: get rid of the lsm_names list and do some cleanup
  2025-04-10 22:47     ` Paul Moore
@ 2025-04-11  2:15       ` Kees Cook
  2025-04-11  3:14         ` Paul Moore
  2025-04-15 22:30       ` John Johansen
  1 sibling, 1 reply; 126+ messages in thread
From: Kees Cook @ 2025-04-11  2:15 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Thu, Apr 10, 2025 at 06:47:12PM -0400, Paul Moore wrote:
> On Wed, Apr 9, 2025 at 7:13 PM Kees Cook <kees@kernel.org> wrote:
> > Better yet, do this whole thing in a initcall after LSMs are loaded, and
> > both can gain __ro_after_init...
> 
> I *really* disliked all the stuff we were having to do during boot,
> and all the redundant global state we were keeping around.  I'll go
> ahead and cache the lsm_read() result local to the function but that's
> probably all I'm going to accept at this point in time.

Oh, for sure. I love that all that can get thrown away. I mean literally
copy/paste what you have in lsm_read() and stick it immediately before
the "lsms are done loading" notifier. Then it only needs to be done
once, it's impossible to race, etc.

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 18/29] loadpin: move initcalls to the LSM framework
  2025-04-11  1:15     ` Paul Moore
@ 2025-04-11  2:16       ` Kees Cook
  2025-04-11  2:41         ` Paul Moore
  0 siblings, 1 reply; 126+ messages in thread
From: Kees Cook @ 2025-04-11  2:16 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Thu, Apr 10, 2025 at 09:15:47PM -0400, Paul Moore wrote:
> On Wed, Apr 9, 2025 at 7:39 PM Kees Cook <kees@kernel.org> wrote:
> > On Wed, Apr 09, 2025 at 02:50:03PM -0400, Paul Moore wrote:
> > > Signed-off-by: Paul Moore <paul@paul-moore.com>
> >
> > Reviewed-by: Kees Cook <kees@kernel.org>
>
> Do you mind if I convert this into an Acked-by?  Generally speaking I
> put more weight behind a Reviewed-by tag, but in the case of Loadpin
> you are the maintainer and I'd much prefer an Acked-by.  While I'm
> always happy to get more reviews on a patch, the primary reason for
> CC'ing you directly was to get ACKs on the LSMs you maintain :)

Acked-by: Kees Cook <kees@kernel.org>

:)

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 27/29] lsm: consolidate all of the LSM framework initcalls
  2025-04-11  1:21     ` Paul Moore
@ 2025-04-11  2:16       ` Kees Cook
  0 siblings, 0 replies; 126+ messages in thread
From: Kees Cook @ 2025-04-11  2:16 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Thu, Apr 10, 2025 at 09:21:46PM -0400, Paul Moore wrote:
> On Wed, Apr 9, 2025 at 7:52 PM Kees Cook <kees@kernel.org> wrote:
> > On Wed, Apr 09, 2025 at 02:50:12PM -0400, Paul Moore wrote:
> > > The LSM framework itself registers a small number of initcalls, this
> > > patch converts these initcalls into the new initcall mechanism.
> > >
> > > Signed-off-by: Paul Moore <paul@paul-moore.com>
> > > ---
> > >  security/inode.c    |  3 +--
> > >  security/lsm.h      |  4 ++++
> > >  security/lsm_init.c | 14 ++++++++++++--
> > >  security/min_addr.c |  5 +++--
> > >  4 files changed, 20 insertions(+), 6 deletions(-)
> 
> ...
> 
> > > @@ -503,7 +508,12 @@ early_initcall(security_initcall_early);
> > >   */
> > >  static int __init security_initcall_core(void)
> > >  {
> > > -     return lsm_initcall(core);
> > > +     int rc_sfs, rc_lsm;
> > > +
> > > +     rc_sfs = securityfs_init();
> > > +     rc_lsm = lsm_initcall(core);
> > > +
> > > +     return (rc_sfs ? rc_sfs : rc_lsm);
> > >  }
> > >  core_initcall(security_initcall_core);
> >
> > Hrm. Given these aren't really _lsm_ hooks, maybe just leave this out. I
> > worry about confusing the lsm inits with the lsm subsystem's core inits.
> 
> I'm not too concerned about that, and I do prefer it this way.

Sounds good to me. And with an eye toward trying to minimize which kinds
of init calls we have in the future, I think it'll just get cleaner over
time.

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 09/29] lsm: cleanup and normalize the LSM enabled functions
  2025-04-11  2:14       ` Paul Moore
@ 2025-04-11  2:17         ` Kees Cook
  0 siblings, 0 replies; 126+ messages in thread
From: Kees Cook @ 2025-04-11  2:17 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Thu, Apr 10, 2025 at 10:14:52PM -0400, Paul Moore wrote:
> On Thu, Apr 10, 2025 at 9:50 PM Paul Moore <paul@paul-moore.com> wrote:
> > On Wed, Apr 9, 2025 at 8:11 PM Kees Cook <kees@kernel.org> wrote:
> > > On Wed, Apr 09, 2025 at 02:49:54PM -0400, Paul Moore wrote:
> 
> ...
> 
> > > The simple renamings looks fine, but would be nicer if they got split
> > > out.
> >
> > I can look into doing that, let me try the squashing first.
> 
> ... and I pulled out the enabled/disable setter/getter functions into
> their own patch.

Awesome. My future review eyes thank you! :)

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 0/29] Rework the LSM initialization
  2025-04-10 14:13 ` [RFC PATCH 0/29] Rework the LSM initialization Casey Schaufler
  2025-04-10 16:31   ` Kees Cook
@ 2025-04-11  2:28   ` Paul Moore
  1 sibling, 0 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-11  2:28 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Tetsuo Handa

On Thu, Apr 10, 2025 at 10:13 AM Casey Schaufler <casey@schaufler-ca.com> wrote:
> On 4/9/2025 11:49 AM, Paul Moore wrote:

...

> General comments:
>
> Adjacent patches with no more commit message than "cleanup" should
> be combined, as that message is telling me "these aren't the changes
> you're looking for".

Things have been shuffled around quite a bit since this posting, and I
expect there will likely be a few more adjustments before a v2 is
posted.

> And about that. I believe that missing or uninformative commit messages
> are on your list of things that displease you. You will need to improve
> them to get them past yourself. :)

You'll notice that I highlighted the garbage commit messages in the
list of things that made this a RFC patch.  I'm well aware that this
is a big problem in this patchset, but I know there are individuals on
the LSM mailing list who have been anxiously awaiting a peek at this
work, so I made a decision to post a very crude revision to satisfy
that curiosity.  If you can't appreciate that decision, I hope that
you can at least understand it ;)

While I hope to never post a proper (read "non RFC") patchset with
such trash for commit messages, if I do, I would hope and expect that
all of you wouldn't hesitate to chastise me!

> There's a lot of churn here due to unnecessary name changes. I can't
> say they're unjustified, but the patch set is bigger than it needs to
> be, and more disruptive.

Perhaps, but there was some pretty awful code, with some pretty awful
names, in the initialization routines and if I was going to spend the
time to clean it all up I felt the renames were justified.  If I'm
ever going to pull a "maintainer's privilege" card, it would probably
be over stuff like this; I know it's trivial, and churns the code, but
I can't tell you how much it bothers me when I keep reading/reviewing
code with awful names.  That's probably why one of my chief nitpicks
with a lot of patches comes back to naming.

> I haven't tested it, but I don't see any substantial problems so far.

I appreciate the review, I know it's not an easy patchset to look at.
The next revision should be cleaner.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 20/29] smack: move initcalls to the LSM framework
  2025-04-09 23:42   ` Kees Cook
@ 2025-04-11  2:30     ` Paul Moore
  0 siblings, 0 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-11  2:30 UTC (permalink / raw)
  To: Kees Cook
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Wed, Apr 9, 2025 at 7:42 PM Kees Cook <kees@kernel.org> wrote:
> On Wed, Apr 09, 2025 at 02:50:05PM -0400, Paul Moore wrote:
> > As the LSM framework only supports one LSM initcall callback for each
> > initcall type, the init_smk_fs() and smack_nf_ip_init() functions were
> > wrapped with a new function, smack_initcall() that is registered with
> > the LSM framework.
> >
> > Signed-off-by: Paul Moore <paul@paul-moore.com>
> > ---
> >  security/smack/smack.h           |  6 ++++++
> >  security/smack/smack_lsm.c       | 16 ++++++++++++++++
> >  security/smack/smack_netfilter.c |  4 +---
> >  security/smack/smackfs.c         |  4 +---
> >  4 files changed, 24 insertions(+), 6 deletions(-)

...

> > diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> > index e09b33fed5f0..80b129a0c92c 100644
> > --- a/security/smack/smack_lsm.c
> > +++ b/security/smack/smack_lsm.c
> > @@ -5277,6 +5277,21 @@ static __init int smack_init(void)
> >       return 0;
> >  }
> >
> > +static int smack_initcall(void)
> > +{
> > +     int rc, rc_tmp;
> > +
> > +     rc_tmp = init_smk_fs();
> > +     if (rc_tmp)
> > +             rc = rc_tmp;
> > +
> > +     rc_tmp = smack_nf_ip_init();
> > +     if (!rc && rc_tmp)
> > +             rc = rc_tmp;
> > +
> > +     return rc;
> > +}
>
> This retains the existing behavior, but I think it'd be better to
> evaluate if the init_smk_fs() call can be tied to the fs init hook
> instead, yes? Then no new helper is needed, etc.

When doing this work I spotted a few LSMs where I think we could
consolidate multiple initcall types into one (or two?), but there was
enough in this patchset already I decided to leave that for another
day.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 18/29] loadpin: move initcalls to the LSM framework
  2025-04-11  2:16       ` Kees Cook
@ 2025-04-11  2:41         ` Paul Moore
  0 siblings, 0 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-11  2:41 UTC (permalink / raw)
  To: Kees Cook
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Thu, Apr 10, 2025 at 10:16 PM Kees Cook <kees@kernel.org> wrote:
>
> On Thu, Apr 10, 2025 at 09:15:47PM -0400, Paul Moore wrote:
> > On Wed, Apr 9, 2025 at 7:39 PM Kees Cook <kees@kernel.org> wrote:
> > > On Wed, Apr 09, 2025 at 02:50:03PM -0400, Paul Moore wrote:
> > > > Signed-off-by: Paul Moore <paul@paul-moore.com>
> > >
> > > Reviewed-by: Kees Cook <kees@kernel.org>
> >
> > Do you mind if I convert this into an Acked-by?  Generally speaking I
> > put more weight behind a Reviewed-by tag, but in the case of Loadpin
> > you are the maintainer and I'd much prefer an Acked-by.  While I'm
> > always happy to get more reviews on a patch, the primary reason for
> > CC'ing you directly was to get ACKs on the LSMs you maintain :)
>
> Acked-by: Kees Cook <kees@kernel.org>
>
> :)

Thanks :)

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 08/29] lsm: get rid of the lsm_names list and do some cleanup
  2025-04-11  2:15       ` Kees Cook
@ 2025-04-11  3:14         ` Paul Moore
  0 siblings, 0 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-11  3:14 UTC (permalink / raw)
  To: Kees Cook
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On Thu, Apr 10, 2025 at 10:15 PM Kees Cook <kees@kernel.org> wrote:
> On Thu, Apr 10, 2025 at 06:47:12PM -0400, Paul Moore wrote:
> > On Wed, Apr 9, 2025 at 7:13 PM Kees Cook <kees@kernel.org> wrote:
> > > Better yet, do this whole thing in a initcall after LSMs are loaded, and
> > > both can gain __ro_after_init...
> >
> > I *really* disliked all the stuff we were having to do during boot,
> > and all the redundant global state we were keeping around.  I'll go
> > ahead and cache the lsm_read() result local to the function but that's
> > probably all I'm going to accept at this point in time.
>
> Oh, for sure. I love that all that can get thrown away. I mean literally
> copy/paste what you have in lsm_read() and stick it immediately before
> the "lsms are done loading" notifier. Then it only needs to be done
> once, it's impossible to race, etc.

Maybe I'll change my mind at some point, but right now I'm feeling
pretty strongly against generating the list string at boot.  I've
added a basic cache protected by a dumb spinlock in lsm_read which
should work.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 26/29] selinux: move initcalls to the LSM framework
  2025-04-10 16:33   ` Stephen Smalley
@ 2025-04-11  3:24     ` Paul Moore
  0 siblings, 0 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-11  3:24 UTC (permalink / raw)
  To: Stephen Smalley
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On Thu, Apr 10, 2025 at 12:33 PM Stephen Smalley
<stephen.smalley.work@gmail.com> wrote:
> On Wed, Apr 9, 2025 at 2:55 PM Paul Moore <paul@paul-moore.com> wrote:
> >
> > SELinux currently has a number of initcalls so we've created a new
> > function, selinux_initcall(), which wraps all of these initcalls so
> > that we have a single initcall function that can be registered with the
> > LSM framework.
> >
> > Signed-off-by: Paul Moore <paul@paul-moore.com>
> > ---
>
> > diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h
> > index d5b0425055e4..5989f8dd1e86 100644
> > --- a/security/selinux/include/audit.h
> > +++ b/security/selinux/include/audit.h
> > @@ -15,6 +15,11 @@
> >  #include <linux/audit.h>
> >  #include <linux/types.h>
> >
> > +/**
> > + * XXX
> > + */
>
> Assuming this will be fixed before merge.

Yep, I noticed that very shortly after posting and added the comment block.

> > +int selinux_audit_rule_avc_callback(u32 event);
> > +
> >  /**
> >   * selinux_audit_rule_init - alloc/init an selinux audit rule structure.
> >   * @field: the field this rule refers to
> > diff --git a/security/selinux/include/initcalls.h b/security/selinux/include/initcalls.h
> > new file mode 100644
> > index 000000000000..6674cf489473
> > --- /dev/null
> > +++ b/security/selinux/include/initcalls.h
> > @@ -0,0 +1,19 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * SELinux initcalls
> > + */
> > +
> > +#ifndef _SELINUX_INITCALLS_H
> > +#define _SELINUX_INITCALLS_H
> > +
> > +int init_sel_fs(void);
> > +int sel_netport_init(void);
> > +int sel_netnode_init(void);
> > +int sel_netif_init(void);
> > +int sel_netlink_init(void);
> > +int sel_ib_pkey_init(void);
> > +int selinux_nf_ip_init(void);
>
> The last two only exist if certain Kconfig options are set.

Good catch, thanks.  The use of the netfilter initcall is already
conditional on CONFIG_NETFILTER in selinux_initcall(), but I forgot
the InfiniBand inticall.

Unless I'm mistaken, it should be harmless to have the function
declaration regardless of if it is defined anywhere.

> > diff --git a/security/selinux/initcalls.c b/security/selinux/initcalls.c
> > new file mode 100644
> > index 000000000000..81f01f8ad215
> > --- /dev/null
> > +++ b/security/selinux/initcalls.c
> > @@ -0,0 +1,50 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * SELinux initcalls
> > + */
> > +
> > +#include <linux/init.h>
> > +
> > +#include "initcalls.h"
> > +
> > +/**
> > + * selinux_initcall - Perform the SELinux initcalls
> > + *
> > + * Used as a device initcall in the SELinux LSM definition.
> > + */
> > +int __init selinux_initcall(void)
> > +{
> > +       int rc = 0, rc_tmp = 0;
> > +
> > +       rc_tmp = init_sel_fs();
> > +       if (!rc && rc_tmp)
> > +               rc = rc_tmp;
> > +
> > +       rc_tmp = sel_netport_init();
> > +       if (!rc && rc_tmp)
> > +               rc = rc_tmp;
> > +
> > +       rc_tmp = sel_netnode_init();
> > +       if (!rc && rc_tmp)
> > +               rc = rc_tmp;
> > +
> > +       rc_tmp = sel_netif_init();
> > +       if (!rc && rc_tmp)
> > +               rc = rc_tmp;
> > +
> > +       rc_tmp = sel_netlink_init();
> > +       if (!rc && rc_tmp)
> > +               rc = rc_tmp;
> > +
> > +       rc_tmp = sel_ib_pkey_init();
>
> This one depends on CONFIG_SECURITY_INFINIBAND.

Fixed, thanks.

> > +       if (!rc && rc_tmp)
> > +               rc = rc_tmp;
> > +
> > +#if defined(CONFIG_NETFILTER)
> > +       rc_tmp = selinux_nf_ip_init();
> > +       if (!rc && rc_tmp)
> > +               rc = rc_tmp;
> > +#endif
> > +
> > +       return rc;
> > +}

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 22/29] safesetid: move initcalls to the LSM framework
  2025-04-09 23:43   ` Kees Cook
@ 2025-04-11 19:20     ` Micah Morton
  2025-04-11 20:45       ` Paul Moore
  0 siblings, 1 reply; 126+ messages in thread
From: Micah Morton @ 2025-04-11 19:20 UTC (permalink / raw)
  To: Kees Cook
  Cc: Paul Moore, linux-security-module, linux-integrity, selinux,
	John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Casey Schaufler,
	Tetsuo Handa

On Wed, Apr 9, 2025 at 4:43 PM Kees Cook <kees@kernel.org> wrote:
>
> On Wed, Apr 09, 2025 at 02:50:07PM -0400, Paul Moore wrote:
> > Signed-off-by: Paul Moore <paul@paul-moore.com>
>
> Reviewed-by: Kees Cook <kees@kernel.org>

Acked-by: Micah Morton <mortonm@chromium.org>

>
> --
> Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 20/29] smack: move initcalls to the LSM framework
  2025-04-10 17:30   ` Casey Schaufler
  2025-04-10 17:47     ` Casey Schaufler
@ 2025-04-11 20:09     ` Paul Moore
  1 sibling, 0 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-11 20:09 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Tetsuo Handa

On Thu, Apr 10, 2025 at 1:30 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> On 4/9/2025 11:50 AM, Paul Moore wrote:
> > As the LSM framework only supports one LSM initcall callback for each
> > initcall type, the init_smk_fs() and smack_nf_ip_init() functions were
> > wrapped with a new function, smack_initcall() that is registered with
> > the LSM framework.
> >
> > Signed-off-by: Paul Moore <paul@paul-moore.com>
> > ---
> >  security/smack/smack.h           |  6 ++++++
> >  security/smack/smack_lsm.c       | 16 ++++++++++++++++
> >  security/smack/smack_netfilter.c |  4 +---
> >  security/smack/smackfs.c         |  4 +---
> >  4 files changed, 24 insertions(+), 6 deletions(-)
> >
> > diff --git a/security/smack/smack.h b/security/smack/smack.h
> > index bf6a6ed3946c..709e0d6cd5e1 100644
> > --- a/security/smack/smack.h
> > +++ b/security/smack/smack.h
> > @@ -275,6 +275,12 @@ struct smk_audit_info {
> >  #endif
> >  };
> >
> > +/*
> > + * Initialization
> > + */
> > +int init_smk_fs(void);
> > +int smack_nf_ip_init(void);
> > +
> >  /*
> >   * These functions are in smack_access.c
> >   */
> > diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> > index e09b33fed5f0..80b129a0c92c 100644
> > --- a/security/smack/smack_lsm.c
> > +++ b/security/smack/smack_lsm.c
> > @@ -5277,6 +5277,21 @@ static __init int smack_init(void)
> >       return 0;
> >  }
> >
> > +static int smack_initcall(void)
> > +{
> > +     int rc, rc_tmp;
>
> separate lines for the declarations please.

Done.

> > +     rc_tmp = init_smk_fs();
> > +     if (rc_tmp)
> > +             rc = rc_tmp;
>
> Replace these three lines with:
>
>  +      rc = init_smk_fs();

Done.

> > +
> > +     rc_tmp = smack_nf_ip_init();
> > +     if (!rc && rc_tmp)
> > +             rc = rc_tmp;
>
> Change this to
>
>  +      rc_tmp = smack_nf_ip_init();
>  +      return rc ? rc : rc_tmp;
>
> Also change rc_tmp to rc_nf and rc to rc_fs.

Done and done.

> > +
> > +     return rc;
> > +}
> > +
>
> Or:
>
> static int smack_initcall(void)
> {
>         int rc_fs = init_smk_fs();
>         int rc_nf = smack_nf_ip_init();
>
>         return rc_fs ? rc_fs : rc:nf;
> }

Done (with the typo fix you mentioned later).

Thanks for taking a look.


--
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 22/29] safesetid: move initcalls to the LSM framework
  2025-04-11 19:20     ` Micah Morton
@ 2025-04-11 20:45       ` Paul Moore
  0 siblings, 0 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-11 20:45 UTC (permalink / raw)
  To: Micah Morton
  Cc: Kees Cook, linux-security-module, linux-integrity, selinux,
	John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Casey Schaufler,
	Tetsuo Handa

On Fri, Apr 11, 2025 at 3:20 PM Micah Morton <mortonm@chromium.org> wrote:
>
> Acked-by: Micah Morton <mortonm@chromium.org>

Thanks Micah!

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 20/29] smack: move initcalls to the LSM framework
  2025-04-09 18:50 ` [RFC PATCH 20/29] smack: " Paul Moore
  2025-04-09 23:42   ` Kees Cook
  2025-04-10 17:30   ` Casey Schaufler
@ 2025-04-14 21:04   ` Fan Wu
  2025-04-15  1:54     ` Paul Moore
  2 siblings, 1 reply; 126+ messages in thread
From: Fan Wu @ 2025-04-14 21:04 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On Wed, Apr 9, 2025 at 11:53 AM Paul Moore <paul@paul-moore.com> wrote:
>
> As the LSM framework only supports one LSM initcall callback for each
> initcall type, the init_smk_fs() and smack_nf_ip_init() functions were
> wrapped with a new function, smack_initcall() that is registered with
> the LSM framework.
>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
>  security/smack/smack.h           |  6 ++++++
>  security/smack/smack_lsm.c       | 16 ++++++++++++++++
>  security/smack/smack_netfilter.c |  4 +---
>  security/smack/smackfs.c         |  4 +---
>  4 files changed, 24 insertions(+), 6 deletions(-)
>
> diff --git a/security/smack/smack.h b/security/smack/smack.h
> index bf6a6ed3946c..709e0d6cd5e1 100644
> --- a/security/smack/smack.h
> +++ b/security/smack/smack.h
> @@ -275,6 +275,12 @@ struct smk_audit_info {
>  #endif
>  };
>
> +/*
> + * Initialization
> + */
> +int init_smk_fs(void);
> +int smack_nf_ip_init(void);
> +
>  /*
>   * These functions are in smack_access.c
>   */
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index e09b33fed5f0..80b129a0c92c 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -5277,6 +5277,21 @@ static __init int smack_init(void)
>         return 0;
>  }
>
> +static int smack_initcall(void)
> +{
> +       int rc, rc_tmp;
> +
> +       rc_tmp = init_smk_fs();
> +       if (rc_tmp)
> +               rc = rc_tmp;
> +
> +       rc_tmp = smack_nf_ip_init();
> +       if (!rc && rc_tmp)
> +               rc = rc_tmp;
> +
> +       return rc;
> +}
> +
>  /*
>   * Smack requires early initialization in order to label
>   * all processes and objects when they are created.
> @@ -5286,4 +5301,5 @@ DEFINE_LSM(smack) = {
>         .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
>         .blobs = &smack_blob_sizes,
>         .init = smack_init,
> +       .initcall_device = smack_initcall,
>  };
> diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c
> index 8fd747b3653a..17ba578b1308 100644
> --- a/security/smack/smack_netfilter.c
> +++ b/security/smack/smack_netfilter.c
> @@ -68,7 +68,7 @@ static struct pernet_operations smack_net_ops = {
>         .exit = smack_nf_unregister,
>  };
>
> -static int __init smack_nf_ip_init(void)
> +int __init smack_nf_ip_init(void)
>  {
>         if (smack_enabled == 0)
>                 return 0;
> @@ -76,5 +76,3 @@ static int __init smack_nf_ip_init(void)
>         printk(KERN_DEBUG "Smack: Registering netfilter hooks\n");
>         return register_pernet_subsys(&smack_net_ops);
>  }
> -
> -__initcall(smack_nf_ip_init);
> diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
> index 90a67e410808..d33dd0368807 100644
> --- a/security/smack/smackfs.c
> +++ b/security/smack/smackfs.c
> @@ -2980,7 +2980,7 @@ static struct vfsmount *smackfs_mount;
>   * Returns true if we were not chosen on boot or if
>   * we were chosen and filesystem registration succeeded.
>   */
> -static int __init init_smk_fs(void)
> +int __init init_smk_fs(void)
>  {
>         int err;
>         int rc;
> @@ -3023,5 +3023,3 @@ static int __init init_smk_fs(void)
>
>         return err;
>  }
> -
> -__initcall(init_smk_fs);
> --
> 2.49.0
>

I'm getting the following WARNING:

WARNING: modpost: vmlinux: section mismatch in reference:
smack_initcall+0xb (section: .text) -> init_smk_fs (section:
.init.text)
WARNING: modpost: vmlinux: section mismatch in reference:
smack_initcall+0x16 (section: .text) -> smack_nf_ip_init (section:
.init.text)
WARNING: modpost: vmlinux: section mismatch in reference:
smack_initcall+0x27 (section: .text) -> smack_nf_ip_init (section:
.init.text)

I guess "__init" is missed for smack_initcall?

-Fan

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 19/29] ipe: move initcalls to the LSM framework
  2025-04-09 18:50 ` [RFC PATCH 19/29] ipe: " Paul Moore
  2025-04-09 23:40   ` Kees Cook
@ 2025-04-14 21:19   ` Fan Wu
  2025-04-15  1:58     ` Paul Moore
  2025-05-14 12:02   ` John Johansen
  2 siblings, 1 reply; 126+ messages in thread
From: Fan Wu @ 2025-04-14 21:19 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On Wed, Apr 9, 2025 at 11:53 AM Paul Moore <paul@paul-moore.com> wrote:
>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
>  security/ipe/fs.c  | 4 +---
>  security/ipe/ipe.c | 1 +
>  security/ipe/ipe.h | 2 ++
>  3 files changed, 4 insertions(+), 3 deletions(-)
>
> diff --git a/security/ipe/fs.c b/security/ipe/fs.c
> index 5b6d19fb844a..e4437c70ed3d 100644
> --- a/security/ipe/fs.c
> +++ b/security/ipe/fs.c
> @@ -187,7 +187,7 @@ static const struct file_operations enforce_fops = {
>   * Return: %0 on success. If an error occurs, the function will return
>   * the -errno.
>   */
> -static int __init ipe_init_securityfs(void)
> +int __init ipe_init_securityfs(void)
>  {
>         int rc = 0;
>         struct ipe_policy *ap;
> @@ -243,5 +243,3 @@ static int __init ipe_init_securityfs(void)
>         securityfs_remove(root);
>         return rc;
>  }
> -
> -fs_initcall(ipe_init_securityfs);
> diff --git a/security/ipe/ipe.c b/security/ipe/ipe.c
> index 2426441181dc..71644748ed56 100644
> --- a/security/ipe/ipe.c
> +++ b/security/ipe/ipe.c
> @@ -95,4 +95,5 @@ DEFINE_LSM(ipe) = {
>         .id = &ipe_lsmid,
>         .init = ipe_init,
>         .blobs = &ipe_blobs,
> +       .initcall_fs = ipe_init_securityfs,
>  };
> diff --git a/security/ipe/ipe.h b/security/ipe/ipe.h
> index fb37513812dd..25cfdb8f0c20 100644
> --- a/security/ipe/ipe.h
> +++ b/security/ipe/ipe.h
> @@ -23,4 +23,6 @@ struct ipe_bdev *ipe_bdev(struct block_device *b);
>  struct ipe_inode *ipe_inode(const struct inode *inode);
>  #endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
>
> +int ipe_init_securityfs(void);
> +
>  #endif /* _IPE_H */
> --
> 2.49.0
>

I have run the ipe's testsuite and all passed.

Tested-by: Fan Wu <wufan@kernel.org>
Acked-by: Fan Wu <wufan@kernel.org>

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 20/29] smack: move initcalls to the LSM framework
  2025-04-14 21:04   ` Fan Wu
@ 2025-04-15  1:54     ` Paul Moore
  0 siblings, 0 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-15  1:54 UTC (permalink / raw)
  To: Fan Wu
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On Mon, Apr 14, 2025 at 5:04 PM Fan Wu <wufan@kernel.org> wrote:
> On Wed, Apr 9, 2025 at 11:53 AM Paul Moore <paul@paul-moore.com> wrote:
> >
> > As the LSM framework only supports one LSM initcall callback for each
> > initcall type, the init_smk_fs() and smack_nf_ip_init() functions were
> > wrapped with a new function, smack_initcall() that is registered with
> > the LSM framework.
> >
> > Signed-off-by: Paul Moore <paul@paul-moore.com>
> > ---
> >  security/smack/smack.h           |  6 ++++++
> >  security/smack/smack_lsm.c       | 16 ++++++++++++++++
> >  security/smack/smack_netfilter.c |  4 +---
> >  security/smack/smackfs.c         |  4 +---
> >  4 files changed, 24 insertions(+), 6 deletions(-)

...

> I'm getting the following WARNING:
>
> WARNING: modpost: vmlinux: section mismatch in reference:
> smack_initcall+0xb (section: .text) -> init_smk_fs (section:
> .init.text)
> WARNING: modpost: vmlinux: section mismatch in reference:
> smack_initcall+0x16 (section: .text) -> smack_nf_ip_init (section:
> .init.text)
> WARNING: modpost: vmlinux: section mismatch in reference:
> smack_initcall+0x27 (section: .text) -> smack_nf_ip_init (section:
> .init.text)
>
> I guess "__init" is missed for smack_initcall?

Yep, fixed, thanks.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 19/29] ipe: move initcalls to the LSM framework
  2025-04-14 21:19   ` Fan Wu
@ 2025-04-15  1:58     ` Paul Moore
  0 siblings, 0 replies; 126+ messages in thread
From: Paul Moore @ 2025-04-15  1:58 UTC (permalink / raw)
  To: Fan Wu
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On Mon, Apr 14, 2025 at 5:19 PM Fan Wu <wufan@kernel.org> wrote:
>
> On Wed, Apr 9, 2025 at 11:53 AM Paul Moore <paul@paul-moore.com> wrote:
> >
> > Signed-off-by: Paul Moore <paul@paul-moore.com>
> > ---
> >  security/ipe/fs.c  | 4 +---
> >  security/ipe/ipe.c | 1 +
> >  security/ipe/ipe.h | 2 ++
> >  3 files changed, 4 insertions(+), 3 deletions(-)

...

> I have run the ipe's testsuite and all passed.
>
> Tested-by: Fan Wu <wufan@kernel.org>
> Acked-by: Fan Wu <wufan@kernel.org>

Thanks Fan.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 01/29] lsm: split the notifier code out into lsm_notifier.c
  2025-04-09 18:49 ` [RFC PATCH 01/29] lsm: split the notifier code out into lsm_notifier.c Paul Moore
  2025-04-09 21:17   ` Kees Cook
@ 2025-04-15 12:14   ` John Johansen
  1 sibling, 0 replies; 126+ messages in thread
From: John Johansen @ 2025-04-15 12:14 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On 4/9/25 11:49, Paul Moore wrote:
> In an effort to decompose security/security.c somewhat to make it less
> twisted and unwieldy, pull out the LSM notifier code into a new file
> as it is fairly well self-contained.
> 
> No code changes.
> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>

lgtm

Reviewed-by: John Johansen <john.johansen@canonical.com>

> ---
>   security/Makefile       |  2 +-
>   security/lsm_notifier.c | 31 +++++++++++++++++++++++++++++++
>   security/security.c     | 23 -----------------------
>   3 files changed, 32 insertions(+), 24 deletions(-)
>   create mode 100644 security/lsm_notifier.c
> 
> diff --git a/security/Makefile b/security/Makefile
> index 22ff4c8bd8ce..14d87847bce8 100644
> --- a/security/Makefile
> +++ b/security/Makefile
> @@ -11,7 +11,7 @@ obj-$(CONFIG_SECURITY) 			+= lsm_syscalls.o
>   obj-$(CONFIG_MMU)			+= min_addr.o
>   
>   # Object file lists
> -obj-$(CONFIG_SECURITY)			+= security.o
> +obj-$(CONFIG_SECURITY)			+= security.o lsm_notifier.o
>   obj-$(CONFIG_SECURITYFS)		+= inode.o
>   obj-$(CONFIG_SECURITY_SELINUX)		+= selinux/
>   obj-$(CONFIG_SECURITY_SMACK)		+= smack/
> diff --git a/security/lsm_notifier.c b/security/lsm_notifier.c
> new file mode 100644
> index 000000000000..c92fad5d57d4
> --- /dev/null
> +++ b/security/lsm_notifier.c
> @@ -0,0 +1,31 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * LSM notifier functions
> + *
> + */
> +
> +#include <linux/notifier.h>
> +#include <linux/security.h>
> +
> +static BLOCKING_NOTIFIER_HEAD(blocking_lsm_notifier_chain);
> +
> +int call_blocking_lsm_notifier(enum lsm_event event, void *data)
> +{
> +	return blocking_notifier_call_chain(&blocking_lsm_notifier_chain,
> +					    event, data);
> +}
> +EXPORT_SYMBOL(call_blocking_lsm_notifier);
> +
> +int register_blocking_lsm_notifier(struct notifier_block *nb)
> +{
> +	return blocking_notifier_chain_register(&blocking_lsm_notifier_chain,
> +						nb);
> +}
> +EXPORT_SYMBOL(register_blocking_lsm_notifier);
> +
> +int unregister_blocking_lsm_notifier(struct notifier_block *nb)
> +{
> +	return blocking_notifier_chain_unregister(&blocking_lsm_notifier_chain,
> +						  nb);
> +}
> +EXPORT_SYMBOL(unregister_blocking_lsm_notifier);
> diff --git a/security/security.c b/security/security.c
> index fb57e8fddd91..477be0a17e3f 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -90,8 +90,6 @@ const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX + 1] = {
>   	[LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality",
>   };
>   
> -static BLOCKING_NOTIFIER_HEAD(blocking_lsm_notifier_chain);
> -
>   static struct kmem_cache *lsm_file_cache;
>   static struct kmem_cache *lsm_inode_cache;
>   
> @@ -643,27 +641,6 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
>   	}
>   }
>   
> -int call_blocking_lsm_notifier(enum lsm_event event, void *data)
> -{
> -	return blocking_notifier_call_chain(&blocking_lsm_notifier_chain,
> -					    event, data);
> -}
> -EXPORT_SYMBOL(call_blocking_lsm_notifier);
> -
> -int register_blocking_lsm_notifier(struct notifier_block *nb)
> -{
> -	return blocking_notifier_chain_register(&blocking_lsm_notifier_chain,
> -						nb);
> -}
> -EXPORT_SYMBOL(register_blocking_lsm_notifier);
> -
> -int unregister_blocking_lsm_notifier(struct notifier_block *nb)
> -{
> -	return blocking_notifier_chain_unregister(&blocking_lsm_notifier_chain,
> -						  nb);
> -}
> -EXPORT_SYMBOL(unregister_blocking_lsm_notifier);
> -
>   /**
>    * lsm_blob_alloc - allocate a composite blob
>    * @dest: the destination for the blob


^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 02/29] lsm: split the init code out into lsm_init.c
  2025-04-09 18:49 ` [RFC PATCH 02/29] lsm: split the init code out into lsm_init.c Paul Moore
  2025-04-09 21:18   ` Kees Cook
@ 2025-04-15 22:01   ` John Johansen
  1 sibling, 0 replies; 126+ messages in thread
From: John Johansen @ 2025-04-15 22:01 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On 4/9/25 11:49, Paul Moore wrote:
> Continue to pull code out of security/security.c to help improve
> readability by pulling all of the LSM framework initialization
> code out into a new file.
> 
> No code changes.
> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>

Reviewed-by: John Johansen <john.johansen@canonical.com>

> ---
>   include/linux/lsm_hooks.h |   3 +-
>   security/Makefile         |   2 +-
>   security/lsm.h            |  22 ++
>   security/lsm_init.c       | 537 ++++++++++++++++++++++++++++++++++
>   security/security.c       | 591 +++-----------------------------------
>   5 files changed, 595 insertions(+), 560 deletions(-)
>   create mode 100644 security/lsm.h
>   create mode 100644 security/lsm_init.c
> 
> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
> index 090d1d3e19fe..eeb4bfd60b79 100644
> --- a/include/linux/lsm_hooks.h
> +++ b/include/linux/lsm_hooks.h
> @@ -167,11 +167,10 @@ struct lsm_info {
>   		__used __section(".early_lsm_info.init")		\
>   		__aligned(sizeof(unsigned long))
>   
> +
>   /* DO NOT tamper with these variables outside of the LSM framework */
>   extern char *lsm_names;
>   extern struct lsm_static_calls_table static_calls_table __ro_after_init;
> -extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
> -extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
>   
>   /**
>    * lsm_get_xattr_slot - Return the next available slot and increment the index
> diff --git a/security/Makefile b/security/Makefile
> index 14d87847bce8..4601230ba442 100644
> --- a/security/Makefile
> +++ b/security/Makefile
> @@ -11,7 +11,7 @@ obj-$(CONFIG_SECURITY) 			+= lsm_syscalls.o
>   obj-$(CONFIG_MMU)			+= min_addr.o
>   
>   # Object file lists
> -obj-$(CONFIG_SECURITY)			+= security.o lsm_notifier.o
> +obj-$(CONFIG_SECURITY)			+= security.o lsm_notifier.o lsm_init.o
>   obj-$(CONFIG_SECURITYFS)		+= inode.o
>   obj-$(CONFIG_SECURITY_SELINUX)		+= selinux/
>   obj-$(CONFIG_SECURITY_SMACK)		+= smack/
> diff --git a/security/lsm.h b/security/lsm.h
> new file mode 100644
> index 000000000000..0e1731bad4a7
> --- /dev/null
> +++ b/security/lsm.h
> @@ -0,0 +1,22 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * LSM functions
> + */
> +
> +#ifndef _LSM_H_
> +#define _LSM_H_
> +
> +#include <linux/lsm_hooks.h>
> +
> +/* LSM blob configuration */
> +extern struct lsm_blob_sizes blob_sizes;
> +
> +/* LSM blob caches */
> +extern struct kmem_cache *lsm_file_cache;
> +extern struct kmem_cache *lsm_inode_cache;
> +
> +/* LSM blob allocators */
> +int lsm_cred_alloc(struct cred *cred, gfp_t gfp);
> +int lsm_task_alloc(struct task_struct *task);
> +
> +#endif /* _LSM_H_ */
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> new file mode 100644
> index 000000000000..70e7d4207dae
> --- /dev/null
> +++ b/security/lsm_init.c
> @@ -0,0 +1,537 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * LSM initialization functions
> + */
> +
> +#define pr_fmt(fmt) "LSM: " fmt
> +
> +#include <linux/init.h>
> +#include <linux/lsm_hooks.h>
> +
> +#include "lsm.h"
> +
> +char *lsm_names;
> +
> +/* Pointers to LSM sections defined in include/asm-generic/vmlinux.lds.h */
> +extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
> +extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
> +
> +/* Boot-time LSM user choice */
> +static __initconst const char *const builtin_lsm_order = CONFIG_LSM;
> +static __initdata const char *chosen_lsm_order;
> +static __initdata const char *chosen_major_lsm;
> +
> +/* Ordered list of LSMs to initialize. */
> +static __initdata struct lsm_info *ordered_lsms[MAX_LSM_COUNT + 1];
> +static __initdata struct lsm_info *exclusive;
> +
> +static __initdata bool debug;
> +#define init_debug(...)							\
> +	do {								\
> +		if (debug)						\
> +			pr_info(__VA_ARGS__);				\
> +	} while (0)
> +
> +static int lsm_append(const char *new, char **result);
> +
> +/* Save user chosen LSM */
> +static int __init choose_major_lsm(char *str)
> +{
> +	chosen_major_lsm = str;
> +	return 1;
> +}
> +__setup("security=", choose_major_lsm);
> +
> +/* Explicitly choose LSM initialization order. */
> +static int __init choose_lsm_order(char *str)
> +{
> +	chosen_lsm_order = str;
> +	return 1;
> +}
> +__setup("lsm=", choose_lsm_order);
> +
> +/* Enable LSM order debugging. */
> +static int __init enable_debug(char *str)
> +{
> +	debug = true;
> +	return 1;
> +}
> +__setup("lsm.debug", enable_debug);
> +
> +/* Mark an LSM's enabled flag. */
> +static int lsm_enabled_true __initdata = 1;
> +static int lsm_enabled_false __initdata = 0;
> +static void __init set_enabled(struct lsm_info *lsm, bool enabled)
> +{
> +	/*
> +	 * When an LSM hasn't configured an enable variable, we can use
> +	 * a hard-coded location for storing the default enabled state.
> +	 */
> +	if (!lsm->enabled) {
> +		if (enabled)
> +			lsm->enabled = &lsm_enabled_true;
> +		else
> +			lsm->enabled = &lsm_enabled_false;
> +	} else if (lsm->enabled == &lsm_enabled_true) {
> +		if (!enabled)
> +			lsm->enabled = &lsm_enabled_false;
> +	} else if (lsm->enabled == &lsm_enabled_false) {
> +		if (enabled)
> +			lsm->enabled = &lsm_enabled_true;
> +	} else {
> +		*lsm->enabled = enabled;
> +	}
> +}
> +
> +static inline bool is_enabled(struct lsm_info *lsm)
> +{
> +	if (!lsm->enabled)
> +		return false;
> +
> +	return *lsm->enabled;
> +}
> +
> +/* Is an LSM already listed in the ordered LSMs list? */
> +static bool __init exists_ordered_lsm(struct lsm_info *lsm)
> +{
> +	struct lsm_info **check;
> +
> +	for (check = ordered_lsms; *check; check++)
> +		if (*check == lsm)
> +			return true;
> +
> +	return false;
> +}
> +
> +/* Append an LSM to the list of ordered LSMs to initialize. */
> +static int last_lsm __initdata;
> +static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
> +{
> +	/* Ignore duplicate selections. */
> +	if (exists_ordered_lsm(lsm))
> +		return;
> +
> +	if (WARN(last_lsm == MAX_LSM_COUNT, "%s: out of LSM static calls!?\n", from))
> +		return;
> +
> +	/* Enable this LSM, if it is not already set. */
> +	if (!lsm->enabled)
> +		lsm->enabled = &lsm_enabled_true;
> +	ordered_lsms[last_lsm++] = lsm;
> +
> +	init_debug("%s ordered: %s (%s)\n", from, lsm->name,
> +		   is_enabled(lsm) ? "enabled" : "disabled");
> +}
> +
> +/* Is an LSM allowed to be initialized? */
> +static bool __init lsm_allowed(struct lsm_info *lsm)
> +{
> +	/* Skip if the LSM is disabled. */
> +	if (!is_enabled(lsm))
> +		return false;
> +
> +	/* Not allowed if another exclusive LSM already initialized. */
> +	if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
> +		init_debug("exclusive disabled: %s\n", lsm->name);
> +		return false;
> +	}
> +
> +	return true;
> +}
> +
> +static void __init lsm_set_blob_size(int *need, int *lbs)
> +{
> +	int offset;
> +
> +	if (*need <= 0)
> +		return;
> +
> +	offset = ALIGN(*lbs, sizeof(void *));
> +	*lbs = offset + *need;
> +	*need = offset;
> +}
> +
> +static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
> +{
> +	if (!needed)
> +		return;
> +
> +	lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
> +	lsm_set_blob_size(&needed->lbs_file, &blob_sizes.lbs_file);
> +	lsm_set_blob_size(&needed->lbs_ib, &blob_sizes.lbs_ib);
> +	/*
> +	 * The inode blob gets an rcu_head in addition to
> +	 * what the modules might need.
> +	 */
> +	if (needed->lbs_inode && blob_sizes.lbs_inode == 0)
> +		blob_sizes.lbs_inode = sizeof(struct rcu_head);
> +	lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
> +	lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
> +	lsm_set_blob_size(&needed->lbs_key, &blob_sizes.lbs_key);
> +	lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
> +	lsm_set_blob_size(&needed->lbs_perf_event, &blob_sizes.lbs_perf_event);
> +	lsm_set_blob_size(&needed->lbs_sock, &blob_sizes.lbs_sock);
> +	lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
> +	lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
> +	lsm_set_blob_size(&needed->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
> +	lsm_set_blob_size(&needed->lbs_xattr_count,
> +			  &blob_sizes.lbs_xattr_count);
> +	lsm_set_blob_size(&needed->lbs_bdev, &blob_sizes.lbs_bdev);
> +}
> +
> +/* Prepare LSM for initialization. */
> +static void __init prepare_lsm(struct lsm_info *lsm)
> +{
> +	int enabled = lsm_allowed(lsm);
> +
> +	/* Record enablement (to handle any following exclusive LSMs). */
> +	set_enabled(lsm, enabled);
> +
> +	/* If enabled, do pre-initialization work. */
> +	if (enabled) {
> +		if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
> +			exclusive = lsm;
> +			init_debug("exclusive chosen:   %s\n", lsm->name);
> +		}
> +
> +		lsm_set_blob_sizes(lsm->blobs);
> +	}
> +}
> +
> +/* Initialize a given LSM, if it is enabled. */
> +static void __init initialize_lsm(struct lsm_info *lsm)
> +{
> +	if (is_enabled(lsm)) {
> +		int ret;
> +
> +		init_debug("initializing %s\n", lsm->name);
> +		ret = lsm->init();
> +		WARN(ret, "%s failed to initialize: %d\n", lsm->name, ret);
> +	}
> +}
> +
> +/*
> + * Current index to use while initializing the lsm id list.
> + */
> +u32 lsm_active_cnt __ro_after_init;
> +const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
> +
> +/* Populate ordered LSMs list from comma-separated LSM name list. */
> +static void __init ordered_lsm_parse(const char *order, const char *origin)
> +{
> +	struct lsm_info *lsm;
> +	char *sep, *name, *next;
> +
> +	/* LSM_ORDER_FIRST is always first. */
> +	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
> +		if (lsm->order == LSM_ORDER_FIRST)
> +			append_ordered_lsm(lsm, "  first");
> +	}
> +
> +	/* Process "security=", if given. */
> +	if (chosen_major_lsm) {
> +		struct lsm_info *major;
> +
> +		/*
> +		 * To match the original "security=" behavior, this
> +		 * explicitly does NOT fallback to another Legacy Major
> +		 * if the selected one was separately disabled: disable
> +		 * all non-matching Legacy Major LSMs.
> +		 */
> +		for (major = __start_lsm_info; major < __end_lsm_info;
> +		     major++) {
> +			if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
> +			    strcmp(major->name, chosen_major_lsm) != 0) {
> +				set_enabled(major, false);
> +				init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
> +					   chosen_major_lsm, major->name);
> +			}
> +		}
> +	}
> +
> +	sep = kstrdup(order, GFP_KERNEL);
> +	next = sep;
> +	/* Walk the list, looking for matching LSMs. */
> +	while ((name = strsep(&next, ",")) != NULL) {
> +		bool found = false;
> +
> +		for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
> +			if (strcmp(lsm->name, name) == 0) {
> +				if (lsm->order == LSM_ORDER_MUTABLE)
> +					append_ordered_lsm(lsm, origin);
> +				found = true;
> +			}
> +		}
> +
> +		if (!found)
> +			init_debug("%s ignored: %s (not built into kernel)\n",
> +				   origin, name);
> +	}
> +
> +	/* Process "security=", if given. */
> +	if (chosen_major_lsm) {
> +		for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
> +			if (exists_ordered_lsm(lsm))
> +				continue;
> +			if (strcmp(lsm->name, chosen_major_lsm) == 0)
> +				append_ordered_lsm(lsm, "security=");
> +		}
> +	}
> +
> +	/* LSM_ORDER_LAST is always last. */
> +	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
> +		if (lsm->order == LSM_ORDER_LAST)
> +			append_ordered_lsm(lsm, "   last");
> +	}
> +
> +	/* Disable all LSMs not in the ordered list. */
> +	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
> +		if (exists_ordered_lsm(lsm))
> +			continue;
> +		set_enabled(lsm, false);
> +		init_debug("%s skipped: %s (not in requested order)\n",
> +			   origin, lsm->name);
> +	}
> +
> +	kfree(sep);
> +}
> +
> +static void __init report_lsm_order(void)
> +{
> +	struct lsm_info **lsm, *early;
> +	int first = 0;
> +
> +	pr_info("initializing lsm=");
> +
> +	/* Report each enabled LSM name, comma separated. */
> +	for (early = __start_early_lsm_info;
> +	     early < __end_early_lsm_info; early++)
> +		if (is_enabled(early))
> +			pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
> +	for (lsm = ordered_lsms; *lsm; lsm++)
> +		if (is_enabled(*lsm))
> +			pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
> +
> +	pr_cont("\n");
> +}
> +
> +/**
> + * lsm_early_cred - during initialization allocate a composite cred blob
> + * @cred: the cred that needs a blob
> + *
> + * Allocate the cred blob for all the modules
> + */
> +static void __init lsm_early_cred(struct cred *cred)
> +{
> +	int rc = lsm_cred_alloc(cred, GFP_KERNEL);
> +
> +	if (rc)
> +		panic("%s: Early cred alloc failed.\n", __func__);
> +}
> +
> +/**
> + * lsm_early_task - during initialization allocate a composite task blob
> + * @task: the task that needs a blob
> + *
> + * Allocate the task blob for all the modules
> + */
> +static void __init lsm_early_task(struct task_struct *task)
> +{
> +	int rc = lsm_task_alloc(task);
> +
> +	if (rc)
> +		panic("%s: Early task alloc failed.\n", __func__);
> +}
> +
> +static void __init ordered_lsm_init(void)
> +{
> +	struct lsm_info **lsm;
> +
> +	if (chosen_lsm_order) {
> +		if (chosen_major_lsm) {
> +			pr_warn("security=%s is ignored because it is superseded by lsm=%s\n",
> +				chosen_major_lsm, chosen_lsm_order);
> +			chosen_major_lsm = NULL;
> +		}
> +		ordered_lsm_parse(chosen_lsm_order, "cmdline");
> +	} else
> +		ordered_lsm_parse(builtin_lsm_order, "builtin");
> +
> +	for (lsm = ordered_lsms; *lsm; lsm++)
> +		prepare_lsm(*lsm);
> +
> +	report_lsm_order();
> +
> +	init_debug("cred blob size       = %d\n", blob_sizes.lbs_cred);
> +	init_debug("file blob size       = %d\n", blob_sizes.lbs_file);
> +	init_debug("ib blob size         = %d\n", blob_sizes.lbs_ib);
> +	init_debug("inode blob size      = %d\n", blob_sizes.lbs_inode);
> +	init_debug("ipc blob size        = %d\n", blob_sizes.lbs_ipc);
> +#ifdef CONFIG_KEYS
> +	init_debug("key blob size        = %d\n", blob_sizes.lbs_key);
> +#endif /* CONFIG_KEYS */
> +	init_debug("msg_msg blob size    = %d\n", blob_sizes.lbs_msg_msg);
> +	init_debug("sock blob size       = %d\n", blob_sizes.lbs_sock);
> +	init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
> +	init_debug("perf event blob size = %d\n", blob_sizes.lbs_perf_event);
> +	init_debug("task blob size       = %d\n", blob_sizes.lbs_task);
> +	init_debug("tun device blob size = %d\n", blob_sizes.lbs_tun_dev);
> +	init_debug("xattr slots          = %d\n", blob_sizes.lbs_xattr_count);
> +	init_debug("bdev blob size       = %d\n", blob_sizes.lbs_bdev);
> +
> +	/*
> +	 * Create any kmem_caches needed for blobs
> +	 */
> +	if (blob_sizes.lbs_file)
> +		lsm_file_cache = kmem_cache_create("lsm_file_cache",
> +						   blob_sizes.lbs_file, 0,
> +						   SLAB_PANIC, NULL);
> +	if (blob_sizes.lbs_inode)
> +		lsm_inode_cache = kmem_cache_create("lsm_inode_cache",
> +						    blob_sizes.lbs_inode, 0,
> +						    SLAB_PANIC, NULL);
> +
> +	lsm_early_cred((struct cred *) current->cred);
> +	lsm_early_task(current);
> +	for (lsm = ordered_lsms; *lsm; lsm++)
> +		initialize_lsm(*lsm);
> +}
> +
> +static bool match_last_lsm(const char *list, const char *lsm)
> +{
> +	const char *last;
> +
> +	if (WARN_ON(!list || !lsm))
> +		return false;
> +	last = strrchr(list, ',');
> +	if (last)
> +		/* Pass the comma, strcmp() will check for '\0' */
> +		last++;
> +	else
> +		last = list;
> +	return !strcmp(last, lsm);
> +}
> +
> +static int lsm_append(const char *new, char **result)
> +{
> +	char *cp;
> +
> +	if (*result == NULL) {
> +		*result = kstrdup(new, GFP_KERNEL);
> +		if (*result == NULL)
> +			return -ENOMEM;
> +	} else {
> +		/* Check if it is the last registered name */
> +		if (match_last_lsm(*result, new))
> +			return 0;
> +		cp = kasprintf(GFP_KERNEL, "%s,%s", *result, new);
> +		if (cp == NULL)
> +			return -ENOMEM;
> +		kfree(*result);
> +		*result = cp;
> +	}
> +	return 0;
> +}
> +
> +static void __init lsm_static_call_init(struct security_hook_list *hl)
> +{
> +	struct lsm_static_call *scall = hl->scalls;
> +	int i;
> +
> +	for (i = 0; i < MAX_LSM_COUNT; i++) {
> +		/* Update the first static call that is not used yet */
> +		if (!scall->hl) {
> +			__static_call_update(scall->key, scall->trampoline,
> +					     hl->hook.lsm_func_addr);
> +			scall->hl = hl;
> +			static_branch_enable(scall->active);
> +			return;
> +		}
> +		scall++;
> +	}
> +	panic("%s - Ran out of static slots.\n", __func__);
> +}
> +
> +/**
> + * security_add_hooks - Add a modules hooks to the hook lists.
> + * @hooks: the hooks to add
> + * @count: the number of hooks to add
> + * @lsmid: the identification information for the security module
> + *
> + * Each LSM has to register its hooks with the infrastructure.
> + */
> +void __init security_add_hooks(struct security_hook_list *hooks, int count,
> +			       const struct lsm_id *lsmid)
> +{
> +	int i;
> +
> +	/*
> +	 * A security module may call security_add_hooks() more
> +	 * than once during initialization, and LSM initialization
> +	 * is serialized. Landlock is one such case.
> +	 * Look at the previous entry, if there is one, for duplication.
> +	 */
> +	if (lsm_active_cnt == 0 || lsm_idlist[lsm_active_cnt - 1] != lsmid) {
> +		if (lsm_active_cnt >= MAX_LSM_COUNT)
> +			panic("%s Too many LSMs registered.\n", __func__);
> +		lsm_idlist[lsm_active_cnt++] = lsmid;
> +	}
> +
> +	for (i = 0; i < count; i++) {
> +		hooks[i].lsmid = lsmid;
> +		lsm_static_call_init(&hooks[i]);
> +	}
> +
> +	/*
> +	 * Don't try to append during early_security_init(), we'll come back
> +	 * and fix this up afterwards.
> +	 */
> +	if (slab_is_available()) {
> +		if (lsm_append(lsmid->name, &lsm_names) < 0)
> +			panic("%s - Cannot get early memory.\n", __func__);
> +	}
> +}
> +
> +int __init early_security_init(void)
> +{
> +	struct lsm_info *lsm;
> +
> +	for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
> +		if (!lsm->enabled)
> +			lsm->enabled = &lsm_enabled_true;
> +		prepare_lsm(lsm);
> +		initialize_lsm(lsm);
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * security_init - initializes the security framework
> + *
> + * This should be called early in the kernel initialization sequence.
> + */
> +int __init security_init(void)
> +{
> +	struct lsm_info *lsm;
> +
> +	init_debug("legacy security=%s\n", chosen_major_lsm ? : " *unspecified*");
> +	init_debug("  CONFIG_LSM=%s\n", builtin_lsm_order);
> +	init_debug("boot arg lsm=%s\n", chosen_lsm_order ? : " *unspecified*");
> +
> +	/*
> +	 * Append the names of the early LSM modules now that kmalloc() is
> +	 * available
> +	 */
> +	for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
> +		init_debug("  early started: %s (%s)\n", lsm->name,
> +			   is_enabled(lsm) ? "enabled" : "disabled");
> +		if (lsm->enabled)
> +			lsm_append(lsm->name, &lsm_names);
> +	}
> +
> +	/* Load LSMs in specified order. */
> +	ordered_lsm_init();
> +
> +	return 0;
> +}
> diff --git a/security/security.c b/security/security.c
> index 477be0a17e3f..8d370a4c5e74 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -32,24 +32,7 @@
>   #include <net/flow.h>
>   #include <net/sock.h>
>   
> -#define SECURITY_HOOK_ACTIVE_KEY(HOOK, IDX) security_hook_active_##HOOK##_##IDX
> -
> -/*
> - * Identifier for the LSM static calls.
> - * HOOK is an LSM hook as defined in linux/lsm_hookdefs.h
> - * IDX is the index of the static call. 0 <= NUM < MAX_LSM_COUNT
> - */
> -#define LSM_STATIC_CALL(HOOK, IDX) lsm_static_call_##HOOK##_##IDX
> -
> -/*
> - * Call the macro M for each LSM hook MAX_LSM_COUNT times.
> - */
> -#define LSM_LOOP_UNROLL(M, ...) 		\
> -do {						\
> -	UNROLL(MAX_LSM_COUNT, M, __VA_ARGS__)	\
> -} while (0)
> -
> -#define LSM_DEFINE_UNROLL(M, ...) UNROLL(MAX_LSM_COUNT, M, __VA_ARGS__)
> +#include "lsm.h"
>   
>   /*
>    * These are descriptions of the reasons that can be passed to the
> @@ -90,21 +73,29 @@ const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX + 1] = {
>   	[LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality",
>   };
>   
> -static struct kmem_cache *lsm_file_cache;
> -static struct kmem_cache *lsm_inode_cache;
> +struct lsm_blob_sizes blob_sizes;
>   
> -char *lsm_names;
> -static struct lsm_blob_sizes blob_sizes __ro_after_init;
> +struct kmem_cache *lsm_file_cache;
> +struct kmem_cache *lsm_inode_cache;
>   
> -/* Boot-time LSM user choice */
> -static __initdata const char *chosen_lsm_order;
> -static __initdata const char *chosen_major_lsm;
> +#define SECURITY_HOOK_ACTIVE_KEY(HOOK, IDX) security_hook_active_##HOOK##_##IDX
>   
> -static __initconst const char *const builtin_lsm_order = CONFIG_LSM;
> +/*
> + * Identifier for the LSM static calls.
> + * HOOK is an LSM hook as defined in linux/lsm_hookdefs.h
> + * IDX is the index of the static call. 0 <= NUM < MAX_LSM_COUNT
> + */
> +#define LSM_STATIC_CALL(HOOK, IDX) lsm_static_call_##HOOK##_##IDX
>   
> -/* Ordered list of LSMs to initialize. */
> -static __initdata struct lsm_info *ordered_lsms[MAX_LSM_COUNT + 1];
> -static __initdata struct lsm_info *exclusive;
> +/*
> + * Call the macro M for each LSM hook MAX_LSM_COUNT times.
> + */
> +#define LSM_LOOP_UNROLL(M, ...) 		\
> +do {						\
> +	UNROLL(MAX_LSM_COUNT, M, __VA_ARGS__)	\
> +} while (0)
> +
> +#define LSM_DEFINE_UNROLL(M, ...) UNROLL(MAX_LSM_COUNT, M, __VA_ARGS__)
>   
>   #ifdef CONFIG_HAVE_STATIC_CALL
>   #define LSM_HOOK_TRAMP(NAME, NUM) \
> @@ -155,490 +146,25 @@ struct lsm_static_calls_table
>   #undef INIT_LSM_STATIC_CALL
>   	};
>   
> -static __initdata bool debug;
> -#define init_debug(...)						\
> -	do {							\
> -		if (debug)					\
> -			pr_info(__VA_ARGS__);			\
> -	} while (0)
> -
> -static bool __init is_enabled(struct lsm_info *lsm)
> -{
> -	if (!lsm->enabled)
> -		return false;
> -
> -	return *lsm->enabled;
> -}
> -
> -/* Mark an LSM's enabled flag. */
> -static int lsm_enabled_true __initdata = 1;
> -static int lsm_enabled_false __initdata = 0;
> -static void __init set_enabled(struct lsm_info *lsm, bool enabled)
> -{
> -	/*
> -	 * When an LSM hasn't configured an enable variable, we can use
> -	 * a hard-coded location for storing the default enabled state.
> -	 */
> -	if (!lsm->enabled) {
> -		if (enabled)
> -			lsm->enabled = &lsm_enabled_true;
> -		else
> -			lsm->enabled = &lsm_enabled_false;
> -	} else if (lsm->enabled == &lsm_enabled_true) {
> -		if (!enabled)
> -			lsm->enabled = &lsm_enabled_false;
> -	} else if (lsm->enabled == &lsm_enabled_false) {
> -		if (enabled)
> -			lsm->enabled = &lsm_enabled_true;
> -	} else {
> -		*lsm->enabled = enabled;
> -	}
> -}
> -
> -/* Is an LSM already listed in the ordered LSMs list? */
> -static bool __init exists_ordered_lsm(struct lsm_info *lsm)
> -{
> -	struct lsm_info **check;
> -
> -	for (check = ordered_lsms; *check; check++)
> -		if (*check == lsm)
> -			return true;
> -
> -	return false;
> -}
> -
> -/* Append an LSM to the list of ordered LSMs to initialize. */
> -static int last_lsm __initdata;
> -static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
> -{
> -	/* Ignore duplicate selections. */
> -	if (exists_ordered_lsm(lsm))
> -		return;
> -
> -	if (WARN(last_lsm == MAX_LSM_COUNT, "%s: out of LSM static calls!?\n", from))
> -		return;
> -
> -	/* Enable this LSM, if it is not already set. */
> -	if (!lsm->enabled)
> -		lsm->enabled = &lsm_enabled_true;
> -	ordered_lsms[last_lsm++] = lsm;
> -
> -	init_debug("%s ordered: %s (%s)\n", from, lsm->name,
> -		   is_enabled(lsm) ? "enabled" : "disabled");
> -}
> -
> -/* Is an LSM allowed to be initialized? */
> -static bool __init lsm_allowed(struct lsm_info *lsm)
> -{
> -	/* Skip if the LSM is disabled. */
> -	if (!is_enabled(lsm))
> -		return false;
> -
> -	/* Not allowed if another exclusive LSM already initialized. */
> -	if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
> -		init_debug("exclusive disabled: %s\n", lsm->name);
> -		return false;
> -	}
> -
> -	return true;
> -}
> -
> -static void __init lsm_set_blob_size(int *need, int *lbs)
> -{
> -	int offset;
> -
> -	if (*need <= 0)
> -		return;
> -
> -	offset = ALIGN(*lbs, sizeof(void *));
> -	*lbs = offset + *need;
> -	*need = offset;
> -}
> -
> -static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
> -{
> -	if (!needed)
> -		return;
> -
> -	lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
> -	lsm_set_blob_size(&needed->lbs_file, &blob_sizes.lbs_file);
> -	lsm_set_blob_size(&needed->lbs_ib, &blob_sizes.lbs_ib);
> -	/*
> -	 * The inode blob gets an rcu_head in addition to
> -	 * what the modules might need.
> -	 */
> -	if (needed->lbs_inode && blob_sizes.lbs_inode == 0)
> -		blob_sizes.lbs_inode = sizeof(struct rcu_head);
> -	lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
> -	lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
> -	lsm_set_blob_size(&needed->lbs_key, &blob_sizes.lbs_key);
> -	lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
> -	lsm_set_blob_size(&needed->lbs_perf_event, &blob_sizes.lbs_perf_event);
> -	lsm_set_blob_size(&needed->lbs_sock, &blob_sizes.lbs_sock);
> -	lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
> -	lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
> -	lsm_set_blob_size(&needed->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
> -	lsm_set_blob_size(&needed->lbs_xattr_count,
> -			  &blob_sizes.lbs_xattr_count);
> -	lsm_set_blob_size(&needed->lbs_bdev, &blob_sizes.lbs_bdev);
> -}
> -
> -/* Prepare LSM for initialization. */
> -static void __init prepare_lsm(struct lsm_info *lsm)
> -{
> -	int enabled = lsm_allowed(lsm);
> -
> -	/* Record enablement (to handle any following exclusive LSMs). */
> -	set_enabled(lsm, enabled);
> -
> -	/* If enabled, do pre-initialization work. */
> -	if (enabled) {
> -		if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
> -			exclusive = lsm;
> -			init_debug("exclusive chosen:   %s\n", lsm->name);
> -		}
> -
> -		lsm_set_blob_sizes(lsm->blobs);
> -	}
> -}
> -
> -/* Initialize a given LSM, if it is enabled. */
> -static void __init initialize_lsm(struct lsm_info *lsm)
> -{
> -	if (is_enabled(lsm)) {
> -		int ret;
> -
> -		init_debug("initializing %s\n", lsm->name);
> -		ret = lsm->init();
> -		WARN(ret, "%s failed to initialize: %d\n", lsm->name, ret);
> -	}
> -}
> -
> -/*
> - * Current index to use while initializing the lsm id list.
> - */
> -u32 lsm_active_cnt __ro_after_init;
> -const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
> -
> -/* Populate ordered LSMs list from comma-separated LSM name list. */
> -static void __init ordered_lsm_parse(const char *order, const char *origin)
> -{
> -	struct lsm_info *lsm;
> -	char *sep, *name, *next;
> -
> -	/* LSM_ORDER_FIRST is always first. */
> -	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
> -		if (lsm->order == LSM_ORDER_FIRST)
> -			append_ordered_lsm(lsm, "  first");
> -	}
> -
> -	/* Process "security=", if given. */
> -	if (chosen_major_lsm) {
> -		struct lsm_info *major;
> -
> -		/*
> -		 * To match the original "security=" behavior, this
> -		 * explicitly does NOT fallback to another Legacy Major
> -		 * if the selected one was separately disabled: disable
> -		 * all non-matching Legacy Major LSMs.
> -		 */
> -		for (major = __start_lsm_info; major < __end_lsm_info;
> -		     major++) {
> -			if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
> -			    strcmp(major->name, chosen_major_lsm) != 0) {
> -				set_enabled(major, false);
> -				init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
> -					   chosen_major_lsm, major->name);
> -			}
> -		}
> -	}
> -
> -	sep = kstrdup(order, GFP_KERNEL);
> -	next = sep;
> -	/* Walk the list, looking for matching LSMs. */
> -	while ((name = strsep(&next, ",")) != NULL) {
> -		bool found = false;
> -
> -		for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
> -			if (strcmp(lsm->name, name) == 0) {
> -				if (lsm->order == LSM_ORDER_MUTABLE)
> -					append_ordered_lsm(lsm, origin);
> -				found = true;
> -			}
> -		}
> -
> -		if (!found)
> -			init_debug("%s ignored: %s (not built into kernel)\n",
> -				   origin, name);
> -	}
> -
> -	/* Process "security=", if given. */
> -	if (chosen_major_lsm) {
> -		for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
> -			if (exists_ordered_lsm(lsm))
> -				continue;
> -			if (strcmp(lsm->name, chosen_major_lsm) == 0)
> -				append_ordered_lsm(lsm, "security=");
> -		}
> -	}
> -
> -	/* LSM_ORDER_LAST is always last. */
> -	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
> -		if (lsm->order == LSM_ORDER_LAST)
> -			append_ordered_lsm(lsm, "   last");
> -	}
> -
> -	/* Disable all LSMs not in the ordered list. */
> -	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
> -		if (exists_ordered_lsm(lsm))
> -			continue;
> -		set_enabled(lsm, false);
> -		init_debug("%s skipped: %s (not in requested order)\n",
> -			   origin, lsm->name);
> -	}
> -
> -	kfree(sep);
> -}
> -
> -static void __init lsm_static_call_init(struct security_hook_list *hl)
> -{
> -	struct lsm_static_call *scall = hl->scalls;
> -	int i;
> -
> -	for (i = 0; i < MAX_LSM_COUNT; i++) {
> -		/* Update the first static call that is not used yet */
> -		if (!scall->hl) {
> -			__static_call_update(scall->key, scall->trampoline,
> -					     hl->hook.lsm_func_addr);
> -			scall->hl = hl;
> -			static_branch_enable(scall->active);
> -			return;
> -		}
> -		scall++;
> -	}
> -	panic("%s - Ran out of static slots.\n", __func__);
> -}
> -
> -static void __init lsm_early_cred(struct cred *cred);
> -static void __init lsm_early_task(struct task_struct *task);
> -
> -static int lsm_append(const char *new, char **result);
> -
> -static void __init report_lsm_order(void)
> -{
> -	struct lsm_info **lsm, *early;
> -	int first = 0;
> -
> -	pr_info("initializing lsm=");
> -
> -	/* Report each enabled LSM name, comma separated. */
> -	for (early = __start_early_lsm_info;
> -	     early < __end_early_lsm_info; early++)
> -		if (is_enabled(early))
> -			pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
> -	for (lsm = ordered_lsms; *lsm; lsm++)
> -		if (is_enabled(*lsm))
> -			pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
> -
> -	pr_cont("\n");
> -}
> -
> -static void __init ordered_lsm_init(void)
> -{
> -	struct lsm_info **lsm;
> -
> -	if (chosen_lsm_order) {
> -		if (chosen_major_lsm) {
> -			pr_warn("security=%s is ignored because it is superseded by lsm=%s\n",
> -				chosen_major_lsm, chosen_lsm_order);
> -			chosen_major_lsm = NULL;
> -		}
> -		ordered_lsm_parse(chosen_lsm_order, "cmdline");
> -	} else
> -		ordered_lsm_parse(builtin_lsm_order, "builtin");
> -
> -	for (lsm = ordered_lsms; *lsm; lsm++)
> -		prepare_lsm(*lsm);
> -
> -	report_lsm_order();
> -
> -	init_debug("cred blob size       = %d\n", blob_sizes.lbs_cred);
> -	init_debug("file blob size       = %d\n", blob_sizes.lbs_file);
> -	init_debug("ib blob size         = %d\n", blob_sizes.lbs_ib);
> -	init_debug("inode blob size      = %d\n", blob_sizes.lbs_inode);
> -	init_debug("ipc blob size        = %d\n", blob_sizes.lbs_ipc);
> -#ifdef CONFIG_KEYS
> -	init_debug("key blob size        = %d\n", blob_sizes.lbs_key);
> -#endif /* CONFIG_KEYS */
> -	init_debug("msg_msg blob size    = %d\n", blob_sizes.lbs_msg_msg);
> -	init_debug("sock blob size       = %d\n", blob_sizes.lbs_sock);
> -	init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
> -	init_debug("perf event blob size = %d\n", blob_sizes.lbs_perf_event);
> -	init_debug("task blob size       = %d\n", blob_sizes.lbs_task);
> -	init_debug("tun device blob size = %d\n", blob_sizes.lbs_tun_dev);
> -	init_debug("xattr slots          = %d\n", blob_sizes.lbs_xattr_count);
> -	init_debug("bdev blob size       = %d\n", blob_sizes.lbs_bdev);
> -
> -	/*
> -	 * Create any kmem_caches needed for blobs
> -	 */
> -	if (blob_sizes.lbs_file)
> -		lsm_file_cache = kmem_cache_create("lsm_file_cache",
> -						   blob_sizes.lbs_file, 0,
> -						   SLAB_PANIC, NULL);
> -	if (blob_sizes.lbs_inode)
> -		lsm_inode_cache = kmem_cache_create("lsm_inode_cache",
> -						    blob_sizes.lbs_inode, 0,
> -						    SLAB_PANIC, NULL);
> -
> -	lsm_early_cred((struct cred *) current->cred);
> -	lsm_early_task(current);
> -	for (lsm = ordered_lsms; *lsm; lsm++)
> -		initialize_lsm(*lsm);
> -}
> -
> -int __init early_security_init(void)
> -{
> -	struct lsm_info *lsm;
> -
> -	for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
> -		if (!lsm->enabled)
> -			lsm->enabled = &lsm_enabled_true;
> -		prepare_lsm(lsm);
> -		initialize_lsm(lsm);
> -	}
> -
> -	return 0;
> -}
> -
>   /**
> - * security_init - initializes the security framework
> + * lsm_file_alloc - allocate a composite file blob
> + * @file: the file that needs a blob
>    *
> - * This should be called early in the kernel initialization sequence.
> - */
> -int __init security_init(void)
> -{
> -	struct lsm_info *lsm;
> -
> -	init_debug("legacy security=%s\n", chosen_major_lsm ? : " *unspecified*");
> -	init_debug("  CONFIG_LSM=%s\n", builtin_lsm_order);
> -	init_debug("boot arg lsm=%s\n", chosen_lsm_order ? : " *unspecified*");
> -
> -	/*
> -	 * Append the names of the early LSM modules now that kmalloc() is
> -	 * available
> -	 */
> -	for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
> -		init_debug("  early started: %s (%s)\n", lsm->name,
> -			   is_enabled(lsm) ? "enabled" : "disabled");
> -		if (lsm->enabled)
> -			lsm_append(lsm->name, &lsm_names);
> -	}
> -
> -	/* Load LSMs in specified order. */
> -	ordered_lsm_init();
> -
> -	return 0;
> -}
> -
> -/* Save user chosen LSM */
> -static int __init choose_major_lsm(char *str)
> -{
> -	chosen_major_lsm = str;
> -	return 1;
> -}
> -__setup("security=", choose_major_lsm);
> -
> -/* Explicitly choose LSM initialization order. */
> -static int __init choose_lsm_order(char *str)
> -{
> -	chosen_lsm_order = str;
> -	return 1;
> -}
> -__setup("lsm=", choose_lsm_order);
> -
> -/* Enable LSM order debugging. */
> -static int __init enable_debug(char *str)
> -{
> -	debug = true;
> -	return 1;
> -}
> -__setup("lsm.debug", enable_debug);
> -
> -static bool match_last_lsm(const char *list, const char *lsm)
> -{
> -	const char *last;
> -
> -	if (WARN_ON(!list || !lsm))
> -		return false;
> -	last = strrchr(list, ',');
> -	if (last)
> -		/* Pass the comma, strcmp() will check for '\0' */
> -		last++;
> -	else
> -		last = list;
> -	return !strcmp(last, lsm);
> -}
> -
> -static int lsm_append(const char *new, char **result)
> -{
> -	char *cp;
> -
> -	if (*result == NULL) {
> -		*result = kstrdup(new, GFP_KERNEL);
> -		if (*result == NULL)
> -			return -ENOMEM;
> -	} else {
> -		/* Check if it is the last registered name */
> -		if (match_last_lsm(*result, new))
> -			return 0;
> -		cp = kasprintf(GFP_KERNEL, "%s,%s", *result, new);
> -		if (cp == NULL)
> -			return -ENOMEM;
> -		kfree(*result);
> -		*result = cp;
> -	}
> -	return 0;
> -}
> -
> -/**
> - * security_add_hooks - Add a modules hooks to the hook lists.
> - * @hooks: the hooks to add
> - * @count: the number of hooks to add
> - * @lsmid: the identification information for the security module
> + * Allocate the file blob for all the modules
>    *
> - * Each LSM has to register its hooks with the infrastructure.
> + * Returns 0, or -ENOMEM if memory can't be allocated.
>    */
> -void __init security_add_hooks(struct security_hook_list *hooks, int count,
> -			       const struct lsm_id *lsmid)
> +static int lsm_file_alloc(struct file *file)
>   {
> -	int i;
> -
> -	/*
> -	 * A security module may call security_add_hooks() more
> -	 * than once during initialization, and LSM initialization
> -	 * is serialized. Landlock is one such case.
> -	 * Look at the previous entry, if there is one, for duplication.
> -	 */
> -	if (lsm_active_cnt == 0 || lsm_idlist[lsm_active_cnt - 1] != lsmid) {
> -		if (lsm_active_cnt >= MAX_LSM_COUNT)
> -			panic("%s Too many LSMs registered.\n", __func__);
> -		lsm_idlist[lsm_active_cnt++] = lsmid;
> +	if (!lsm_file_cache) {
> +		file->f_security = NULL;
> +		return 0;
>   	}
>   
> -	for (i = 0; i < count; i++) {
> -		hooks[i].lsmid = lsmid;
> -		lsm_static_call_init(&hooks[i]);
> -	}
> -
> -	/*
> -	 * Don't try to append during early_security_init(), we'll come back
> -	 * and fix this up afterwards.
> -	 */
> -	if (slab_is_available()) {
> -		if (lsm_append(lsmid->name, &lsm_names) < 0)
> -			panic("%s - Cannot get early memory.\n", __func__);
> -	}
> +	file->f_security = kmem_cache_zalloc(lsm_file_cache, GFP_KERNEL);
> +	if (file->f_security == NULL)
> +		return -ENOMEM;
> +	return 0;
>   }
>   
>   /**
> @@ -673,46 +199,11 @@ static int lsm_blob_alloc(void **dest, size_t size, gfp_t gfp)
>    *
>    * Returns 0, or -ENOMEM if memory can't be allocated.
>    */
> -static int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
> +int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
>   {
>   	return lsm_blob_alloc(&cred->security, blob_sizes.lbs_cred, gfp);
>   }
>   
> -/**
> - * lsm_early_cred - during initialization allocate a composite cred blob
> - * @cred: the cred that needs a blob
> - *
> - * Allocate the cred blob for all the modules
> - */
> -static void __init lsm_early_cred(struct cred *cred)
> -{
> -	int rc = lsm_cred_alloc(cred, GFP_KERNEL);
> -
> -	if (rc)
> -		panic("%s: Early cred alloc failed.\n", __func__);
> -}
> -
> -/**
> - * lsm_file_alloc - allocate a composite file blob
> - * @file: the file that needs a blob
> - *
> - * Allocate the file blob for all the modules
> - *
> - * Returns 0, or -ENOMEM if memory can't be allocated.
> - */
> -static int lsm_file_alloc(struct file *file)
> -{
> -	if (!lsm_file_cache) {
> -		file->f_security = NULL;
> -		return 0;
> -	}
> -
> -	file->f_security = kmem_cache_zalloc(lsm_file_cache, GFP_KERNEL);
> -	if (file->f_security == NULL)
> -		return -ENOMEM;
> -	return 0;
> -}
> -
>   /**
>    * lsm_inode_alloc - allocate a composite inode blob
>    * @inode: the inode that needs a blob
> @@ -743,7 +234,7 @@ static int lsm_inode_alloc(struct inode *inode, gfp_t gfp)
>    *
>    * Returns 0, or -ENOMEM if memory can't be allocated.
>    */
> -static int lsm_task_alloc(struct task_struct *task)
> +int lsm_task_alloc(struct task_struct *task)
>   {
>   	return lsm_blob_alloc(&task->security, blob_sizes.lbs_task, GFP_KERNEL);
>   }
> @@ -812,20 +303,6 @@ static int lsm_bdev_alloc(struct block_device *bdev)
>   	return 0;
>   }
>   
> -/**
> - * lsm_early_task - during initialization allocate a composite task blob
> - * @task: the task that needs a blob
> - *
> - * Allocate the task blob for all the modules
> - */
> -static void __init lsm_early_task(struct task_struct *task)
> -{
> -	int rc = lsm_task_alloc(task);
> -
> -	if (rc)
> -		panic("%s: Early task alloc failed.\n", __func__);
> -}
> -
>   /**
>    * lsm_superblock_alloc - allocate a composite superblock blob
>    * @sb: the superblock that needs a blob


^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 03/29] lsm: simplify prepare_lsm() and rename to lsm_prep_single()
  2025-04-09 18:49 ` [RFC PATCH 03/29] lsm: simplify prepare_lsm() and rename to lsm_prep_single() Paul Moore
  2025-04-09 21:30   ` Kees Cook
@ 2025-04-15 22:10   ` John Johansen
  1 sibling, 0 replies; 126+ messages in thread
From: John Johansen @ 2025-04-15 22:10 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On 4/9/25 11:49, Paul Moore wrote:
> One part of a larger effort to cleanup the LSM framework initialization
> code.
> 

I like kees's suggestion of using enums and arrays but I think that
should be done as a separate patch. It doesn't even need to be part
of the series. Keeping the logic changes small here makes it easier
to check what the patch is doing. Then another small step ...

> Signed-off-by: Paul Moore <paul@paul-moore.com>


Reviewed-by: John Johansen <john.johansen@canonical.com>

> ---
>   security/lsm_init.c | 103 ++++++++++++++++++--------------------------
>   1 file changed, 43 insertions(+), 60 deletions(-)
> 
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 70e7d4207dae..dffa8dc2da36 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -123,22 +123,6 @@ static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
>   		   is_enabled(lsm) ? "enabled" : "disabled");
>   }
>   
> -/* Is an LSM allowed to be initialized? */
> -static bool __init lsm_allowed(struct lsm_info *lsm)
> -{
> -	/* Skip if the LSM is disabled. */
> -	if (!is_enabled(lsm))
> -		return false;
> -
> -	/* Not allowed if another exclusive LSM already initialized. */
> -	if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
> -		init_debug("exclusive disabled: %s\n", lsm->name);
> -		return false;
> -	}
> -
> -	return true;
> -}
> -
>   static void __init lsm_set_blob_size(int *need, int *lbs)
>   {
>   	int offset;
> @@ -151,51 +135,50 @@ static void __init lsm_set_blob_size(int *need, int *lbs)
>   	*need = offset;
>   }
>   
> -static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
> +/**
> + * lsm_prep_single - Prepare the LSM framework for a new LSM
> + * @lsm: LSM definition
> + */
> +static void __init lsm_prep_single(struct lsm_info *lsm)
>   {
> -	if (!needed)
> +	struct lsm_blob_sizes *blobs;
> +
> +	if (!is_enabled(lsm)) {
> +		set_enabled(lsm, false);
> +		return;
> +	} else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
> +		init_debug("exclusive disabled: %s\n", lsm->name);
> +		set_enabled(lsm, false);
>   		return;
> -
> -	lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
> -	lsm_set_blob_size(&needed->lbs_file, &blob_sizes.lbs_file);
> -	lsm_set_blob_size(&needed->lbs_ib, &blob_sizes.lbs_ib);
> -	/*
> -	 * The inode blob gets an rcu_head in addition to
> -	 * what the modules might need.
> -	 */
> -	if (needed->lbs_inode && blob_sizes.lbs_inode == 0)
> -		blob_sizes.lbs_inode = sizeof(struct rcu_head);
> -	lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
> -	lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
> -	lsm_set_blob_size(&needed->lbs_key, &blob_sizes.lbs_key);
> -	lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
> -	lsm_set_blob_size(&needed->lbs_perf_event, &blob_sizes.lbs_perf_event);
> -	lsm_set_blob_size(&needed->lbs_sock, &blob_sizes.lbs_sock);
> -	lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
> -	lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
> -	lsm_set_blob_size(&needed->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
> -	lsm_set_blob_size(&needed->lbs_xattr_count,
> -			  &blob_sizes.lbs_xattr_count);
> -	lsm_set_blob_size(&needed->lbs_bdev, &blob_sizes.lbs_bdev);
> -}
> -
> -/* Prepare LSM for initialization. */
> -static void __init prepare_lsm(struct lsm_info *lsm)
> -{
> -	int enabled = lsm_allowed(lsm);
> -
> -	/* Record enablement (to handle any following exclusive LSMs). */
> -	set_enabled(lsm, enabled);
> -
> -	/* If enabled, do pre-initialization work. */
> -	if (enabled) {
> -		if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
> -			exclusive = lsm;
> -			init_debug("exclusive chosen:   %s\n", lsm->name);
> -		}
> -
> -		lsm_set_blob_sizes(lsm->blobs);
>   	}
> +
> +	/* Mark the LSM as enabled. */
> +	set_enabled(lsm, true);
> +	if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
> +		init_debug("exclusive chosen:   %s\n", lsm->name);
> +		exclusive = lsm;
> +	}
> +
> +	/* Register the LSM blob sizes. */
> +	blobs = lsm->blobs;
> +	lsm_set_blob_size(&blobs->lbs_cred, &blob_sizes.lbs_cred);
> +	lsm_set_blob_size(&blobs->lbs_file, &blob_sizes.lbs_file);
> +	lsm_set_blob_size(&blobs->lbs_ib, &blob_sizes.lbs_ib);
> +	/* inode blob gets an rcu_head in addition to LSM blobs. */
> +	if (blobs->lbs_inode && blob_sizes.lbs_inode == 0)
> +		blob_sizes.lbs_inode = sizeof(struct rcu_head);
> +	lsm_set_blob_size(&blobs->lbs_inode, &blob_sizes.lbs_inode);
> +	lsm_set_blob_size(&blobs->lbs_ipc, &blob_sizes.lbs_ipc);
> +	lsm_set_blob_size(&blobs->lbs_key, &blob_sizes.lbs_key);
> +	lsm_set_blob_size(&blobs->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
> +	lsm_set_blob_size(&blobs->lbs_perf_event, &blob_sizes.lbs_perf_event);
> +	lsm_set_blob_size(&blobs->lbs_sock, &blob_sizes.lbs_sock);
> +	lsm_set_blob_size(&blobs->lbs_superblock, &blob_sizes.lbs_superblock);
> +	lsm_set_blob_size(&blobs->lbs_task, &blob_sizes.lbs_task);
> +	lsm_set_blob_size(&blobs->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
> +	lsm_set_blob_size(&blobs->lbs_xattr_count,
> +			  &blob_sizes.lbs_xattr_count);
> +	lsm_set_blob_size(&blobs->lbs_bdev, &blob_sizes.lbs_bdev);
>   }
>   
>   /* Initialize a given LSM, if it is enabled. */
> @@ -358,7 +341,7 @@ static void __init ordered_lsm_init(void)
>   		ordered_lsm_parse(builtin_lsm_order, "builtin");
>   
>   	for (lsm = ordered_lsms; *lsm; lsm++)
> -		prepare_lsm(*lsm);
> +		lsm_prep_single(*lsm);
>   
>   	report_lsm_order();
>   
> @@ -499,7 +482,7 @@ int __init early_security_init(void)
>   	for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
>   		if (!lsm->enabled)
>   			lsm->enabled = &lsm_enabled_true;
> -		prepare_lsm(lsm);
> +		lsm_prep_single(lsm);
>   		initialize_lsm(lsm);
>   	}
>   


^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 05/29] lsm: replace the name field with a pointer to the lsm_id struct
  2025-04-09 18:49 ` [RFC PATCH 05/29] lsm: replace the name field with a pointer to the lsm_id struct Paul Moore
  2025-04-09 21:40   ` Kees Cook
@ 2025-04-15 22:20   ` John Johansen
  1 sibling, 0 replies; 126+ messages in thread
From: John Johansen @ 2025-04-15 22:20 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On 4/9/25 11:49, Paul Moore wrote:
> Reduce the duplication between the lsm_id struct and the DEFINE_LSM()
> definition by linking the lsm_id struct directly into the individual
> LSM's DEFINE_LSM() instance.
> 
> Linking the lsm_id into the LSM definition also allows us to simplify
> the security_add_hooks() function by removing the code which populates
> the lsm_idlist[] array and moving it into the normal LSM startup code
> where the LSM list is parsed and the individual LSMs are enabled,
> making for a cleaner implementation with less overhead at boot.
> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>


Reviewed-by: John Johansen <john.johansen@canonical.com>

> ---
>   include/linux/lsm_hooks.h         |  2 +-
>   security/apparmor/lsm.c           |  2 +-
>   security/bpf/hooks.c              |  2 +-
>   security/commoncap.c              |  2 +-
>   security/integrity/evm/evm_main.c |  2 +-
>   security/integrity/ima/ima_main.c |  2 +-
>   security/ipe/ipe.c                |  2 +-
>   security/landlock/setup.c         |  2 +-
>   security/loadpin/loadpin.c        |  2 +-
>   security/lockdown/lockdown.c      |  2 +-
>   security/lsm_init.c               | 43 ++++++++++++-------------------
>   security/safesetid/lsm.c          |  2 +-
>   security/selinux/hooks.c          |  2 +-
>   security/smack/smack_lsm.c        |  2 +-
>   security/tomoyo/tomoyo.c          |  2 +-
>   security/yama/yama_lsm.c          |  2 +-
>   16 files changed, 31 insertions(+), 42 deletions(-)
> 
> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
> index eeb4bfd60b79..4cd17c9a229f 100644
> --- a/include/linux/lsm_hooks.h
> +++ b/include/linux/lsm_hooks.h
> @@ -149,7 +149,7 @@ enum lsm_order {
>   };
>   
>   struct lsm_info {
> -	const char *name;	/* Required. */
> +	const struct lsm_id *id;
>   	enum lsm_order order;	/* Optional: default is LSM_ORDER_MUTABLE */
>   	unsigned long flags;	/* Optional: flags describing LSM */
>   	int *enabled;		/* Optional: controlled by CONFIG_LSM */
> diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
> index 9b6c2f157f83..a7f6a3274682 100644
> --- a/security/apparmor/lsm.c
> +++ b/security/apparmor/lsm.c
> @@ -2272,7 +2272,7 @@ static int __init apparmor_init(void)
>   }
>   
>   DEFINE_LSM(apparmor) = {
> -	.name = "apparmor",
> +	.id = &apparmor_lsmid,
>   	.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
>   	.enabled = &apparmor_enabled,
>   	.blobs = &apparmor_blob_sizes,
> diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c
> index db759025abe1..40efde233f3a 100644
> --- a/security/bpf/hooks.c
> +++ b/security/bpf/hooks.c
> @@ -33,7 +33,7 @@ struct lsm_blob_sizes bpf_lsm_blob_sizes __ro_after_init = {
>   };
>   
>   DEFINE_LSM(bpf) = {
> -	.name = "bpf",
> +	.id = &bpf_lsmid,
>   	.init = bpf_lsm_init,
>   	.blobs = &bpf_lsm_blob_sizes
>   };
> diff --git a/security/commoncap.c b/security/commoncap.c
> index 28d4248bf001..e04aa4f50eaf 100644
> --- a/security/commoncap.c
> +++ b/security/commoncap.c
> @@ -1509,7 +1509,7 @@ static int __init capability_init(void)
>   }
>   
>   DEFINE_LSM(capability) = {
> -	.name = "capability",
> +	.id = &capability_lsmid,
>   	.order = LSM_ORDER_FIRST,
>   	.init = capability_init,
>   };
> diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
> index 0add782e73ba..db8e324ed4e6 100644
> --- a/security/integrity/evm/evm_main.c
> +++ b/security/integrity/evm/evm_main.c
> @@ -1175,7 +1175,7 @@ struct lsm_blob_sizes evm_blob_sizes __ro_after_init = {
>   };
>   
>   DEFINE_LSM(evm) = {
> -	.name = "evm",
> +	.id = &evm_lsmid,
>   	.init = init_evm_lsm,
>   	.order = LSM_ORDER_LAST,
>   	.blobs = &evm_blob_sizes,
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index f3e7ac513db3..55a4f08a2565 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -1251,7 +1251,7 @@ struct lsm_blob_sizes ima_blob_sizes __ro_after_init = {
>   };
>   
>   DEFINE_LSM(ima) = {
> -	.name = "ima",
> +	.id = &ima_lsmid,
>   	.init = init_ima_lsm,
>   	.order = LSM_ORDER_LAST,
>   	.blobs = &ima_blob_sizes,
> diff --git a/security/ipe/ipe.c b/security/ipe/ipe.c
> index 4317134cb0da..2426441181dc 100644
> --- a/security/ipe/ipe.c
> +++ b/security/ipe/ipe.c
> @@ -92,7 +92,7 @@ static int __init ipe_init(void)
>   }
>   
>   DEFINE_LSM(ipe) = {
> -	.name = "ipe",
> +	.id = &ipe_lsmid,
>   	.init = ipe_init,
>   	.blobs = &ipe_blobs,
>   };
> diff --git a/security/landlock/setup.c b/security/landlock/setup.c
> index bd53c7a56ab9..47dac1736f10 100644
> --- a/security/landlock/setup.c
> +++ b/security/landlock/setup.c
> @@ -75,7 +75,7 @@ static int __init landlock_init(void)
>   }
>   
>   DEFINE_LSM(LANDLOCK_NAME) = {
> -	.name = LANDLOCK_NAME,
> +	.id = &landlock_lsmid,
>   	.init = landlock_init,
>   	.blobs = &landlock_blob_sizes,
>   };
> diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c
> index 68252452b66c..b9ddf05c5c16 100644
> --- a/security/loadpin/loadpin.c
> +++ b/security/loadpin/loadpin.c
> @@ -271,7 +271,7 @@ static int __init loadpin_init(void)
>   }
>   
>   DEFINE_LSM(loadpin) = {
> -	.name = "loadpin",
> +	.id = &loadpin_lsmid,
>   	.init = loadpin_init,
>   };
>   
> diff --git a/security/lockdown/lockdown.c b/security/lockdown/lockdown.c
> index cf83afa1d879..4813f168ff93 100644
> --- a/security/lockdown/lockdown.c
> +++ b/security/lockdown/lockdown.c
> @@ -168,6 +168,6 @@ DEFINE_EARLY_LSM(lockdown) = {
>   #else
>   DEFINE_LSM(lockdown) = {
>   #endif
> -	.name = "lockdown",
> +	.id = &lockdown_lsmid,
>   	.init = lockdown_lsm_init,
>   };
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 407429688f1b..d458a365b0d5 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -124,9 +124,10 @@ static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
>   	/* Enable this LSM, if it is not already set. */
>   	if (!lsm->enabled)
>   		lsm->enabled = &lsm_enabled_true;
> -	ordered_lsms[last_lsm++] = lsm;
> +	ordered_lsms[last_lsm] = lsm;
> +	lsm_idlist[last_lsm++] = lsm->id;
>   
> -	init_debug("%s ordered: %s (%s)\n", from, lsm->name,
> +	init_debug("%s ordered: %s (%s)\n", from, lsm->id->name,
>   		   is_enabled(lsm) ? "enabled" : "disabled");
>   }
>   
> @@ -154,7 +155,7 @@ static void __init lsm_prep_single(struct lsm_info *lsm)
>   		set_enabled(lsm, false);
>   		return;
>   	} else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
> -		init_debug("exclusive disabled: %s\n", lsm->name);
> +		init_debug("exclusive disabled: %s\n", lsm->id->name);
>   		set_enabled(lsm, false);
>   		return;
>   	}
> @@ -162,7 +163,7 @@ static void __init lsm_prep_single(struct lsm_info *lsm)
>   	/* Mark the LSM as enabled. */
>   	set_enabled(lsm, true);
>   	if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
> -		init_debug("exclusive chosen:   %s\n", lsm->name);
> +		init_debug("exclusive chosen:   %s\n", lsm->id->name);
>   		exclusive = lsm;
>   	}
>   
> @@ -194,9 +195,9 @@ static void __init initialize_lsm(struct lsm_info *lsm)
>   	if (is_enabled(lsm)) {
>   		int ret;
>   
> -		init_debug("initializing %s\n", lsm->name);
> +		init_debug("initializing %s\n", lsm->id->name);
>   		ret = lsm->init();
> -		WARN(ret, "%s failed to initialize: %d\n", lsm->name, ret);
> +		WARN(ret, "%s failed to initialize: %d\n", lsm->id->name, ret);
>   	}
>   }
>   
> @@ -231,10 +232,10 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
>   		for (major = __start_lsm_info; major < __end_lsm_info;
>   		     major++) {
>   			if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
> -			    strcmp(major->name, chosen_major_lsm) != 0) {
> +			    strcmp(major->id->name, chosen_major_lsm) != 0) {
>   				set_enabled(major, false);
>   				init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
> -					   chosen_major_lsm, major->name);
> +					   chosen_major_lsm, major->id->name);
>   			}
>   		}
>   	}
> @@ -246,7 +247,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
>   		bool found = false;
>   
>   		for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
> -			if (strcmp(lsm->name, name) == 0) {
> +			if (strcmp(lsm->id->name, name) == 0) {
>   				if (lsm->order == LSM_ORDER_MUTABLE)
>   					append_ordered_lsm(lsm, origin);
>   				found = true;
> @@ -263,7 +264,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
>   		for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
>   			if (exists_ordered_lsm(lsm))
>   				continue;
> -			if (strcmp(lsm->name, chosen_major_lsm) == 0)
> +			if (strcmp(lsm->id->name, chosen_major_lsm) == 0)
>   				append_ordered_lsm(lsm, "security=");
>   		}
>   	}
> @@ -280,7 +281,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
>   			continue;
>   		set_enabled(lsm, false);
>   		init_debug("%s skipped: %s (not in requested order)\n",
> -			   origin, lsm->name);
> +			   origin, lsm->id->name);
>   	}
>   
>   	kfree(sep);
> @@ -313,12 +314,12 @@ static void __init lsm_init_ordered(void)
>   		if (is_enabled(early))
>   			pr_cont("%s%s",
>   				early == __start_early_lsm_info ? "" : ",",
> -				early->name);
> +				early->id->name);
>   	}
>   	lsm_order_for_each(lsm) {
>   		if (is_enabled(*lsm))
>   			pr_cont("%s%s",
> -				lsm == ordered_lsms ? "" : ",", (*lsm)->name);
> +				lsm == ordered_lsms ? "" : ",", (*lsm)->id->name);
>   	}
>   	pr_cont("\n");
>   
> @@ -426,18 +427,6 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
>   {
>   	int i;
>   
> -	/*
> -	 * A security module may call security_add_hooks() more
> -	 * than once during initialization, and LSM initialization
> -	 * is serialized. Landlock is one such case.
> -	 * Look at the previous entry, if there is one, for duplication.
> -	 */
> -	if (lsm_active_cnt == 0 || lsm_idlist[lsm_active_cnt - 1] != lsmid) {
> -		if (lsm_active_cnt >= MAX_LSM_COUNT)
> -			panic("%s Too many LSMs registered.\n", __func__);
> -		lsm_idlist[lsm_active_cnt++] = lsmid;
> -	}
> -
>   	for (i = 0; i < count; i++) {
>   		hooks[i].lsmid = lsmid;
>   		lsm_static_call_init(&hooks[i]);
> @@ -485,10 +474,10 @@ int __init security_init(void)
>   	 * available
>   	 */
>   	lsm_early_for_each_raw(lsm) {
> -		init_debug("  early started: %s (%s)\n", lsm->name,
> +		init_debug("  early started: %s (%s)\n", lsm->id->name,
>   			   is_enabled(lsm) ? "enabled" : "disabled");
>   		if (lsm->enabled)
> -			lsm_append(lsm->name, &lsm_names);
> +			lsm_append(lsm->id->name, &lsm_names);
>   	}
>   
>   	/* Load LSMs in specified order. */
> diff --git a/security/safesetid/lsm.c b/security/safesetid/lsm.c
> index 1ba564f097f5..9a7c68d4e642 100644
> --- a/security/safesetid/lsm.c
> +++ b/security/safesetid/lsm.c
> @@ -287,6 +287,6 @@ static int __init safesetid_security_init(void)
>   }
>   
>   DEFINE_LSM(safesetid_security_init) = {
> +	.id = &safesetid_lsmid,
>   	.init = safesetid_security_init,
> -	.name = "safesetid",
>   };
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index e7a7dcab81db..f28a12a0a1c8 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -7562,7 +7562,7 @@ void selinux_complete_init(void)
>   /* SELinux requires early initialization in order to label
>      all processes and objects when they are created. */
>   DEFINE_LSM(selinux) = {
> -	.name = "selinux",
> +	.id = &selinux_lsmid,
>   	.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
>   	.enabled = &selinux_enabled_boot,
>   	.blobs = &selinux_blob_sizes,
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index 99833168604e..e09b33fed5f0 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -5282,7 +5282,7 @@ static __init int smack_init(void)
>    * all processes and objects when they are created.
>    */
>   DEFINE_LSM(smack) = {
> -	.name = "smack",
> +	.id = &smack_lsmid,
>   	.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
>   	.blobs = &smack_blob_sizes,
>   	.init = smack_init,
> diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
> index d6ebcd9db80a..ed0f7b052a85 100644
> --- a/security/tomoyo/tomoyo.c
> +++ b/security/tomoyo/tomoyo.c
> @@ -612,7 +612,7 @@ static int __init tomoyo_init(void)
>   }
>   
>   DEFINE_LSM(tomoyo) = {
> -	.name = "tomoyo",
> +	.id = &tomoyo_lsmid,
>   	.enabled = &tomoyo_enabled,
>   	.flags = LSM_FLAG_LEGACY_MAJOR,
>   	.blobs = &tomoyo_blob_sizes,
> diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c
> index 3d064dd4e03f..38b21ee0c560 100644
> --- a/security/yama/yama_lsm.c
> +++ b/security/yama/yama_lsm.c
> @@ -476,6 +476,6 @@ static int __init yama_init(void)
>   }
>   
>   DEFINE_LSM(yama) = {
> -	.name = "yama",
> +	.id = &yama_lsmid,
>   	.init = yama_init,
>   };


^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 06/29] lsm: cleanup and normalize the LSM order symbols naming
  2025-04-09 18:49 ` [RFC PATCH 06/29] lsm: cleanup and normalize the LSM order symbols naming Paul Moore
  2025-04-09 23:00   ` Kees Cook
@ 2025-04-15 22:23   ` John Johansen
  1 sibling, 0 replies; 126+ messages in thread
From: John Johansen @ 2025-04-15 22:23 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On 4/9/25 11:49, Paul Moore wrote:
> One part of a larger effort to cleanup the LSM framework initialization
> code.
> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>

with the commit message updates already brought up, code looks good

Reviewed-by: John Johansen <john.johansen@canonical.com>

> ---
>   security/lsm_init.c | 88 +++++++++++++++++++++++++--------------------
>   1 file changed, 49 insertions(+), 39 deletions(-)
> 
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index d458a365b0d5..edf2f4140eaa 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -16,14 +16,14 @@ char *lsm_names;
>   extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
>   extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
>   
> -/* Boot-time LSM user choice */
> -static __initconst const char *const builtin_lsm_order = CONFIG_LSM;
> -static __initdata const char *chosen_lsm_order;
> -static __initdata const char *chosen_major_lsm;
> +/* Build and boot-time LSM ordering. */
> +static __initconst const char *const lsm_order_builtin = CONFIG_LSM;
> +static __initdata const char *lsm_order_cmdline;
> +static __initdata const char *lsm_order_legacy;
>   
>   /* Ordered list of LSMs to initialize. */
> -static __initdata struct lsm_info *ordered_lsms[MAX_LSM_COUNT + 1];
> -static __initdata struct lsm_info *exclusive;
> +static __initdata struct lsm_info *lsm_order[MAX_LSM_COUNT + 1];
> +static __initdata struct lsm_info *lsm_exclusive;
>   
>   static __initdata bool debug;
>   #define init_debug(...)							\
> @@ -33,36 +33,46 @@ static __initdata bool debug;
>   	} while (0)
>   
>   #define lsm_order_for_each(iter)					\
> -	for ((iter) = ordered_lsms; *(iter); (iter)++)
> +	for ((iter) = lsm_order; *(iter); (iter)++)
>   #define lsm_early_for_each_raw(iter)					\
>   	for ((iter) = __start_early_lsm_info;				\
>   	     (iter) < __end_early_lsm_info; (iter)++)
>   
> -static int lsm_append(const char *new, char **result);
> -
> -/* Save user chosen LSM */
> -static int __init choose_major_lsm(char *str)
> +/**
> + * lsm_choose_security - Legacy "major" LSM selection
> + * @str: kernel command line parameter
> + */
> +static int __init lsm_choose_security(char *str)
>   {
> -	chosen_major_lsm = str;
> +	lsm_order_legacy = str;
>   	return 1;
>   }
> -__setup("security=", choose_major_lsm);
> +__setup("security=", lsm_choose_security);
>   
> -/* Explicitly choose LSM initialization order. */
> -static int __init choose_lsm_order(char *str)
> +/**
> + * lsm_choose_lsm - Modern LSM selection
> + * @str: kernel command line parameter
> + */
> +static int __init lsm_choose_lsm(char *str)
>   {
> -	chosen_lsm_order = str;
> +	lsm_order_cmdline = str;
>   	return 1;
>   }
> -__setup("lsm=", choose_lsm_order);
> +__setup("lsm=", lsm_choose_lsm);
>   
> -/* Enable LSM order debugging. */
> -static int __init enable_debug(char *str)
> +/**
> + * lsm_debug_enable - Enable LSM framework debugging
> + * @str: kernel command line parameter
> + *
> + * Currently we only provide debug info during LSM initialization, but we may
> + * want to expand this in the future.
> + */
> +static int __init lsm_debug_enable(char *str)
>   {
>   	debug = true;
>   	return 1;
>   }
> -__setup("lsm.debug", enable_debug);
> +__setup("lsm.debug", lsm_debug_enable);
>   
>   /* Mark an LSM's enabled flag. */
>   static int lsm_enabled_true __initdata = 1;
> @@ -124,7 +134,7 @@ static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
>   	/* Enable this LSM, if it is not already set. */
>   	if (!lsm->enabled)
>   		lsm->enabled = &lsm_enabled_true;
> -	ordered_lsms[last_lsm] = lsm;
> +	lsm_order[last_lsm] = lsm;
>   	lsm_idlist[last_lsm++] = lsm->id;
>   
>   	init_debug("%s ordered: %s (%s)\n", from, lsm->id->name,
> @@ -154,7 +164,7 @@ static void __init lsm_prep_single(struct lsm_info *lsm)
>   	if (!is_enabled(lsm)) {
>   		set_enabled(lsm, false);
>   		return;
> -	} else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
> +	} else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && lsm_exclusive) {
>   		init_debug("exclusive disabled: %s\n", lsm->id->name);
>   		set_enabled(lsm, false);
>   		return;
> @@ -162,9 +172,9 @@ static void __init lsm_prep_single(struct lsm_info *lsm)
>   
>   	/* Mark the LSM as enabled. */
>   	set_enabled(lsm, true);
> -	if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
> +	if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !lsm_exclusive) {
>   		init_debug("exclusive chosen:   %s\n", lsm->id->name);
> -		exclusive = lsm;
> +		lsm_exclusive = lsm;
>   	}
>   
>   	/* Register the LSM blob sizes. */
> @@ -220,7 +230,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
>   	}
>   
>   	/* Process "security=", if given. */
> -	if (chosen_major_lsm) {
> +	if (lsm_order_legacy) {
>   		struct lsm_info *major;
>   
>   		/*
> @@ -232,10 +242,10 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
>   		for (major = __start_lsm_info; major < __end_lsm_info;
>   		     major++) {
>   			if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
> -			    strcmp(major->id->name, chosen_major_lsm) != 0) {
> +			    strcmp(major->id->name, lsm_order_legacy) != 0) {
>   				set_enabled(major, false);
>   				init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
> -					   chosen_major_lsm, major->id->name);
> +					   lsm_order_legacy, major->id->name);
>   			}
>   		}
>   	}
> @@ -260,11 +270,11 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
>   	}
>   
>   	/* Process "security=", if given. */
> -	if (chosen_major_lsm) {
> +	if (lsm_order_legacy) {
>   		for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
>   			if (exists_ordered_lsm(lsm))
>   				continue;
> -			if (strcmp(lsm->id->name, chosen_major_lsm) == 0)
> +			if (strcmp(lsm->id->name, lsm_order_legacy) == 0)
>   				append_ordered_lsm(lsm, "security=");
>   		}
>   	}
> @@ -295,15 +305,15 @@ static void __init lsm_init_ordered(void)
>   	struct lsm_info **lsm;
>   	struct lsm_info *early;
>   
> -	if (chosen_lsm_order) {
> -		if (chosen_major_lsm) {
> +	if (lsm_order_cmdline) {
> +		if (lsm_order_legacy) {
>   			pr_warn("security=%s is ignored because it is superseded by lsm=%s\n",
> -				chosen_major_lsm, chosen_lsm_order);
> -			chosen_major_lsm = NULL;
> +				lsm_order_legacy, lsm_order_cmdline);
> +			lsm_order_legacy = NULL;
>   		}
> -		ordered_lsm_parse(chosen_lsm_order, "cmdline");
> +		ordered_lsm_parse(lsm_order_cmdline, "cmdline");
>   	} else
> -		ordered_lsm_parse(builtin_lsm_order, "builtin");
> +		ordered_lsm_parse(lsm_order_builtin, "builtin");
>   
>   	lsm_order_for_each(lsm) {
>   		lsm_prep_single(*lsm);
> @@ -319,7 +329,7 @@ static void __init lsm_init_ordered(void)
>   	lsm_order_for_each(lsm) {
>   		if (is_enabled(*lsm))
>   			pr_cont("%s%s",
> -				lsm == ordered_lsms ? "" : ",", (*lsm)->id->name);
> +				lsm == lsm_order ? "" : ",", (*lsm)->id->name);
>   	}
>   	pr_cont("\n");
>   
> @@ -465,9 +475,9 @@ int __init security_init(void)
>   {
>   	struct lsm_info *lsm;
>   
> -	init_debug("legacy security=%s\n", chosen_major_lsm ? : " *unspecified*");
> -	init_debug("  CONFIG_LSM=%s\n", builtin_lsm_order);
> -	init_debug("boot arg lsm=%s\n", chosen_lsm_order ? : " *unspecified*");
> +	init_debug("legacy security=%s\n", lsm_order_legacy ? : " *unspecified*");
> +	init_debug("  CONFIG_LSM=%s\n", lsm_order_builtin);
> +	init_debug("boot arg lsm=%s\n", lsm_order_cmdline ? : " *unspecified*");
>   
>   	/*
>   	 * Append the names of the early LSM modules now that kmalloc() is


^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 08/29] lsm: get rid of the lsm_names list and do some cleanup
  2025-04-10 22:47     ` Paul Moore
  2025-04-11  2:15       ` Kees Cook
@ 2025-04-15 22:30       ` John Johansen
  1 sibling, 0 replies; 126+ messages in thread
From: John Johansen @ 2025-04-15 22:30 UTC (permalink / raw)
  To: Paul Moore, Kees Cook
  Cc: linux-security-module, linux-integrity, selinux, Mimi Zohar,
	Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Micah Morton, Casey Schaufler, Tetsuo Handa

On 4/10/25 15:47, Paul Moore wrote:
> On Wed, Apr 9, 2025 at 7:13 PM Kees Cook <kees@kernel.org> wrote:
>>
>> On Wed, Apr 09, 2025 at 02:49:53PM -0400, Paul Moore wrote:
>>> The LSM currently has a lot of code to maintain a list of the
>>> currently active LSMs in a human readable string, with the only
>>> user being the "/sys/kernel/security/lsm" code.  Let's drop all
>>> of that code and generate the string on an as-needed basis when
>>> userspace reads "/sys/kernel/security/lsm".
>>>
>>> Signed-off-by: Paul Moore <paul@paul-moore.com>
>>> ---
>>>   include/linux/lsm_hooks.h |  1 -
>>>   security/inode.c          | 27 +++++++++++++++++++--
>>>   security/lsm_init.c       | 49 ---------------------------------------
>>>   3 files changed, 25 insertions(+), 52 deletions(-)
> 
> ...
> 
>>> @@ -343,8 +345,29 @@ static struct dentry *lsm_dentry;
>>>   static ssize_t lsm_read(struct file *filp, char __user *buf, size_t count,
>>>                        loff_t *ppos)
>>>   {
>>> -     return simple_read_from_buffer(buf, count, ppos, lsm_names,
>>> -             strlen(lsm_names));
>>> +     int i;
>>> +     char *str;
>>> +     ssize_t rc, len = 0;
>>> +
>>> +     for (i = 0; i < lsm_count; i++)
>>> +             /* the '+ 1' accounts for either a comma or a NUL terminator */
>>> +             len += strlen(lsm_order[i]->id->name) + 1;
>>> +
>>> +     str = kmalloc(len, GFP_KERNEL);
>>> +     if (!str)
>>> +             return -ENOMEM;
>>> +     str[0] = '\0';
>>> +
>>> +     i = 0;
>>> +     while (i < lsm_count) {
>>> +             strcat(str, lsm_order[i]->id->name);
>>> +             if (++i < lsm_count)
>>> +                     strcat(str, ",");
>>> +     }
>>> +
>>> +     rc = simple_read_from_buffer(buf, count, ppos, str, len);
>>> +     kfree(str);
>>> +     return rc;
>>
>> Hrm, at least cache it?
> 
> Are you aware of a performance critical use of this?
> 
no I can't see anything performance critical, I think it just is cleaner
to only generate once if after init the list doesn't change.

>> Better yet, do this whole thing in a initcall after LSMs are loaded, and
>> both can gain __ro_after_init...
> 
> I *really* disliked all the stuff we were having to do during boot,
> and all the redundant global state we were keeping around.  I'll go
> ahead and cache the lsm_read() result local to the function but that's
> probably all I'm going to accept at this point in time.
> 
fair, I don't even think this needs to be changed, I think kees's suggestion
is more of a nice to have


^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 10/29] lsm: cleanup the LSM blob size code
  2025-04-09 18:49 ` [RFC PATCH 10/29] lsm: cleanup the LSM blob size code Paul Moore
  2025-04-09 23:29   ` Kees Cook
@ 2025-04-15 23:02   ` John Johansen
  2025-04-19  2:42   ` Fan Wu
  2 siblings, 0 replies; 126+ messages in thread
From: John Johansen @ 2025-04-15 23:02 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On 4/9/25 11:49, Paul Moore wrote:
> Convert the lsm_blob_size fields to unsigned integers as there is no
> current need for them to be negative, change "lsm_set_blob_size()" to
> "lsm_blob_size_update()" to better reflect reality, and perform some
> other minor cleanups to the associated code.
> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>

Reviewed-by: John Johansen <john.johansen@canonical.com>

> ---
>   include/linux/lsm_hooks.h | 28 +++++++++++-----------
>   security/lsm_init.c       | 50 +++++++++++++++++++++++----------------
>   2 files changed, 43 insertions(+), 35 deletions(-)
> 
> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
> index bc477fb20d02..a7ecb0791a0f 100644
> --- a/include/linux/lsm_hooks.h
> +++ b/include/linux/lsm_hooks.h
> @@ -102,20 +102,20 @@ struct security_hook_list {
>    * Security blob size or offset data.
>    */
>   struct lsm_blob_sizes {
> -	int lbs_cred;
> -	int lbs_file;
> -	int lbs_ib;
> -	int lbs_inode;
> -	int lbs_sock;
> -	int lbs_superblock;
> -	int lbs_ipc;
> -	int lbs_key;
> -	int lbs_msg_msg;
> -	int lbs_perf_event;
> -	int lbs_task;
> -	int lbs_xattr_count; /* number of xattr slots in new_xattrs array */
> -	int lbs_tun_dev;
> -	int lbs_bdev;
> +	unsigned int lbs_cred;
> +	unsigned int lbs_file;
> +	unsigned int lbs_ib;
> +	unsigned int lbs_inode;
> +	unsigned int lbs_sock;
> +	unsigned int lbs_superblock;
> +	unsigned int lbs_ipc;
> +	unsigned int lbs_key;
> +	unsigned int lbs_msg_msg;
> +	unsigned int lbs_perf_event;
> +	unsigned int lbs_task;
> +	unsigned int lbs_xattr_count; /* num xattr slots in new_xattrs array */
> +	unsigned int lbs_tun_dev;
> +	unsigned int lbs_bdev;
>   };
>   
>   /*
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 7f2bc8c22ce9..9bb4b4fc9888 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -148,16 +148,22 @@ static void __init lsm_order_append(struct lsm_info *lsm, const char *src)
>   		   lsm_is_enabled(lsm) ? "enabled" : "disabled");
>   }
>   
> -static void __init lsm_set_blob_size(int *need, int *lbs)
> +/**
> + * lsm_blob_size_update - Update the LSM blob size and offset information
> + * @sz_req: the requested additional blob size
> + * @sz_cur: the existing blob size
> + */
> +static void __init lsm_blob_size_update(unsigned int *sz_req,
> +					unsigned int *sz_cur)
>   {
> -	int offset;
> +	unsigned int offset;
>   
> -	if (*need <= 0)
> +	if (*sz_req == 0)
>   		return;
>   
> -	offset = ALIGN(*lbs, sizeof(void *));
> -	*lbs = offset + *need;
> -	*need = offset;
> +	offset = ALIGN(*sz_cur, sizeof(void *));
> +	*sz_cur = offset + *sz_req;
> +	*sz_req = offset;
>   }
>   
>   /**
> @@ -186,24 +192,26 @@ static void __init lsm_prep_single(struct lsm_info *lsm)
>   
>   	/* Register the LSM blob sizes. */
>   	blobs = lsm->blobs;
> -	lsm_set_blob_size(&blobs->lbs_cred, &blob_sizes.lbs_cred);
> -	lsm_set_blob_size(&blobs->lbs_file, &blob_sizes.lbs_file);
> -	lsm_set_blob_size(&blobs->lbs_ib, &blob_sizes.lbs_ib);
> +	lsm_blob_size_update(&blobs->lbs_cred, &blob_sizes.lbs_cred);
> +	lsm_blob_size_update(&blobs->lbs_file, &blob_sizes.lbs_file);
> +	lsm_blob_size_update(&blobs->lbs_ib, &blob_sizes.lbs_ib);
>   	/* inode blob gets an rcu_head in addition to LSM blobs. */
>   	if (blobs->lbs_inode && blob_sizes.lbs_inode == 0)
>   		blob_sizes.lbs_inode = sizeof(struct rcu_head);
> -	lsm_set_blob_size(&blobs->lbs_inode, &blob_sizes.lbs_inode);
> -	lsm_set_blob_size(&blobs->lbs_ipc, &blob_sizes.lbs_ipc);
> -	lsm_set_blob_size(&blobs->lbs_key, &blob_sizes.lbs_key);
> -	lsm_set_blob_size(&blobs->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
> -	lsm_set_blob_size(&blobs->lbs_perf_event, &blob_sizes.lbs_perf_event);
> -	lsm_set_blob_size(&blobs->lbs_sock, &blob_sizes.lbs_sock);
> -	lsm_set_blob_size(&blobs->lbs_superblock, &blob_sizes.lbs_superblock);
> -	lsm_set_blob_size(&blobs->lbs_task, &blob_sizes.lbs_task);
> -	lsm_set_blob_size(&blobs->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
> -	lsm_set_blob_size(&blobs->lbs_xattr_count,
> -			  &blob_sizes.lbs_xattr_count);
> -	lsm_set_blob_size(&blobs->lbs_bdev, &blob_sizes.lbs_bdev);
> +	lsm_blob_size_update(&blobs->lbs_inode, &blob_sizes.lbs_inode);
> +	lsm_blob_size_update(&blobs->lbs_ipc, &blob_sizes.lbs_ipc);
> +	lsm_blob_size_update(&blobs->lbs_key, &blob_sizes.lbs_key);
> +	lsm_blob_size_update(&blobs->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
> +	lsm_blob_size_update(&blobs->lbs_perf_event,
> +			     &blob_sizes.lbs_perf_event);
> +	lsm_blob_size_update(&blobs->lbs_sock, &blob_sizes.lbs_sock);
> +	lsm_blob_size_update(&blobs->lbs_superblock,
> +			     &blob_sizes.lbs_superblock);
> +	lsm_blob_size_update(&blobs->lbs_task, &blob_sizes.lbs_task);
> +	lsm_blob_size_update(&blobs->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
> +	lsm_blob_size_update(&blobs->lbs_xattr_count,
> +			     &blob_sizes.lbs_xattr_count);
> +	lsm_blob_size_update(&blobs->lbs_bdev, &blob_sizes.lbs_bdev);
>   }
>   
>   /* Initialize a given LSM, if it is enabled. */


^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 11/29] lsm: cleanup initialize_lsm() and rename to lsm_init_single()
  2025-04-09 18:49 ` [RFC PATCH 11/29] lsm: cleanup initialize_lsm() and rename to lsm_init_single() Paul Moore
  2025-04-09 23:30   ` Kees Cook
@ 2025-04-15 23:04   ` John Johansen
  1 sibling, 0 replies; 126+ messages in thread
From: John Johansen @ 2025-04-15 23:04 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On 4/9/25 11:49, Paul Moore wrote:
> One part of a larger effort to cleanup the LSM framework initialization
> code.
> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>


Reviewed-by: John Johansen <john.johansen@canonical.com>

> ---
>   security/lsm_init.c | 24 ++++++++++++++----------
>   1 file changed, 14 insertions(+), 10 deletions(-)
> 
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 9bb4b4fc9888..163fc2a1a952 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -214,16 +214,20 @@ static void __init lsm_prep_single(struct lsm_info *lsm)
>   	lsm_blob_size_update(&blobs->lbs_bdev, &blob_sizes.lbs_bdev);
>   }
>   
> -/* Initialize a given LSM, if it is enabled. */
> -static void __init initialize_lsm(struct lsm_info *lsm)
> +/**
> + * lsm_init_single - Initialize a given LSM
> + * @lsm: LSM definition
> + */
> +static void __init lsm_init_single(struct lsm_info *lsm)
>   {
> -	if (lsm_is_enabled(lsm)) {
> -		int ret;
> +	int ret;
>   
> -		init_debug("initializing %s\n", lsm->id->name);
> -		ret = lsm->init();
> -		WARN(ret, "%s failed to initialize: %d\n", lsm->id->name, ret);
> -	}
> +	if (!lsm_is_enabled(lsm))
> +		return;
> +
> +	init_debug("initializing %s\n", lsm->id->name);
> +	ret = lsm->init();
> +	WARN(ret, "%s failed to initialize: %d\n", lsm->id->name, ret);
>   }
>   
>   /* Populate ordered LSMs list from comma-separated LSM name list. */
> @@ -374,7 +378,7 @@ static void __init lsm_init_ordered(void)
>   		panic("%s: early task alloc failed.\n", __func__);
>   
>   	lsm_order_for_each(lsm) {
> -		initialize_lsm(*lsm);
> +		lsm_init_single(*lsm);
>   	}
>   }
>   
> @@ -423,7 +427,7 @@ int __init early_security_init(void)
>   	lsm_early_for_each_raw(lsm) {
>   		lsm_enabled_set(lsm, true);
>   		lsm_prep_single(lsm);
> -		initialize_lsm(lsm);
> +		lsm_init_single(lsm);
>   	}
>   
>   	return 0;


^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 10/29] lsm: cleanup the LSM blob size code
  2025-04-09 18:49 ` [RFC PATCH 10/29] lsm: cleanup the LSM blob size code Paul Moore
  2025-04-09 23:29   ` Kees Cook
  2025-04-15 23:02   ` John Johansen
@ 2025-04-19  2:42   ` Fan Wu
  2025-04-19  5:53     ` Kees Cook
  2 siblings, 1 reply; 126+ messages in thread
From: Fan Wu @ 2025-04-19  2:42 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On Wed, Apr 9, 2025 at 11:53 AM Paul Moore <paul@paul-moore.com> wrote:
>
> Convert the lsm_blob_size fields to unsigned integers as there is no
> current need for them to be negative, change "lsm_set_blob_size()" to
> "lsm_blob_size_update()" to better reflect reality, and perform some
> other minor cleanups to the associated code.
>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
>  include/linux/lsm_hooks.h | 28 +++++++++++-----------
>  security/lsm_init.c       | 50 +++++++++++++++++++++++----------------
>  2 files changed, 43 insertions(+), 35 deletions(-)
>
> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
> index bc477fb20d02..a7ecb0791a0f 100644
> --- a/include/linux/lsm_hooks.h
> +++ b/include/linux/lsm_hooks.h
> @@ -102,20 +102,20 @@ struct security_hook_list {
>   * Security blob size or offset data.
>   */
>  struct lsm_blob_sizes {
> -       int lbs_cred;
> -       int lbs_file;
> -       int lbs_ib;
> -       int lbs_inode;
> -       int lbs_sock;
> -       int lbs_superblock;
> -       int lbs_ipc;
> -       int lbs_key;
> -       int lbs_msg_msg;
> -       int lbs_perf_event;
> -       int lbs_task;
> -       int lbs_xattr_count; /* number of xattr slots in new_xattrs array */
> -       int lbs_tun_dev;
> -       int lbs_bdev;
> +       unsigned int lbs_cred;
> +       unsigned int lbs_file;
> +       unsigned int lbs_ib;
> +       unsigned int lbs_inode;
> +       unsigned int lbs_sock;
> +       unsigned int lbs_superblock;
> +       unsigned int lbs_ipc;
> +       unsigned int lbs_key;
> +       unsigned int lbs_msg_msg;
> +       unsigned int lbs_perf_event;
> +       unsigned int lbs_task;
> +       unsigned int lbs_xattr_count; /* num xattr slots in new_xattrs array */
> +       unsigned int lbs_tun_dev;
> +       unsigned int lbs_bdev;
>  };

Can we use size_t here?

-Fan

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 10/29] lsm: cleanup the LSM blob size code
  2025-04-19  2:42   ` Fan Wu
@ 2025-04-19  5:53     ` Kees Cook
  2025-04-19 15:58       ` Fan Wu
  0 siblings, 1 reply; 126+ messages in thread
From: Kees Cook @ 2025-04-19  5:53 UTC (permalink / raw)
  To: Fan Wu
  Cc: Paul Moore, linux-security-module, linux-integrity, selinux,
	John Johansen, Mimi Zohar, Roberto Sassu,
	Mickaël Salaün, Günther Noack, Micah Morton,
	Casey Schaufler, Tetsuo Handa

On Fri, Apr 18, 2025 at 07:42:52PM -0700, Fan Wu wrote:
> On Wed, Apr 9, 2025 at 11:53 AM Paul Moore <paul@paul-moore.com> wrote:
> >
> > Convert the lsm_blob_size fields to unsigned integers as there is no
> > current need for them to be negative, change "lsm_set_blob_size()" to
> > "lsm_blob_size_update()" to better reflect reality, and perform some
> > other minor cleanups to the associated code.
> >
> > Signed-off-by: Paul Moore <paul@paul-moore.com>
> > ---
> >  include/linux/lsm_hooks.h | 28 +++++++++++-----------
> >  security/lsm_init.c       | 50 +++++++++++++++++++++++----------------
> >  2 files changed, 43 insertions(+), 35 deletions(-)
> >
> > diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
> > index bc477fb20d02..a7ecb0791a0f 100644
> > --- a/include/linux/lsm_hooks.h
> > +++ b/include/linux/lsm_hooks.h
> > @@ -102,20 +102,20 @@ struct security_hook_list {
> >   * Security blob size or offset data.
> >   */
> >  struct lsm_blob_sizes {
> > -       int lbs_cred;
> > -       int lbs_file;
> > -       int lbs_ib;
> > -       int lbs_inode;
> > -       int lbs_sock;
> > -       int lbs_superblock;
> > -       int lbs_ipc;
> > -       int lbs_key;
> > -       int lbs_msg_msg;
> > -       int lbs_perf_event;
> > -       int lbs_task;
> > -       int lbs_xattr_count; /* number of xattr slots in new_xattrs array */
> > -       int lbs_tun_dev;
> > -       int lbs_bdev;
> > +       unsigned int lbs_cred;
> > +       unsigned int lbs_file;
> > +       unsigned int lbs_ib;
> > +       unsigned int lbs_inode;
> > +       unsigned int lbs_sock;
> > +       unsigned int lbs_superblock;
> > +       unsigned int lbs_ipc;
> > +       unsigned int lbs_key;
> > +       unsigned int lbs_msg_msg;
> > +       unsigned int lbs_perf_event;
> > +       unsigned int lbs_task;
> > +       unsigned int lbs_xattr_count; /* num xattr slots in new_xattrs array */
> > +       unsigned int lbs_tun_dev;
> > +       unsigned int lbs_bdev;
> >  };
> 
> Can we use size_t here?

These blobs are relatively small -- size_t would double the memory usage here.

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 10/29] lsm: cleanup the LSM blob size code
  2025-04-19  5:53     ` Kees Cook
@ 2025-04-19 15:58       ` Fan Wu
  0 siblings, 0 replies; 126+ messages in thread
From: Fan Wu @ 2025-04-19 15:58 UTC (permalink / raw)
  To: Kees Cook
  Cc: Fan Wu, Paul Moore, linux-security-module, linux-integrity,
	selinux, John Johansen, Mimi Zohar, Roberto Sassu,
	Mickaël Salaün, Günther Noack, Micah Morton,
	Casey Schaufler, Tetsuo Handa

On Fri, Apr 18, 2025 at 10:53 PM Kees Cook <kees@kernel.org> wrote:
>
> On Fri, Apr 18, 2025 at 07:42:52PM -0700, Fan Wu wrote:
> > On Wed, Apr 9, 2025 at 11:53 AM Paul Moore <paul@paul-moore.com> wrote:
> > >
> > > Convert the lsm_blob_size fields to unsigned integers as there is no
> > > current need for them to be negative, change "lsm_set_blob_size()" to
> > > "lsm_blob_size_update()" to better reflect reality, and perform some
> > > other minor cleanups to the associated code.
> > >
> > > Signed-off-by: Paul Moore <paul@paul-moore.com>
> > > ---
...
> >
> > Can we use size_t here?
>
> These blobs are relatively small -- size_t would double the memory usage here.
>
Thanks for the insight. The memory usage consideration makes sense to me.

-Fan

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 29/29] lsm: add support for counting lsm_prop support among LSMs
  2025-04-09 18:50 ` [RFC PATCH 29/29] lsm: add support for counting lsm_prop support among LSMs Paul Moore
@ 2025-05-13 16:39   ` Casey Schaufler
  2025-05-13 20:23     ` Paul Moore
  0 siblings, 1 reply; 126+ messages in thread
From: Casey Schaufler @ 2025-05-13 16:39 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Tetsuo Handa, Casey Schaufler

On 4/9/2025 11:50 AM, Paul Moore wrote:
> Add two new variables, lsm_count_prop_subj and lsm_count_prop_obj, to
> count the number of lsm_prop entries for subjects and objects across all
> of the enabled LSMs.  Future patches will use this to continue the
> conversion towards the lsm_prop struct.
>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
>  include/linux/lsm_hooks.h         | 6 ++++++
>  security/apparmor/lsm.c           | 1 +
>  security/bpf/hooks.c              | 1 +
>  security/commoncap.c              | 1 +
>  security/integrity/evm/evm_main.c | 1 +
>  security/integrity/ima/ima_main.c | 1 +
>  security/ipe/ipe.c                | 1 +
>  security/landlock/setup.c         | 1 +
>  security/loadpin/loadpin.c        | 1 +
>  security/lockdown/lockdown.c      | 1 +
>  security/lsm.h                    | 4 ++++
>  security/lsm_init.c               | 6 ++++++
>  security/safesetid/lsm.c          | 1 +
>  security/security.c               | 3 +++
>  security/selinux/hooks.c          | 1 +
>  security/smack/smack_lsm.c        | 1 +
>  security/tomoyo/tomoyo.c          | 1 +
>  security/yama/yama_lsm.c          | 1 +
>  18 files changed, 33 insertions(+)
>
> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
> index 0d2c2a017ffc..5bc144c5f685 100644
> --- a/include/linux/lsm_hooks.h
> +++ b/include/linux/lsm_hooks.h
> @@ -71,16 +71,22 @@ struct lsm_static_calls_table {
>  	#undef LSM_HOOK
>  } __packed __randomize_layout;
>  
> +#define LSM_ID_FLG_NONE			0x00000000
> +#define LSM_ID_FLG_PROP_SUBJ		0x00000001
> +#define LSM_ID_FLG_PROP_OBJ		0x00000002
> +
>  /**
>   * struct lsm_id - Identify a Linux Security Module.
>   * @lsm: name of the LSM, must be approved by the LSM maintainers
>   * @id: LSM ID number from uapi/linux/lsm.h
> + * @flags: LSM flags, see LSM_ID_FLG_XXX
>   *
>   * Contains the information that identifies the LSM.
>   */
>  struct lsm_id {
>  	const char *name;
>  	u64 id;
> +	u32 flags;
>  };
>  
>  /*
> diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
> index 2fefaab6349f..db8592bed189 100644
> --- a/security/apparmor/lsm.c
> +++ b/security/apparmor/lsm.c
> @@ -1428,6 +1428,7 @@ struct lsm_blob_sizes apparmor_blob_sizes __ro_after_init = {
>  static const struct lsm_id apparmor_lsmid = {
>  	.name = "apparmor",
>  	.id = LSM_ID_APPARMOR,
> +	.flags = LSM_ID_FLG_PROP_SUBJ,
>  };
>  
>  static struct security_hook_list apparmor_hooks[] __ro_after_init = {
> diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c
> index 40efde233f3a..c72df6ff69f7 100644
> --- a/security/bpf/hooks.c
> +++ b/security/bpf/hooks.c
> @@ -18,6 +18,7 @@ static struct security_hook_list bpf_lsm_hooks[] __ro_after_init = {
>  static const struct lsm_id bpf_lsmid = {
>  	.name = "bpf",
>  	.id = LSM_ID_BPF,
> +	.flags = LSM_ID_FLG_PROP_SUBJ | LSM_ID_FLG_PROP_OBJ,

There's a problem here. BPF can have properties, but usually does not.
Unless there's a bpf program loaded that provides them it is incorrect
to use these flags. You can't know that at initialization.

I have an alternative that will address this that I will propose
shortly.


^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 29/29] lsm: add support for counting lsm_prop support among LSMs
  2025-05-13 16:39   ` Casey Schaufler
@ 2025-05-13 20:23     ` Paul Moore
  2025-05-14 19:30       ` Casey Schaufler
  0 siblings, 1 reply; 126+ messages in thread
From: Paul Moore @ 2025-05-13 20:23 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Tetsuo Handa

On Tue, May 13, 2025 at 12:39 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> On 4/9/2025 11:50 AM, Paul Moore wrote:
> > Add two new variables, lsm_count_prop_subj and lsm_count_prop_obj, to
> > count the number of lsm_prop entries for subjects and objects across all
> > of the enabled LSMs.  Future patches will use this to continue the
> > conversion towards the lsm_prop struct.
> >
> > Signed-off-by: Paul Moore <paul@paul-moore.com>
> > ---
> >  include/linux/lsm_hooks.h         | 6 ++++++
> >  security/apparmor/lsm.c           | 1 +
> >  security/bpf/hooks.c              | 1 +
> >  security/commoncap.c              | 1 +
> >  security/integrity/evm/evm_main.c | 1 +
> >  security/integrity/ima/ima_main.c | 1 +
> >  security/ipe/ipe.c                | 1 +
> >  security/landlock/setup.c         | 1 +
> >  security/loadpin/loadpin.c        | 1 +
> >  security/lockdown/lockdown.c      | 1 +
> >  security/lsm.h                    | 4 ++++
> >  security/lsm_init.c               | 6 ++++++
> >  security/safesetid/lsm.c          | 1 +
> >  security/security.c               | 3 +++
> >  security/selinux/hooks.c          | 1 +
> >  security/smack/smack_lsm.c        | 1 +
> >  security/tomoyo/tomoyo.c          | 1 +
> >  security/yama/yama_lsm.c          | 1 +
> >  18 files changed, 33 insertions(+)

...

> > diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c
> > index 40efde233f3a..c72df6ff69f7 100644
> > --- a/security/bpf/hooks.c
> > +++ b/security/bpf/hooks.c
> > @@ -18,6 +18,7 @@ static struct security_hook_list bpf_lsm_hooks[] __ro_after_init = {
> >  static const struct lsm_id bpf_lsmid = {
> >       .name = "bpf",
> >       .id = LSM_ID_BPF,
> > +     .flags = LSM_ID_FLG_PROP_SUBJ | LSM_ID_FLG_PROP_OBJ,
>
> There's a problem here. BPF can have properties, but usually does not.
> Unless there's a bpf program loaded that provides them it is incorrect
> to use these flags. You can't know that at initialization.
>
> I have an alternative that will address this that I will propose
> shortly.

Okay, thanks.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 14/29] lsm: add missing function header comment blocks in lsm_init.c
  2025-04-09 18:49 ` [RFC PATCH 14/29] lsm: add missing function header comment blocks in lsm_init.c Paul Moore
@ 2025-05-14 10:10   ` John Johansen
  0 siblings, 0 replies; 126+ messages in thread
From: John Johansen @ 2025-05-14 10:10 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On 4/9/25 11:49, Paul Moore wrote:
> Signed-off-by: Paul Moore <paul@paul-moore.com>

Reviewed-by: John Johansen <john.johansen@canonical.com>

> ---
>   security/lsm_init.c | 7 +++++++
>   1 file changed, 7 insertions(+)
> 
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 55b3fa82db76..04b1f5e760b1 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -313,6 +313,10 @@ static void __init lsm_init_single(struct lsm_info *lsm)
>   	WARN(ret, "%s failed to initialize: %d\n", lsm->id->name, ret);
>   }
>   
> +/**
> + * lsm_static_call_init - Initialize a LSM's static calls
> + * @hl: LSM hook list
> + */
>   static void __init lsm_static_call_init(struct security_hook_list *hl)
>   {
>   	struct lsm_static_call *scall = hl->scalls;
> @@ -351,6 +355,9 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
>   	}
>   }
>   
> +/**
> + * early_security_init - Initialize the early LSMs
> + */
>   int __init early_security_init(void)
>   {
>   	struct lsm_info *lsm;


^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 18/29] loadpin: move initcalls to the LSM framework
  2025-04-09 18:50 ` [RFC PATCH 18/29] loadpin: move initcalls to " Paul Moore
  2025-04-09 23:39   ` Kees Cook
@ 2025-05-14 11:57   ` John Johansen
  1 sibling, 0 replies; 126+ messages in thread
From: John Johansen @ 2025-05-14 11:57 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On 4/9/25 11:50, Paul Moore wrote:
> Signed-off-by: Paul Moore <paul@paul-moore.com>

Reviewed-by: John Johansen <john.johansen@canonical.com>

> ---
>   security/loadpin/loadpin.c | 15 ++++++++-------
>   1 file changed, 8 insertions(+), 7 deletions(-)
> 
> diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c
> index b9ddf05c5c16..273ffbd6defe 100644
> --- a/security/loadpin/loadpin.c
> +++ b/security/loadpin/loadpin.c
> @@ -270,11 +270,6 @@ static int __init loadpin_init(void)
>   	return 0;
>   }
>   
> -DEFINE_LSM(loadpin) = {
> -	.id = &loadpin_lsmid,
> -	.init = loadpin_init,
> -};
> -
>   #ifdef CONFIG_SECURITY_LOADPIN_VERITY
>   
>   enum loadpin_securityfs_interface_index {
> @@ -434,10 +429,16 @@ static int __init init_loadpin_securityfs(void)
>   	return 0;
>   }
>   
> -fs_initcall(init_loadpin_securityfs);
> -
>   #endif /* CONFIG_SECURITY_LOADPIN_VERITY */
>   
> +DEFINE_LSM(loadpin) = {
> +	.id = &loadpin_lsmid,
> +	.init = loadpin_init,
> +#ifdef CONFIG_SECURITY_LOADPIN_VERITY
> +	.initcall_fs = init_loadpin_securityfs,
> +#endif /* CONFIG_SECURITY_LOADPIN_VERITY */
> +};
> +
>   /* Should not be mutable after boot, so not listed in sysfs (perm == 0). */
>   module_param(enforce, int, 0);
>   MODULE_PARM_DESC(enforce, "Enforce module/firmware pinning");


^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 17/29] lsm: introduce an initcall mechanism into the LSM framework
  2025-04-09 18:50 ` [RFC PATCH 17/29] lsm: introduce an initcall mechanism into the LSM framework Paul Moore
  2025-04-09 21:16   ` Kees Cook
@ 2025-05-14 11:59   ` John Johansen
  1 sibling, 0 replies; 126+ messages in thread
From: John Johansen @ 2025-05-14 11:59 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On 4/9/25 11:50, Paul Moore wrote:
> Currently the individual LSMs register their own initcalls, and while
> this should be harmless, it can be wasteful in the case where a LSM
> is disabled at boot as the initcall will still be executed.  This
> patch introduces support for managing the initcalls in the LSM
> framework, and future patches will convert the existing LSMs over to
> this new mechanism.
> 
> Only initcall types which are used by the current in-tree LSMs are
> supported, additional initcall types can easily be added in the future
> if needed.
> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>

Reviewed-by: John Johansen <john.johansen@canonical.com>


> ---
>   include/linux/lsm_hooks.h | 33 ++++++++++++---
>   security/lsm_init.c       | 89 +++++++++++++++++++++++++++++++++++++++
>   2 files changed, 117 insertions(+), 5 deletions(-)
> 
> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
> index a7ecb0791a0f..0d2c2a017ffc 100644
> --- a/include/linux/lsm_hooks.h
> +++ b/include/linux/lsm_hooks.h
> @@ -148,13 +148,36 @@ enum lsm_order {
>   	LSM_ORDER_LAST = 1,	/* This is only for integrity. */
>   };
>   
> +/**
> + * struct lsm_info - Define an individual LSM for the LSM framework.
> + * @id: LSM name/ID info
> + * @order: ordering with respect to other LSMs, optional
> + * @flags: descriptive flags, optional
> + * @blobs: LSM blob sharing, optional
> + * @enabled: controlled by CONFIG_LSM, optional
> + * @init: LSM specific initialization routine
> + * @initcall_pure: LSM callback for initcall_pure() setup, optional
> + * @initcall_early: LSM callback for early_initcall setup, optional
> + * @initcall_core: LSM callback for core_initcall() setup, optional
> + * @initcall_subsys: LSM callback for subsys_initcall() setup, optional
> + * @initcall_fs: LSM callback for fs_initcall setup, optional
> + * @nitcall_device: LSM callback for device_initcall() setup, optional
> + * @initcall_late: LSM callback for late_initcall() setup, optional
> + */
>   struct lsm_info {
>   	const struct lsm_id *id;
> -	enum lsm_order order;	/* Optional: default is LSM_ORDER_MUTABLE */
> -	unsigned long flags;	/* Optional: flags describing LSM */
> -	int *enabled;		/* Optional: controlled by CONFIG_LSM */
> -	int (*init)(void);	/* Required. */
> -	struct lsm_blob_sizes *blobs; /* Optional: for blob sharing. */
> +	enum lsm_order order;
> +	unsigned long flags;
> +	struct lsm_blob_sizes *blobs;
> +	int *enabled;
> +	int (*init)(void);
> +	int (*initcall_pure)(void);
> +	int (*initcall_early)(void);
> +	int (*initcall_core)(void);
> +	int (*initcall_subsys)(void);
> +	int (*initcall_fs)(void);
> +	int (*initcall_device)(void);
> +	int (*initcall_late)(void);
>   };
>   
>   #define DEFINE_LSM(lsm)							\
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 8e00afeb84cf..75eb0cc82869 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -39,6 +39,27 @@ static __initdata struct lsm_info *lsm_order[MAX_LSM_COUNT + 1];
>   	for ((iter) = __start_early_lsm_info;				\
>   	     (iter) < __end_early_lsm_info; (iter)++)
>   
> +#define lsm_initcall(level)						\
> +	({ 								\
> +		int _r, _rc = 0;					\
> +		struct lsm_info **_lp, *_l; 				\
> +		lsm_order_for_each(_lp) { 				\
> +			_l = *_lp; 					\
> +			if (!_l->initcall_##level) 			\
> +				continue;				\
> +			lsm_pr_dbg("running %s %s initcall",		\
> +				   _l->id->name, #level);		\
> +			_r = _l->initcall_##level();			\
> +			if (_r) {					\
> +				pr_warn("failed LSM %s %s initcall with errno %d\n", \
> +					_l->id->name, #level, _r);	\
> +				if (!_rc)				\
> +					_rc = _r;			\
> +			}						\
> +		}							\
> +		_rc;							\
> +	})
> +
>   /**
>    * lsm_choose_security - Legacy "major" LSM selection
>    * @str: kernel command line parameter
> @@ -458,3 +479,71 @@ int __init security_init(void)
>   
>   	return 0;
>   }
> +
> +/**
> + * security_initcall_pure - Run the LSM pure initcalls
> + */
> +static int __init security_initcall_pure(void)
> +{
> +	return lsm_initcall(pure);
> +}
> +pure_initcall(security_initcall_pure);
> +
> +/**
> + * security_initcall_early - Run the LSM early initcalls
> + */
> +static int __init security_initcall_early(void)
> +{
> +	return lsm_initcall(early);
> +}
> +early_initcall(security_initcall_early);
> +
> +/**
> + * security_initcall_core - Run the LSM core initcalls
> + */
> +static int __init security_initcall_core(void)
> +{
> +	return lsm_initcall(core);
> +}
> +core_initcall(security_initcall_core);
> +
> +/**
> + * security_initcall_subsys - Run the LSM subsys initcalls
> + */
> +static int __init security_initcall_subsys(void)
> +{
> +	return lsm_initcall(subsys);
> +}
> +subsys_initcall(security_initcall_subsys);
> +
> +/**
> + * security_initcall_fs - Run the LSM fs initcalls
> + */
> +static int __init security_initcall_fs(void)
> +{
> +	return lsm_initcall(fs);
> +}
> +fs_initcall(security_initcall_fs);
> +
> +/**
> + * security_initcall_device - Run the LSM device initcalls
> + */
> +static int __init security_initcall_device(void)
> +{
> +	return lsm_initcall(device);
> +}
> +device_initcall(security_initcall_device);
> +
> +/**
> + * security_initcall_late - Run the LSM late initcalls
> + */
> +static int __init security_initcall_late(void)
> +{
> +	int rc;
> +
> +	rc = lsm_initcall(late);
> +	lsm_pr_dbg("all enabled LSMs fully activated\n");
> +
> +	return rc;
> +}
> +late_initcall(security_initcall_late);


^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 16/29] lsm: output available LSMs when debugging
  2025-04-09 18:50 ` [RFC PATCH 16/29] lsm: output available LSMs when debugging Paul Moore
@ 2025-05-14 12:01   ` John Johansen
  0 siblings, 0 replies; 126+ messages in thread
From: John Johansen @ 2025-05-14 12:01 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On 4/9/25 11:50, Paul Moore wrote:
> This will display all of the LSMs built into the kernel, regardless
> of if they are enabled or not.
> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>

Reviewed-by: John Johansen <john.johansen@canonical.com>

> ---
>   security/lsm_init.c | 19 ++++++++++++++++++-
>   1 file changed, 18 insertions(+), 1 deletion(-)
> 
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index aba1253ffc4c..8e00afeb84cf 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -363,6 +363,8 @@ int __init early_security_init(void)
>   {
>   	struct lsm_info *lsm;
>   
> +	/* NOTE: lsm_pr_dbg() doesn't work here as lsm_debug is not yet set */
> +
>   	lsm_early_for_each_raw(lsm) {
>   		lsm_enabled_set(lsm, true);
>   		lsm_order_append(lsm, "early");
> @@ -385,9 +387,24 @@ int __init security_init(void)
>   	struct lsm_info **lsm;
>   
>   	if (lsm_debug) {
> -		lsm_pr("built-in LSM list: %s\n", lsm_order_builtin);
> +		struct lsm_info *i;
> +
> +		cnt = 0;
> +		lsm_pr("available LSMs: ");
> +		lsm_early_for_each_raw(i)
> +			lsm_pr_cont("%s%s(E)", (cnt++ ? "," : ""), i->id->name);
> +		lsm_for_each_raw(i)
> +			lsm_pr_cont("%s%s", (cnt++ ? "," : ""), i->id->name);
> +		lsm_pr_cont("\n");
> +
> +		lsm_pr("built-in LSM config: %s\n", lsm_order_builtin);
> +
>   		lsm_pr("legacy LSM parameter: %s\n", lsm_order_legacy);
>   		lsm_pr("boot LSM parameter: %s\n", lsm_order_cmdline);
> +
> +		/* see the note about lsm_pr_dbg() in early_security_init() */
> +		lsm_early_for_each_raw(i)
> +			lsm_pr("enabled LSM early:%s\n", i->id->name);
>   	}
>   
>   	if (lsm_order_cmdline) {


^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 19/29] ipe: move initcalls to the LSM framework
  2025-04-09 18:50 ` [RFC PATCH 19/29] ipe: " Paul Moore
  2025-04-09 23:40   ` Kees Cook
  2025-04-14 21:19   ` Fan Wu
@ 2025-05-14 12:02   ` John Johansen
  2 siblings, 0 replies; 126+ messages in thread
From: John Johansen @ 2025-05-14 12:02 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On 4/9/25 11:50, Paul Moore wrote:
> Signed-off-by: Paul Moore <paul@paul-moore.com>

Reviewed-by: John Johansen <john.johansen@canonical.com>


> ---
>   security/ipe/fs.c  | 4 +---
>   security/ipe/ipe.c | 1 +
>   security/ipe/ipe.h | 2 ++
>   3 files changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/security/ipe/fs.c b/security/ipe/fs.c
> index 5b6d19fb844a..e4437c70ed3d 100644
> --- a/security/ipe/fs.c
> +++ b/security/ipe/fs.c
> @@ -187,7 +187,7 @@ static const struct file_operations enforce_fops = {
>    * Return: %0 on success. If an error occurs, the function will return
>    * the -errno.
>    */
> -static int __init ipe_init_securityfs(void)
> +int __init ipe_init_securityfs(void)
>   {
>   	int rc = 0;
>   	struct ipe_policy *ap;
> @@ -243,5 +243,3 @@ static int __init ipe_init_securityfs(void)
>   	securityfs_remove(root);
>   	return rc;
>   }
> -
> -fs_initcall(ipe_init_securityfs);
> diff --git a/security/ipe/ipe.c b/security/ipe/ipe.c
> index 2426441181dc..71644748ed56 100644
> --- a/security/ipe/ipe.c
> +++ b/security/ipe/ipe.c
> @@ -95,4 +95,5 @@ DEFINE_LSM(ipe) = {
>   	.id = &ipe_lsmid,
>   	.init = ipe_init,
>   	.blobs = &ipe_blobs,
> +	.initcall_fs = ipe_init_securityfs,
>   };
> diff --git a/security/ipe/ipe.h b/security/ipe/ipe.h
> index fb37513812dd..25cfdb8f0c20 100644
> --- a/security/ipe/ipe.h
> +++ b/security/ipe/ipe.h
> @@ -23,4 +23,6 @@ struct ipe_bdev *ipe_bdev(struct block_device *b);
>   struct ipe_inode *ipe_inode(const struct inode *inode);
>   #endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
>   
> +int ipe_init_securityfs(void);
> +
>   #endif /* _IPE_H */


^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 21/29] tomoyo: move initcalls to the LSM framework
  2025-04-09 18:50 ` [RFC PATCH 21/29] tomoyo: " Paul Moore
  2025-04-09 23:43   ` Kees Cook
@ 2025-05-14 12:05   ` John Johansen
  1 sibling, 0 replies; 126+ messages in thread
From: John Johansen @ 2025-05-14 12:05 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On 4/9/25 11:50, Paul Moore wrote:
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Reviewed-by: John Johansen <john.johansen@canonical.com>

> ---
>   security/tomoyo/common.h        | 2 ++
>   security/tomoyo/securityfs_if.c | 4 +---
>   security/tomoyo/tomoyo.c        | 1 +
>   3 files changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
> index 0e8e2e959aef..3b2a97d10a5d 100644
> --- a/security/tomoyo/common.h
> +++ b/security/tomoyo/common.h
> @@ -924,6 +924,8 @@ struct tomoyo_task {
>   
>   /********** Function prototypes. **********/
>   
> +int tomoyo_interface_init(void);
> +
>   bool tomoyo_address_matches_group(const bool is_ipv6, const __be32 *address,
>   				  const struct tomoyo_group *group);
>   bool tomoyo_compare_number_union(const unsigned long value,
> diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c
> index 7e69747b2f77..33933645f5b9 100644
> --- a/security/tomoyo/securityfs_if.c
> +++ b/security/tomoyo/securityfs_if.c
> @@ -233,7 +233,7 @@ static void __init tomoyo_create_entry(const char *name, const umode_t mode,
>    *
>    * Returns 0.
>    */
> -static int __init tomoyo_interface_init(void)
> +int __init tomoyo_interface_init(void)
>   {
>   	struct tomoyo_domain_info *domain;
>   	struct dentry *tomoyo_dir;
> @@ -269,5 +269,3 @@ static int __init tomoyo_interface_init(void)
>   	tomoyo_load_builtin_policy();
>   	return 0;
>   }
> -
> -fs_initcall(tomoyo_interface_init);
> diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
> index ed0f7b052a85..a015cf0c4a00 100644
> --- a/security/tomoyo/tomoyo.c
> +++ b/security/tomoyo/tomoyo.c
> @@ -617,4 +617,5 @@ DEFINE_LSM(tomoyo) = {
>   	.flags = LSM_FLAG_LEGACY_MAJOR,
>   	.blobs = &tomoyo_blob_sizes,
>   	.init = tomoyo_init,
> +	.initcall_fs = tomoyo_interface_init,
>   };


^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 22/29] safesetid: move initcalls to the LSM framework
  2025-04-09 18:50 ` [RFC PATCH 22/29] safesetid: " Paul Moore
  2025-04-09 23:43   ` Kees Cook
@ 2025-05-14 12:18   ` John Johansen
  1 sibling, 0 replies; 126+ messages in thread
From: John Johansen @ 2025-05-14 12:18 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On 4/9/25 11:50, Paul Moore wrote:
> Signed-off-by: Paul Moore <paul@paul-moore.com>

Reviewed-by: John Johansen <john.johansen@canonical.com>

> ---
>   security/safesetid/lsm.c        | 1 +
>   security/safesetid/lsm.h        | 2 ++
>   security/safesetid/securityfs.c | 3 +--
>   3 files changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/security/safesetid/lsm.c b/security/safesetid/lsm.c
> index 9a7c68d4e642..d5fb949050dd 100644
> --- a/security/safesetid/lsm.c
> +++ b/security/safesetid/lsm.c
> @@ -289,4 +289,5 @@ static int __init safesetid_security_init(void)
>   DEFINE_LSM(safesetid_security_init) = {
>   	.id = &safesetid_lsmid,
>   	.init = safesetid_security_init,
> +	.initcall_fs = safesetid_init_securityfs,
>   };
> diff --git a/security/safesetid/lsm.h b/security/safesetid/lsm.h
> index d346f4849cea..bf5172e2c3f7 100644
> --- a/security/safesetid/lsm.h
> +++ b/security/safesetid/lsm.h
> @@ -70,4 +70,6 @@ enum sid_policy_type _setid_policy_lookup(struct setid_ruleset *policy,
>   extern struct setid_ruleset __rcu *safesetid_setuid_rules;
>   extern struct setid_ruleset __rcu *safesetid_setgid_rules;
>   
> +int safesetid_init_securityfs(void);
> +
>   #endif /* _SAFESETID_H */
> diff --git a/security/safesetid/securityfs.c b/security/safesetid/securityfs.c
> index 8e1ffd70b18a..ece259f75b0d 100644
> --- a/security/safesetid/securityfs.c
> +++ b/security/safesetid/securityfs.c
> @@ -308,7 +308,7 @@ static const struct file_operations safesetid_gid_file_fops = {
>   	.write = safesetid_gid_file_write,
>   };
>   
> -static int __init safesetid_init_securityfs(void)
> +int __init safesetid_init_securityfs(void)
>   {
>   	int ret;
>   	struct dentry *policy_dir;
> @@ -345,4 +345,3 @@ static int __init safesetid_init_securityfs(void)
>   	securityfs_remove(policy_dir);
>   	return ret;
>   }
> -fs_initcall(safesetid_init_securityfs);


^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 25/29] ima,evm: move initcalls to the LSM framework
  2025-04-09 18:50 ` [RFC PATCH 25/29] ima,evm: " Paul Moore
@ 2025-05-14 13:06   ` John Johansen
  2025-06-11 20:09     ` Paul Moore
  2025-05-30 22:03   ` Mimi Zohar
  1 sibling, 1 reply; 126+ messages in thread
From: John Johansen @ 2025-05-14 13:06 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On 4/9/25 11:50, Paul Moore wrote:
> This patch converts IMA and EVM to use the LSM frameworks's initcall
> mechanism.  There were two challenges to doing this conversion: the
> first simply being the number of initcalls across IMA and EVM, and the
> second was the number of resources shared between the two related,
> yet independent LSMs.
> 
> The first problem was resolved by the creation of two new functions,
> integrity_device_init() and integrity_late_init(), with each focused on
> calling all of the various IMA/EVM initcalls for a single initcall type.
> The second problem was resolved by registering both of these new
> functions as initcalls for each LSM and including code in each
> registered initcall to ensure it only executes once.
> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
>   security/integrity/Makefile                   |  2 +-
>   security/integrity/evm/evm_main.c             |  7 +-
>   security/integrity/iint.c                     |  4 +-
>   security/integrity/ima/ima_main.c             |  7 +-
>   security/integrity/ima/ima_mok.c              |  4 +-
>   security/integrity/initcalls.c                | 97 +++++++++++++++++++
>   security/integrity/initcalls.h                | 23 +++++
>   .../integrity/platform_certs/load_ipl_s390.c  |  4 +-
>   .../integrity/platform_certs/load_powerpc.c   |  4 +-
>   security/integrity/platform_certs/load_uefi.c |  4 +-
>   .../platform_certs/machine_keyring.c          |  4 +-
>   .../platform_certs/platform_keyring.c         | 14 ++-
>   12 files changed, 147 insertions(+), 27 deletions(-)
>   create mode 100644 security/integrity/initcalls.c
>   create mode 100644 security/integrity/initcalls.h
> 
> diff --git a/security/integrity/Makefile b/security/integrity/Makefile
> index 92b63039c654..6ea330ea88b1 100644
> --- a/security/integrity/Makefile
> +++ b/security/integrity/Makefile
> @@ -5,7 +5,7 @@
>   
>   obj-$(CONFIG_INTEGRITY) += integrity.o
>   
> -integrity-y := iint.o
> +integrity-y := iint.o initcalls.o
>   integrity-$(CONFIG_INTEGRITY_AUDIT) += integrity_audit.o
>   integrity-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
>   integrity-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
> diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
> index db8e324ed4e6..770d0411da2b 100644
> --- a/security/integrity/evm/evm_main.c
> +++ b/security/integrity/evm/evm_main.c
> @@ -25,6 +25,7 @@
>   #include <crypto/hash.h>
>   #include <crypto/hash_info.h>
>   #include <crypto/utils.h>
> +#include "../initcalls.h"
>   #include "evm.h"
>   
>   int evm_initialized;
> @@ -1112,7 +1113,7 @@ void __init evm_load_x509(void)
>   }
>   #endif
>   
> -static int __init init_evm(void)
> +int __init init_evm(void)
>   {
>   	int error;
>   	struct list_head *pos, *q;
> @@ -1179,6 +1180,6 @@ DEFINE_LSM(evm) = {
>   	.init = init_evm_lsm,
>   	.order = LSM_ORDER_LAST,
>   	.blobs = &evm_blob_sizes,
> +	.initcall_device = integrity_device_init,
> +	.initcall_late = integrity_late_init,
>   };
> -
> -late_initcall(init_evm);
> diff --git a/security/integrity/iint.c b/security/integrity/iint.c
> index 068ac6c2ae1e..a4b88d67ff43 100644
> --- a/security/integrity/iint.c
> +++ b/security/integrity/iint.c
> @@ -11,6 +11,7 @@
>    */
>   #include <linux/security.h>
>   #include "integrity.h"
> +#include "initcalls.h"
>   
>   struct dentry *integrity_dir;
>   
> @@ -42,7 +43,7 @@ void __init integrity_load_keys(void)
>   		evm_load_x509();
>   }
>   
> -static int __init integrity_fs_init(void)
> +int __init integrity_fs_init(void)
>   {
>   	integrity_dir = securityfs_create_dir("integrity", NULL);
>   	if (IS_ERR(integrity_dir)) {
> @@ -58,4 +59,3 @@ static int __init integrity_fs_init(void)
>   	return 0;
>   }
>   
> -late_initcall(integrity_fs_init)
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index 55a4f08a2565..1687badafb48 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -27,6 +27,7 @@
>   #include <linux/fs.h>
>   #include <linux/iversion.h>
>   #include <linux/evm.h>
> +#include "../initcalls.h"
>   
>   #include "ima.h"
>   
> @@ -1180,7 +1181,7 @@ static int ima_kernel_module_request(char *kmod_name)
>   
>   #endif /* CONFIG_INTEGRITY_ASYMMETRIC_KEYS */
>   
> -static int __init init_ima(void)
> +int __init init_ima(void)
>   {
>   	int error;
>   
> @@ -1255,6 +1256,6 @@ DEFINE_LSM(ima) = {
>   	.init = init_ima_lsm,
>   	.order = LSM_ORDER_LAST,
>   	.blobs = &ima_blob_sizes,
> +	.initcall_device = integrity_device_init,
> +	.initcall_late = integrity_late_init,
>   };
> -
> -late_initcall(init_ima);	/* Start IMA after the TPM is available */
> diff --git a/security/integrity/ima/ima_mok.c b/security/integrity/ima/ima_mok.c
> index 95cc31525c57..4374fb6cc66d 100644
> --- a/security/integrity/ima/ima_mok.c
> +++ b/security/integrity/ima/ima_mok.c
> @@ -14,6 +14,7 @@
>   #include <linux/init.h>
>   #include <linux/slab.h>
>   #include <keys/system_keyring.h>
> +#include "../initcalls.h"
>   
>   
>   struct key *ima_blacklist_keyring;
> @@ -21,7 +22,7 @@ struct key *ima_blacklist_keyring;
>   /*
>    * Allocate the IMA blacklist keyring
>    */
> -static __init int ima_mok_init(void)
> +int __init ima_mok_init(void)
>   {
>   	struct key_restriction *restriction;
>   
> @@ -46,4 +47,3 @@ static __init int ima_mok_init(void)
>   		panic("Can't allocate IMA blacklist keyring.");
>   	return 0;
>   }
> -device_initcall(ima_mok_init);
> diff --git a/security/integrity/initcalls.c b/security/integrity/initcalls.c
> new file mode 100644
> index 000000000000..de39754a1c2c
> --- /dev/null
> +++ b/security/integrity/initcalls.c
> @@ -0,0 +1,97 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Platform certificate / keyring initcalls
> + *
> + */
> +
> +#include <linux/init.h>
> +
> +#include "initcalls.h"
> +
> +/**
> + * integrity_device_init - device_initcalls for IMA/EVM
> + *
> + * This helper function wraps all of the device_initcalls for both IMA and EVM.
> + * It can be called multiple times, e.g. once from IMA and once from EVM,
> + * without problem as it maintains an internal static state variable which
> + * ensures that any setup/initialization is only done once.
> + */
> +int __init integrity_device_init(void)
> +{
> +	int rc = 0, rc_tmp;
if none of the below config options are defined then rc_tmp is unused and the build can kick out with

../security/integrity/initcalls.c:21:21: error: unused variable ‘rc_tmp’ [-Werror=unused-variable]


> +	static bool setup = false;
> +
> +	if (setup)
> +		return 0;
> +	setup = true;
> +
> +#if defined(CONFIG_INTEGRITY_PLATFORM_KEYRING)
> +	rc_tmp = platform_keyring_init();
> +	if (!rc && rc_tmp)
> +		rc = rc_tmp;
> +#endif
> +
> +#if defined(CONFIG_INTEGRITY_MACHINE_KEYRING)
> +	rc_tmp = machine_keyring_init();
> +	if (!rc && rc_tmp)
> +		rc = rc_tmp;
> +#endif
> +
> +#if defined(CONFIG_IMA_BLACKLIST_KEYRING)
> +	rc_tmp = ima_mok_init();
> +	if (!rc && rc_tmp)
> +		rc = rc_tmp;
> +#endif
> +
> +	return rc;
> +}
> +
> +/**
> + * integrity_late_init - late_initcalls for IMA/EVM
> + *
> + * This helper function wraps all of the late_initcalls for both IMA and EVM.
> + * It can be called multiple times, e.g. once from IMA and once from EVM,
> + * without problem as it maintains an internal static state variable which
> + * ensures that any setup/initialization is only done once.
> + */
> +int __init integrity_late_init(void)
> +{
> +	int rc = 0, rc_tmp;
> +	static bool setup = false;
> +
> +	if (setup)
> +		return 0;
> +	setup = true;
> +
> +#if defined(CONFIG_LOAD_UEFI_KEYS)
> +	rc_tmp = load_uefi_certs();
> +	if (!rc && rc_tmp)
> +		rc = rc_tmp;
> +#endif
> +
> +#if defined(CONFIG_LOAD_IPL_KEYS)
> +	rc_tmp = load_ipl_certs();
> +	if (!rc && rc_tmp)
> +		rc = rc_tmp;
> +#endif
> +
> +#if defined(CONFIG_LOAD_PPC_KEYS)
> +	rc_tmp = load_powerpc_certs();
> +	if (!rc && rc_tmp)
> +		rc = rc_tmp;
> +#endif
> +
> +	rc_tmp = integrity_fs_init();
> +	if (!rc && rc_tmp)
> +		rc = rc_tmp;
> +
> +	rc_tmp = init_ima();
> +	if (!rc && rc_tmp)
> +		rc = rc_tmp;
> +
> +	rc_tmp = init_evm();
> +	if (!rc && rc_tmp)
> +		rc = rc_tmp;
> +
> +	return rc;
> +}
> diff --git a/security/integrity/initcalls.h b/security/integrity/initcalls.h
> new file mode 100644
> index 000000000000..dce16abb3b8a
> --- /dev/null
> +++ b/security/integrity/initcalls.h
> @@ -0,0 +1,23 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#ifndef PLATFORM_CERTS_INITCALLS_H
> +#define PLATFORM_CERTS_INITCALLS_H
> +
> +int machine_keyring_init(void);
> +int platform_keyring_init(void);
> +
> +int load_uefi_certs(void);
> +int load_ipl_certs(void);
> +int load_powerpc_certs(void);
> +
> +int integrity_fs_init(void);
> +
> +int init_ima(void);
> +int init_evm(void);
> +
> +int ima_mok_init(void);
> +
> +int integrity_device_init(void);
> +int integrity_late_init(void);
> +
> +#endif
> diff --git a/security/integrity/platform_certs/load_ipl_s390.c b/security/integrity/platform_certs/load_ipl_s390.c
> index c7c381a9ddaa..3bf91d925614 100644
> --- a/security/integrity/platform_certs/load_ipl_s390.c
> +++ b/security/integrity/platform_certs/load_ipl_s390.c
> @@ -10,12 +10,13 @@
>   #include <keys/system_keyring.h>
>   #include <asm/boot_data.h>
>   #include "../integrity.h"
> +#include "../initcalls.h"
>   
>   /*
>    * Load the certs contained in the IPL report created by the machine loader
>    * into the platform trusted keyring.
>    */
> -static int __init load_ipl_certs(void)
> +int __init load_ipl_certs(void)
>   {
>   	void *ptr, *end;
>   	unsigned int len;
> @@ -33,4 +34,3 @@ static int __init load_ipl_certs(void)
>   	}
>   	return 0;
>   }
> -late_initcall(load_ipl_certs);
> diff --git a/security/integrity/platform_certs/load_powerpc.c b/security/integrity/platform_certs/load_powerpc.c
> index c85febca3343..2904559e485b 100644
> --- a/security/integrity/platform_certs/load_powerpc.c
> +++ b/security/integrity/platform_certs/load_powerpc.c
> @@ -14,6 +14,7 @@
>   #include <asm/secvar.h>
>   #include "keyring_handler.h"
>   #include "../integrity.h"
> +#include "../initcalls.h"
>   
>   #define extract_esl(db, data, size, offset)	\
>   	do { db = data + offset; size = size - offset; } while (0)
> @@ -56,7 +57,7 @@ static __init void *get_cert_list(u8 *key, unsigned long keylen, u64 *size)
>    * keyring and the blacklisted X.509 cert SHA256 hashes into the blacklist
>    * keyring.
>    */
> -static int __init load_powerpc_certs(void)
> +int __init load_powerpc_certs(void)
>   {
>   	void *db = NULL, *dbx = NULL, *data = NULL;
>   	void *trustedca;
> @@ -156,4 +157,3 @@ static int __init load_powerpc_certs(void)
>   
>   	return rc;
>   }
> -late_initcall(load_powerpc_certs);
> diff --git a/security/integrity/platform_certs/load_uefi.c b/security/integrity/platform_certs/load_uefi.c
> index d1fdd113450a..52c180704674 100644
> --- a/security/integrity/platform_certs/load_uefi.c
> +++ b/security/integrity/platform_certs/load_uefi.c
> @@ -12,6 +12,7 @@
>   #include <keys/system_keyring.h>
>   #include "../integrity.h"
>   #include "keyring_handler.h"
> +#include "../initcalls.h"
>   
>   /*
>    * On T2 Macs reading the db and dbx efi variables to load UEFI Secure Boot
> @@ -157,7 +158,7 @@ static int __init load_moklist_certs(void)
>    * keyring and the UEFI blacklisted X.509 cert SHA256 hashes into the blacklist
>    * keyring.
>    */
> -static int __init load_uefi_certs(void)
> +int __init load_uefi_certs(void)
>   {
>   	efi_guid_t secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
>   	efi_guid_t mok_var = EFI_SHIM_LOCK_GUID;
> @@ -235,4 +236,3 @@ static int __init load_uefi_certs(void)
>   
>   	return rc;
>   }
> -late_initcall(load_uefi_certs);
> diff --git a/security/integrity/platform_certs/machine_keyring.c b/security/integrity/platform_certs/machine_keyring.c
> index a401640a63cd..b49eb2bab7a2 100644
> --- a/security/integrity/platform_certs/machine_keyring.c
> +++ b/security/integrity/platform_certs/machine_keyring.c
> @@ -7,8 +7,9 @@
>   
>   #include <linux/efi.h>
>   #include "../integrity.h"
> +#include "../initcalls.h"
>   
> -static __init int machine_keyring_init(void)
> +int __init machine_keyring_init(void)
>   {
>   	int rc;
>   
> @@ -19,7 +20,6 @@ static __init int machine_keyring_init(void)
>   	pr_notice("Machine keyring initialized\n");
>   	return 0;
>   }
> -device_initcall(machine_keyring_init);
>   
>   void __init add_to_machine_keyring(const char *source, const void *data, size_t len)
>   {
> diff --git a/security/integrity/platform_certs/platform_keyring.c b/security/integrity/platform_certs/platform_keyring.c
> index bcafd7387729..84a8e4309f06 100644
> --- a/security/integrity/platform_certs/platform_keyring.c
> +++ b/security/integrity/platform_certs/platform_keyring.c
> @@ -13,6 +13,7 @@
>   #include <linux/err.h>
>   #include <linux/slab.h>
>   #include "../integrity.h"
> +#include "../initcalls.h"
>   
>   /**
>    * add_to_platform_keyring - Add to platform keyring without validation.
> @@ -37,10 +38,12 @@ void __init add_to_platform_keyring(const char *source, const void *data,
>   		pr_info("Error adding keys to platform keyring %s\n", source);
>   }
>   
> -/*
> - * Create the trusted keyrings.
> +/**
> + * platform_keyring_init - Create the trusted keyrings.
> + *
> + * Must be initialised before we try and load the keys into the keyring.
>    */
> -static __init int platform_keyring_init(void)
> +int __init platform_keyring_init(void)
>   {
>   	int rc;
>   
> @@ -51,8 +54,3 @@ static __init int platform_keyring_init(void)
>   	pr_notice("Platform Keyring initialized\n");
>   	return 0;
>   }
> -
> -/*
> - * Must be initialised before we try and load the keys into the keyring.
> - */
> -device_initcall(platform_keyring_init);


^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 24/29] lockdown: move initcalls to the LSM framework
  2025-04-09 18:50 ` [RFC PATCH 24/29] lockdown: " Paul Moore
  2025-04-09 23:44   ` Kees Cook
@ 2025-05-14 13:31   ` John Johansen
  1 sibling, 0 replies; 126+ messages in thread
From: John Johansen @ 2025-05-14 13:31 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On 4/9/25 11:50, Paul Moore wrote:
> Signed-off-by: Paul Moore <paul@paul-moore.com>

Reviewed-by: John Johansen <john.johansen@canonical.com>

> ---
>   security/lockdown/lockdown.c | 3 +--
>   1 file changed, 1 insertion(+), 2 deletions(-)
> 
> diff --git a/security/lockdown/lockdown.c b/security/lockdown/lockdown.c
> index 4813f168ff93..8d46886d2cca 100644
> --- a/security/lockdown/lockdown.c
> +++ b/security/lockdown/lockdown.c
> @@ -161,8 +161,6 @@ static int __init lockdown_secfs_init(void)
>   	return PTR_ERR_OR_ZERO(dentry);
>   }
>   
> -core_initcall(lockdown_secfs_init);
> -
>   #ifdef CONFIG_SECURITY_LOCKDOWN_LSM_EARLY
>   DEFINE_EARLY_LSM(lockdown) = {
>   #else
> @@ -170,4 +168,5 @@ DEFINE_LSM(lockdown) = {
>   #endif
>   	.id = &lockdown_lsmid,
>   	.init = lockdown_lsm_init,
> +	.initcall_core = lockdown_secfs_init,
>   };


^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 23/29] apparmor: move initcalls to the LSM framework
  2025-04-09 18:50 ` [RFC PATCH 23/29] apparmor: " Paul Moore
  2025-04-09 23:44   ` Kees Cook
@ 2025-05-14 13:33   ` John Johansen
  1 sibling, 0 replies; 126+ messages in thread
From: John Johansen @ 2025-05-14 13:33 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On 4/9/25 11:50, Paul Moore wrote:
> Signed-off-by: Paul Moore <paul@paul-moore.com>

Acked-by: John Johansen <john.johansen@canonical.com>

> ---
>   security/apparmor/apparmorfs.c         | 4 +---
>   security/apparmor/crypto.c             | 4 +---
>   security/apparmor/include/apparmorfs.h | 2 ++
>   security/apparmor/include/crypto.h     | 1 +
>   security/apparmor/lsm.c                | 9 ++++++++-
>   5 files changed, 13 insertions(+), 7 deletions(-)
> 
> diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
> index 6039afae4bfc..0a7550a5bceb 100644
> --- a/security/apparmor/apparmorfs.c
> +++ b/security/apparmor/apparmorfs.c
> @@ -2632,7 +2632,7 @@ static const struct inode_operations policy_link_iops = {
>    *
>    * Returns: error on failure
>    */
> -static int __init aa_create_aafs(void)
> +int __init aa_create_aafs(void)
>   {
>   	struct dentry *dent;
>   	int error;
> @@ -2711,5 +2711,3 @@ static int __init aa_create_aafs(void)
>   	AA_ERROR("Error creating AppArmor securityfs\n");
>   	return error;
>   }
> -
> -fs_initcall(aa_create_aafs);
> diff --git a/security/apparmor/crypto.c b/security/apparmor/crypto.c
> index aad486b2fca6..e4395c1bfac5 100644
> --- a/security/apparmor/crypto.c
> +++ b/security/apparmor/crypto.c
> @@ -99,7 +99,7 @@ int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start,
>   	return error;
>   }
>   
> -static int __init init_profile_hash(void)
> +int __init init_profile_hash(void)
>   {
>   	struct crypto_shash *tfm;
>   
> @@ -119,5 +119,3 @@ static int __init init_profile_hash(void)
>   
>   	return 0;
>   }
> -
> -late_initcall(init_profile_hash);
> diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h
> index 1e94904f68d9..dd580594dfb7 100644
> --- a/security/apparmor/include/apparmorfs.h
> +++ b/security/apparmor/include/apparmorfs.h
> @@ -104,6 +104,8 @@ enum aafs_prof_type {
>   #define prof_dir(X) ((X)->dents[AAFS_PROF_DIR])
>   #define prof_child_dir(X) ((X)->dents[AAFS_PROF_PROFS])
>   
> +int aa_create_aafs(void);
> +
>   void __aa_bump_ns_revision(struct aa_ns *ns);
>   void __aafs_profile_rmdir(struct aa_profile *profile);
>   void __aafs_profile_migrate_dents(struct aa_profile *old,
> diff --git a/security/apparmor/include/crypto.h b/security/apparmor/include/crypto.h
> index 636a04e20d91..f3ffd388cc58 100644
> --- a/security/apparmor/include/crypto.h
> +++ b/security/apparmor/include/crypto.h
> @@ -13,6 +13,7 @@
>   #include "policy.h"
>   
>   #ifdef CONFIG_SECURITY_APPARMOR_HASH
> +int init_profile_hash(void);
>   unsigned int aa_hash_size(void);
>   char *aa_calc_hash(void *data, size_t len);
>   int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start,
> diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
> index a7f6a3274682..2fefaab6349f 100644
> --- a/security/apparmor/lsm.c
> +++ b/security/apparmor/lsm.c
> @@ -31,6 +31,7 @@
>   #include "include/audit.h"
>   #include "include/capability.h"
>   #include "include/cred.h"
> +#include "include/crypto.h"
>   #include "include/file.h"
>   #include "include/ipc.h"
>   #include "include/net.h"
> @@ -2146,7 +2147,6 @@ static int __init apparmor_nf_ip_init(void)
>   
>   	return 0;
>   }
> -__initcall(apparmor_nf_ip_init);
>   #endif
>   
>   static char nulldfa_src[] = {
> @@ -2277,4 +2277,11 @@ DEFINE_LSM(apparmor) = {
>   	.enabled = &apparmor_enabled,
>   	.blobs = &apparmor_blob_sizes,
>   	.init = apparmor_init,
> +	.initcall_fs = aa_create_aafs,
> +#if defined(CONFIG_NETFILTER) && defined(CONFIG_NETWORK_SECMARK)
> +	.initcall_device = apparmor_nf_ip_init,
> +#endif
> +#ifdef CONFIG_SECURITY_APPARMOR_HASH
> +	.initcall_late = init_profile_hash,
> +#endif
>   };


^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 28/29] lsm: add a LSM_STARTED_ALL notification event
  2025-04-09 18:50 ` [RFC PATCH 28/29] lsm: add a LSM_STARTED_ALL notification event Paul Moore
  2025-04-09 23:53   ` Kees Cook
@ 2025-05-14 13:34   ` John Johansen
  1 sibling, 0 replies; 126+ messages in thread
From: John Johansen @ 2025-05-14 13:34 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On 4/9/25 11:50, Paul Moore wrote:
> Add a new LSM notifier event, LSM_STARTED_ALL, which is fired once at
> boot when all of the LSMs have been started.
> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Reviewed-by: John Johansen <john.johansen@canonical.com>

> ---
>   include/linux/security.h | 1 +
>   security/lsm_init.c      | 1 +
>   2 files changed, 2 insertions(+)
> 
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 8aac21787a9f..a0ff4fc69375 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -85,6 +85,7 @@ struct timezone;
>   
>   enum lsm_event {
>   	LSM_POLICY_CHANGE,
> +	LSM_STARTED_ALL,
>   };
>   
>   struct dm_verity_digest {
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index c0881407ca3f..cad6d243a2a6 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -553,6 +553,7 @@ static int __init security_initcall_late(void)
>   
>   	rc = lsm_initcall(late);
>   	lsm_pr_dbg("all enabled LSMs fully activated\n");
> +	call_blocking_lsm_notifier(LSM_STARTED_ALL, NULL);
>   
>   	return rc;
>   }


^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 27/29] lsm: consolidate all of the LSM framework initcalls
  2025-04-09 18:50 ` [RFC PATCH 27/29] lsm: consolidate all of the LSM framework initcalls Paul Moore
  2025-04-09 23:52   ` Kees Cook
@ 2025-05-14 13:38   ` John Johansen
  1 sibling, 0 replies; 126+ messages in thread
From: John Johansen @ 2025-05-14 13:38 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On 4/9/25 11:50, Paul Moore wrote:
> The LSM framework itself registers a small number of initcalls, this
> patch converts these initcalls into the new initcall mechanism.
> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>

Reviewed-by: John Johansen <john.johansen@canonical.com>

> ---
>   security/inode.c    |  3 +--
>   security/lsm.h      |  4 ++++
>   security/lsm_init.c | 14 ++++++++++++--
>   security/min_addr.c |  5 +++--
>   4 files changed, 20 insertions(+), 6 deletions(-)
> 
> diff --git a/security/inode.c b/security/inode.c
> index f687e22e6809..671c66c147bc 100644
> --- a/security/inode.c
> +++ b/security/inode.c
> @@ -375,7 +375,7 @@ static const struct file_operations lsm_ops = {
>   };
>   #endif
>   
> -static int __init securityfs_init(void)
> +int __init securityfs_init(void)
>   {
>   	int retval;
>   
> @@ -394,4 +394,3 @@ static int __init securityfs_init(void)
>   #endif
>   	return 0;
>   }
> -core_initcall(securityfs_init);
> diff --git a/security/lsm.h b/security/lsm.h
> index 8ecb66896646..c432dc0c5e30 100644
> --- a/security/lsm.h
> +++ b/security/lsm.h
> @@ -35,4 +35,8 @@ extern struct kmem_cache *lsm_inode_cache;
>   int lsm_cred_alloc(struct cred *cred, gfp_t gfp);
>   int lsm_task_alloc(struct task_struct *task);
>   
> +/* LSM framework initializers */
> +int securityfs_init(void);
> +int min_addr_init(void);
> +
>   #endif /* _LSM_H_ */
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 75eb0cc82869..c0881407ca3f 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -485,7 +485,12 @@ int __init security_init(void)
>    */
>   static int __init security_initcall_pure(void)
>   {
> -	return lsm_initcall(pure);
> +	int rc_adr, rc_lsm;
> +
> +	rc_adr = min_addr_init();
> +	rc_lsm = lsm_initcall(pure);
> +
> +	return (rc_adr ? rc_adr : rc_lsm);
>   }
>   pure_initcall(security_initcall_pure);
>   
> @@ -503,7 +508,12 @@ early_initcall(security_initcall_early);
>    */
>   static int __init security_initcall_core(void)
>   {
> -	return lsm_initcall(core);
> +	int rc_sfs, rc_lsm;
> +
> +	rc_sfs = securityfs_init();
> +	rc_lsm = lsm_initcall(core);
> +
> +	return (rc_sfs ? rc_sfs : rc_lsm);
>   }
>   core_initcall(security_initcall_core);
>   
> diff --git a/security/min_addr.c b/security/min_addr.c
> index df1bc643d886..40714bdeefbe 100644
> --- a/security/min_addr.c
> +++ b/security/min_addr.c
> @@ -4,6 +4,8 @@
>   #include <linux/security.h>
>   #include <linux/sysctl.h>
>   
> +#include "lsm.h"
> +
>   /* amount of vm to protect from userspace access by both DAC and the LSM*/
>   unsigned long mmap_min_addr;
>   /* amount of vm to protect from userspace using CAP_SYS_RAWIO (DAC) */
> @@ -54,11 +56,10 @@ static const struct ctl_table min_addr_sysctl_table[] = {
>   	},
>   };
>   
> -static int __init init_mmap_min_addr(void)
> +int __init min_addr_init(void)
>   {
>   	register_sysctl_init("vm", min_addr_sysctl_table);
>   	update_mmap_min_addr();
>   
>   	return 0;
>   }
> -pure_initcall(init_mmap_min_addr);


^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 29/29] lsm: add support for counting lsm_prop support among LSMs
  2025-05-13 20:23     ` Paul Moore
@ 2025-05-14 19:30       ` Casey Schaufler
  2025-05-14 20:57         ` Paul Moore
  0 siblings, 1 reply; 126+ messages in thread
From: Casey Schaufler @ 2025-05-14 19:30 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Tetsuo Handa,
	Casey Schaufler


On 5/13/2025 1:23 PM, Paul Moore wrote:
> On Tue, May 13, 2025 at 12:39 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
>> On 4/9/2025 11:50 AM, Paul Moore wrote:
>>> Add two new variables, lsm_count_prop_subj and lsm_count_prop_obj, to
>>> count the number of lsm_prop entries for subjects and objects across all
>>> of the enabled LSMs.  Future patches will use this to continue the
>>> conversion towards the lsm_prop struct.
>>>
>>> Signed-off-by: Paul Moore <paul@paul-moore.com>
>>> ---
>>>  include/linux/lsm_hooks.h         | 6 ++++++
>>>  security/apparmor/lsm.c           | 1 +
>>>  security/bpf/hooks.c              | 1 +
>>>  security/commoncap.c              | 1 +
>>>  security/integrity/evm/evm_main.c | 1 +
>>>  security/integrity/ima/ima_main.c | 1 +
>>>  security/ipe/ipe.c                | 1 +
>>>  security/landlock/setup.c         | 1 +
>>>  security/loadpin/loadpin.c        | 1 +
>>>  security/lockdown/lockdown.c      | 1 +
>>>  security/lsm.h                    | 4 ++++
>>>  security/lsm_init.c               | 6 ++++++
>>>  security/safesetid/lsm.c          | 1 +
>>>  security/security.c               | 3 +++
>>>  security/selinux/hooks.c          | 1 +
>>>  security/smack/smack_lsm.c        | 1 +
>>>  security/tomoyo/tomoyo.c          | 1 +
>>>  security/yama/yama_lsm.c          | 1 +
>>>  18 files changed, 33 insertions(+)
> ..
>
>>> diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c
>>> index 40efde233f3a..c72df6ff69f7 100644
>>> --- a/security/bpf/hooks.c
>>> +++ b/security/bpf/hooks.c
>>> @@ -18,6 +18,7 @@ static struct security_hook_list bpf_lsm_hooks[] __ro_after_init = {
>>>  static const struct lsm_id bpf_lsmid = {
>>>       .name = "bpf",
>>>       .id = LSM_ID_BPF,
>>> +     .flags = LSM_ID_FLG_PROP_SUBJ | LSM_ID_FLG_PROP_OBJ,
>> There's a problem here. BPF can have properties, but usually does not.
>> Unless there's a bpf program loaded that provides them it is incorrect
>> to use these flags. You can't know that at initialization.
>>
>> I have an alternative that will address this that I will propose
>> shortly.
> Okay, thanks.

In my coming audit patch I changed where the counts of properties are
maintained from the LSM infrastructure to the audit subsystem, where they are
actually used. Instead of the LSM init code counting the property users, the
individual LSM init functions call an audit function that keeps track. BPF
could call that audit function if it loads a program that uses contexts. That
could happen after init, and the audit system would handle it properly.
Unloading the bpf program would be problematic. I honestly don't know whether
that's permitted.


^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 29/29] lsm: add support for counting lsm_prop support among LSMs
  2025-05-14 19:30       ` Casey Schaufler
@ 2025-05-14 20:57         ` Paul Moore
  2025-05-14 21:16           ` Casey Schaufler
  0 siblings, 1 reply; 126+ messages in thread
From: Paul Moore @ 2025-05-14 20:57 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Tetsuo Handa

On Wed, May 14, 2025 at 3:30 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> On 5/13/2025 1:23 PM, Paul Moore wrote:
> > On Tue, May 13, 2025 at 12:39 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> >> On 4/9/2025 11:50 AM, Paul Moore wrote:
> >>> Add two new variables, lsm_count_prop_subj and lsm_count_prop_obj, to
> >>> count the number of lsm_prop entries for subjects and objects across all
> >>> of the enabled LSMs.  Future patches will use this to continue the
> >>> conversion towards the lsm_prop struct.
> >>>
> >>> Signed-off-by: Paul Moore <paul@paul-moore.com>
> >>> ---
> >>>  include/linux/lsm_hooks.h         | 6 ++++++
> >>>  security/apparmor/lsm.c           | 1 +
> >>>  security/bpf/hooks.c              | 1 +
> >>>  security/commoncap.c              | 1 +
> >>>  security/integrity/evm/evm_main.c | 1 +
> >>>  security/integrity/ima/ima_main.c | 1 +
> >>>  security/ipe/ipe.c                | 1 +
> >>>  security/landlock/setup.c         | 1 +
> >>>  security/loadpin/loadpin.c        | 1 +
> >>>  security/lockdown/lockdown.c      | 1 +
> >>>  security/lsm.h                    | 4 ++++
> >>>  security/lsm_init.c               | 6 ++++++
> >>>  security/safesetid/lsm.c          | 1 +
> >>>  security/security.c               | 3 +++
> >>>  security/selinux/hooks.c          | 1 +
> >>>  security/smack/smack_lsm.c        | 1 +
> >>>  security/tomoyo/tomoyo.c          | 1 +
> >>>  security/yama/yama_lsm.c          | 1 +
> >>>  18 files changed, 33 insertions(+)
> > ..
> >
> >>> diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c
> >>> index 40efde233f3a..c72df6ff69f7 100644
> >>> --- a/security/bpf/hooks.c
> >>> +++ b/security/bpf/hooks.c
> >>> @@ -18,6 +18,7 @@ static struct security_hook_list bpf_lsm_hooks[] __ro_after_init = {
> >>>  static const struct lsm_id bpf_lsmid = {
> >>>       .name = "bpf",
> >>>       .id = LSM_ID_BPF,
> >>> +     .flags = LSM_ID_FLG_PROP_SUBJ | LSM_ID_FLG_PROP_OBJ,
> >> There's a problem here. BPF can have properties, but usually does not.
> >> Unless there's a bpf program loaded that provides them it is incorrect
> >> to use these flags. You can't know that at initialization.
> >>
> >> I have an alternative that will address this that I will propose
> >> shortly.
> > Okay, thanks.
>
> In my coming audit patch I changed where the counts of properties are
> maintained from the LSM infrastructure to the audit subsystem, where they are
> actually used. Instead of the LSM init code counting the property users, the
> individual LSM init functions call an audit function that keeps track. BPF
> could call that audit function if it loads a program that uses contexts. That
> could happen after init, and the audit system would handle it properly.
> Unloading the bpf program would be problematic. I honestly don't know whether
> that's permitted.

BPF programs can definitely go away, so that is something that would
need to be accounted for in any solution.  My understanding is that
once all references to a BPF program are gone, the BPF program is
unloaded from the kernel.

Perhaps the answer is that whenever the BPF LSM is enabled at boot,
the audit subsystem always queries for subj/obj labels from the BPF
LSM and instead of using the normal audit placeholder for missing
values, "?", we simply don't log the BPF subj/obj fields.  I dislike
the special case nature of the solution, but the reality is that the
BPF is a bit "special" and we are going to need to have some special
code to deal with it.

Of course I'm open to other ideas too ...

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 29/29] lsm: add support for counting lsm_prop support among LSMs
  2025-05-14 20:57         ` Paul Moore
@ 2025-05-14 21:16           ` Casey Schaufler
  2025-05-14 22:11             ` Paul Moore
  0 siblings, 1 reply; 126+ messages in thread
From: Casey Schaufler @ 2025-05-14 21:16 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Tetsuo Handa,
	Casey Schaufler

On 5/14/2025 1:57 PM, Paul Moore wrote:
> On Wed, May 14, 2025 at 3:30 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
>> On 5/13/2025 1:23 PM, Paul Moore wrote:
>>> On Tue, May 13, 2025 at 12:39 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
>>>> On 4/9/2025 11:50 AM, Paul Moore wrote:
>>>>> Add two new variables, lsm_count_prop_subj and lsm_count_prop_obj, to
>>>>> count the number of lsm_prop entries for subjects and objects across all
>>>>> of the enabled LSMs.  Future patches will use this to continue the
>>>>> conversion towards the lsm_prop struct.
>>>>>
>>>>> Signed-off-by: Paul Moore <paul@paul-moore.com>
>>>>> ---
>>>>>  include/linux/lsm_hooks.h         | 6 ++++++
>>>>>  security/apparmor/lsm.c           | 1 +
>>>>>  security/bpf/hooks.c              | 1 +
>>>>>  security/commoncap.c              | 1 +
>>>>>  security/integrity/evm/evm_main.c | 1 +
>>>>>  security/integrity/ima/ima_main.c | 1 +
>>>>>  security/ipe/ipe.c                | 1 +
>>>>>  security/landlock/setup.c         | 1 +
>>>>>  security/loadpin/loadpin.c        | 1 +
>>>>>  security/lockdown/lockdown.c      | 1 +
>>>>>  security/lsm.h                    | 4 ++++
>>>>>  security/lsm_init.c               | 6 ++++++
>>>>>  security/safesetid/lsm.c          | 1 +
>>>>>  security/security.c               | 3 +++
>>>>>  security/selinux/hooks.c          | 1 +
>>>>>  security/smack/smack_lsm.c        | 1 +
>>>>>  security/tomoyo/tomoyo.c          | 1 +
>>>>>  security/yama/yama_lsm.c          | 1 +
>>>>>  18 files changed, 33 insertions(+)
>>> ..
>>>
>>>>> diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c
>>>>> index 40efde233f3a..c72df6ff69f7 100644
>>>>> --- a/security/bpf/hooks.c
>>>>> +++ b/security/bpf/hooks.c
>>>>> @@ -18,6 +18,7 @@ static struct security_hook_list bpf_lsm_hooks[] __ro_after_init = {
>>>>>  static const struct lsm_id bpf_lsmid = {
>>>>>       .name = "bpf",
>>>>>       .id = LSM_ID_BPF,
>>>>> +     .flags = LSM_ID_FLG_PROP_SUBJ | LSM_ID_FLG_PROP_OBJ,
>>>> There's a problem here. BPF can have properties, but usually does not.
>>>> Unless there's a bpf program loaded that provides them it is incorrect
>>>> to use these flags. You can't know that at initialization.
>>>>
>>>> I have an alternative that will address this that I will propose
>>>> shortly.
>>> Okay, thanks.
>> In my coming audit patch I changed where the counts of properties are
>> maintained from the LSM infrastructure to the audit subsystem, where they are
>> actually used. Instead of the LSM init code counting the property users, the
>> individual LSM init functions call an audit function that keeps track. BPF
>> could call that audit function if it loads a program that uses contexts. That
>> could happen after init, and the audit system would handle it properly.
>> Unloading the bpf program would be problematic. I honestly don't know whether
>> that's permitted.
> BPF programs can definitely go away, so that is something that would
> need to be accounted for in any solution.  My understanding is that
> once all references to a BPF program are gone, the BPF program is
> unloaded from the kernel.
>
> Perhaps the answer is that whenever the BPF LSM is enabled at boot,
> the audit subsystem always queries for subj/obj labels from the BPF
> LSM and instead of using the normal audit placeholder for missing
> values, "?", we simply don't log the BPF subj/obj fields.  I dislike
> the special case nature of the solution, but the reality is that the
> BPF is a bit "special" and we are going to need to have some special
> code to deal with it.

If BPF never calls audit_lsm_secctx() everything is fine, and the BPF
context(s) never result in an aux record. If BPF does call audit_lsm_secctx()
and there is another LSM that uses contexts you get the aux record, even
if the BPF program goes away. You will get an aux record with only one context.
This is not ideal, but provides the correct information. This all assumes that
BPF programs can call into the audit system, and that they deal with multiple
contexts within BPF. There could be a flag to audit_lsm_secctx() to delete the
entry, but that seems potentially dangerous.

>
> Of course I'm open to other ideas too ...
>

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 29/29] lsm: add support for counting lsm_prop support among LSMs
  2025-05-14 21:16           ` Casey Schaufler
@ 2025-05-14 22:11             ` Paul Moore
  2025-05-15 14:12               ` Casey Schaufler
  0 siblings, 1 reply; 126+ messages in thread
From: Paul Moore @ 2025-05-14 22:11 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Tetsuo Handa

On Wed, May 14, 2025 at 5:16 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> On 5/14/2025 1:57 PM, Paul Moore wrote:
> > On Wed, May 14, 2025 at 3:30 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> >> On 5/13/2025 1:23 PM, Paul Moore wrote:
> >>> On Tue, May 13, 2025 at 12:39 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> >>>> On 4/9/2025 11:50 AM, Paul Moore wrote:

...

> >> In my coming audit patch I changed where the counts of properties are
> >> maintained from the LSM infrastructure to the audit subsystem, where they are
> >> actually used. Instead of the LSM init code counting the property users, the
> >> individual LSM init functions call an audit function that keeps track. BPF
> >> could call that audit function if it loads a program that uses contexts. That
> >> could happen after init, and the audit system would handle it properly.
> >> Unloading the bpf program would be problematic. I honestly don't know whether
> >> that's permitted.
> >
> > BPF programs can definitely go away, so that is something that would
> > need to be accounted for in any solution.  My understanding is that
> > once all references to a BPF program are gone, the BPF program is
> > unloaded from the kernel.
> >
> > Perhaps the answer is that whenever the BPF LSM is enabled at boot,
> > the audit subsystem always queries for subj/obj labels from the BPF
> > LSM and instead of using the normal audit placeholder for missing
> > values, "?", we simply don't log the BPF subj/obj fields.  I dislike
> > the special case nature of the solution, but the reality is that the
> > BPF is a bit "special" and we are going to need to have some special
> > code to deal with it.
>
> If BPF never calls audit_lsm_secctx() everything is fine, and the BPF
> context(s) never result in an aux record. If BPF does call audit_lsm_secctx()
> and there is another LSM that uses contexts you get the aux record, even
> if the BPF program goes away. You will get an aux record with only one context.
> This is not ideal, but provides the correct information. This all assumes that
> BPF programs can call into the audit system, and that they deal with multiple
> contexts within BPF. There could be a flag to audit_lsm_secctx() to delete the
> entry, but that seems potentially dangerous.

I think the answer to "can BPF programs call into the audit subsystem"
is dependent on if they have the proper BPF kfuncs for the audit API.
I don't recall seeing them post anything to the audit list about that,
but it's also possible they did it without telling anyone (ala move
fast, break things).  I don't think we would want to prevent BPF
programs from calling into the normal audit API that other subsystems
use, but we would need to look at that as it comes up.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 29/29] lsm: add support for counting lsm_prop support among LSMs
  2025-05-14 22:11             ` Paul Moore
@ 2025-05-15 14:12               ` Casey Schaufler
  2025-05-15 18:13                 ` Paul Moore
  0 siblings, 1 reply; 126+ messages in thread
From: Casey Schaufler @ 2025-05-15 14:12 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Tetsuo Handa,
	Casey Schaufler

On 5/14/2025 3:11 PM, Paul Moore wrote:
> On Wed, May 14, 2025 at 5:16 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
>> On 5/14/2025 1:57 PM, Paul Moore wrote:
>>> On Wed, May 14, 2025 at 3:30 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
>>>> On 5/13/2025 1:23 PM, Paul Moore wrote:
>>>>> On Tue, May 13, 2025 at 12:39 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
>>>>>> On 4/9/2025 11:50 AM, Paul Moore wrote:
> ..
>
>>>> In my coming audit patch I changed where the counts of properties are
>>>> maintained from the LSM infrastructure to the audit subsystem, where they are
>>>> actually used. Instead of the LSM init code counting the property users, the
>>>> individual LSM init functions call an audit function that keeps track. BPF
>>>> could call that audit function if it loads a program that uses contexts. That
>>>> could happen after init, and the audit system would handle it properly.
>>>> Unloading the bpf program would be problematic. I honestly don't know whether
>>>> that's permitted.
>>> BPF programs can definitely go away, so that is something that would
>>> need to be accounted for in any solution.  My understanding is that
>>> once all references to a BPF program are gone, the BPF program is
>>> unloaded from the kernel.
>>>
>>> Perhaps the answer is that whenever the BPF LSM is enabled at boot,
>>> the audit subsystem always queries for subj/obj labels from the BPF
>>> LSM and instead of using the normal audit placeholder for missing
>>> values, "?", we simply don't log the BPF subj/obj fields.  I dislike
>>> the special case nature of the solution, but the reality is that the
>>> BPF is a bit "special" and we are going to need to have some special
>>> code to deal with it.
>> If BPF never calls audit_lsm_secctx() everything is fine, and the BPF
>> context(s) never result in an aux record. If BPF does call audit_lsm_secctx()
>> and there is another LSM that uses contexts you get the aux record, even
>> if the BPF program goes away. You will get an aux record with only one context.
>> This is not ideal, but provides the correct information. This all assumes that
>> BPF programs can call into the audit system, and that they deal with multiple
>> contexts within BPF. There could be a flag to audit_lsm_secctx() to delete the
>> entry, but that seems potentially dangerous.
> I think the answer to "can BPF programs call into the audit subsystem"
> is dependent on if they have the proper BPF kfuncs for the audit API.
> I don't recall seeing them post anything to the audit list about that,
> but it's also possible they did it without telling anyone (ala move
> fast, break things).  I don't think we would want to prevent BPF
> programs from calling into the normal audit API that other subsystems
> use, but we would need to look at that as it comes up.

I suggest that until the "BPF auditing doesn't work!!!" crisis hits
there's not a lot of point in going to heroic efforts to ensure all
the bases are covered. I'll move forward assuming that an LSM could
dynamically decide to call audit_lsm_secctx(), and that once it does
it will always show up in the aux record, even if that means subj_bpf=?
shows up every time.



^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 29/29] lsm: add support for counting lsm_prop support among LSMs
  2025-05-15 14:12               ` Casey Schaufler
@ 2025-05-15 18:13                 ` Paul Moore
  2025-05-15 19:41                   ` Casey Schaufler
  0 siblings, 1 reply; 126+ messages in thread
From: Paul Moore @ 2025-05-15 18:13 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Tetsuo Handa

On Thu, May 15, 2025 at 10:12 AM Casey Schaufler <casey@schaufler-ca.com> wrote:
>
> On 5/14/2025 3:11 PM, Paul Moore wrote:
> > On Wed, May 14, 2025 at 5:16 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> >> On 5/14/2025 1:57 PM, Paul Moore wrote:
> >>> On Wed, May 14, 2025 at 3:30 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> >>>> On 5/13/2025 1:23 PM, Paul Moore wrote:
> >>>>> On Tue, May 13, 2025 at 12:39 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> >>>>>> On 4/9/2025 11:50 AM, Paul Moore wrote:
> > ..
> >
> >>>> In my coming audit patch I changed where the counts of properties are
> >>>> maintained from the LSM infrastructure to the audit subsystem, where they are
> >>>> actually used. Instead of the LSM init code counting the property users, the
> >>>> individual LSM init functions call an audit function that keeps track. BPF
> >>>> could call that audit function if it loads a program that uses contexts. That
> >>>> could happen after init, and the audit system would handle it properly.
> >>>> Unloading the bpf program would be problematic. I honestly don't know whether
> >>>> that's permitted.
> >>> BPF programs can definitely go away, so that is something that would
> >>> need to be accounted for in any solution.  My understanding is that
> >>> once all references to a BPF program are gone, the BPF program is
> >>> unloaded from the kernel.
> >>>
> >>> Perhaps the answer is that whenever the BPF LSM is enabled at boot,
> >>> the audit subsystem always queries for subj/obj labels from the BPF
> >>> LSM and instead of using the normal audit placeholder for missing
> >>> values, "?", we simply don't log the BPF subj/obj fields.  I dislike
> >>> the special case nature of the solution, but the reality is that the
> >>> BPF is a bit "special" and we are going to need to have some special
> >>> code to deal with it.
> >> If BPF never calls audit_lsm_secctx() everything is fine, and the BPF
> >> context(s) never result in an aux record. If BPF does call audit_lsm_secctx()
> >> and there is another LSM that uses contexts you get the aux record, even
> >> if the BPF program goes away. You will get an aux record with only one context.
> >> This is not ideal, but provides the correct information. This all assumes that
> >> BPF programs can call into the audit system, and that they deal with multiple
> >> contexts within BPF. There could be a flag to audit_lsm_secctx() to delete the
> >> entry, but that seems potentially dangerous.
> > I think the answer to "can BPF programs call into the audit subsystem"
> > is dependent on if they have the proper BPF kfuncs for the audit API.
> > I don't recall seeing them post anything to the audit list about that,
> > but it's also possible they did it without telling anyone (ala move
> > fast, break things).  I don't think we would want to prevent BPF
> > programs from calling into the normal audit API that other subsystems
> > use, but we would need to look at that as it comes up.
>
> I suggest that until the "BPF auditing doesn't work!!!" crisis hits
> there's not a lot of point in going to heroic efforts to ensure all
> the bases are covered. I'll move forward assuming that an LSM could
> dynamically decide to call audit_lsm_secctx(), and that once it does
> it will always show up in the aux record, even if that means subj_bpf=?
> shows up every time.

My only concern is that I suspect most/all of the major distro enable
the BPF LSM by default which means that suddenly a lot of users/admins
are going to start seeing the multi-subj/obj labeling scheme only to
have an empty field logged.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 29/29] lsm: add support for counting lsm_prop support among LSMs
  2025-05-15 18:13                 ` Paul Moore
@ 2025-05-15 19:41                   ` Casey Schaufler
  2025-05-15 21:02                     ` Paul Moore
  0 siblings, 1 reply; 126+ messages in thread
From: Casey Schaufler @ 2025-05-15 19:41 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Tetsuo Handa,
	Casey Schaufler

On 5/15/2025 11:13 AM, Paul Moore wrote:
> On Thu, May 15, 2025 at 10:12 AM Casey Schaufler <casey@schaufler-ca.com> wrote:
>> On 5/14/2025 3:11 PM, Paul Moore wrote:
>>> On Wed, May 14, 2025 at 5:16 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
>>>> On 5/14/2025 1:57 PM, Paul Moore wrote:
>>>>> On Wed, May 14, 2025 at 3:30 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
>>>>>> On 5/13/2025 1:23 PM, Paul Moore wrote:
>>>>>>> On Tue, May 13, 2025 at 12:39 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
>>>>>>>> On 4/9/2025 11:50 AM, Paul Moore wrote:
>>> ..
>>>
>>>>>> In my coming audit patch I changed where the counts of properties are
>>>>>> maintained from the LSM infrastructure to the audit subsystem, where they are
>>>>>> actually used. Instead of the LSM init code counting the property users, the
>>>>>> individual LSM init functions call an audit function that keeps track. BPF
>>>>>> could call that audit function if it loads a program that uses contexts. That
>>>>>> could happen after init, and the audit system would handle it properly.
>>>>>> Unloading the bpf program would be problematic. I honestly don't know whether
>>>>>> that's permitted.
>>>>> BPF programs can definitely go away, so that is something that would
>>>>> need to be accounted for in any solution.  My understanding is that
>>>>> once all references to a BPF program are gone, the BPF program is
>>>>> unloaded from the kernel.
>>>>>
>>>>> Perhaps the answer is that whenever the BPF LSM is enabled at boot,
>>>>> the audit subsystem always queries for subj/obj labels from the BPF
>>>>> LSM and instead of using the normal audit placeholder for missing
>>>>> values, "?", we simply don't log the BPF subj/obj fields.  I dislike
>>>>> the special case nature of the solution, but the reality is that the
>>>>> BPF is a bit "special" and we are going to need to have some special
>>>>> code to deal with it.
>>>> If BPF never calls audit_lsm_secctx() everything is fine, and the BPF
>>>> context(s) never result in an aux record. If BPF does call audit_lsm_secctx()
>>>> and there is another LSM that uses contexts you get the aux record, even
>>>> if the BPF program goes away. You will get an aux record with only one context.
>>>> This is not ideal, but provides the correct information. This all assumes that
>>>> BPF programs can call into the audit system, and that they deal with multiple
>>>> contexts within BPF. There could be a flag to audit_lsm_secctx() to delete the
>>>> entry, but that seems potentially dangerous.
>>> I think the answer to "can BPF programs call into the audit subsystem"
>>> is dependent on if they have the proper BPF kfuncs for the audit API.
>>> I don't recall seeing them post anything to the audit list about that,
>>> but it's also possible they did it without telling anyone (ala move
>>> fast, break things).  I don't think we would want to prevent BPF
>>> programs from calling into the normal audit API that other subsystems
>>> use, but we would need to look at that as it comes up.
>> I suggest that until the "BPF auditing doesn't work!!!" crisis hits
>> there's not a lot of point in going to heroic efforts to ensure all
>> the bases are covered. I'll move forward assuming that an LSM could
>> dynamically decide to call audit_lsm_secctx(), and that once it does
>> it will always show up in the aux record, even if that means subj_bpf=?
>> shows up every time.
> My only concern is that I suspect most/all of the major distro enable
> the BPF LSM by default which means that suddenly a lot of users/admins
> are going to start seeing the multi-subj/obj labeling scheme only to
> have an empty field logged.

That will only occur if a BPF program says it want to provide contexts
and then stops doing so, either by exiting or in error. As no BPF programs
currently use audit, it seems that this is at worst a future problem.
Should BPF programs develop the ability to use audit the behavior will need
to be documented. I don't see how we can anticipate what they'll end up
trying.


^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 29/29] lsm: add support for counting lsm_prop support among LSMs
  2025-05-15 19:41                   ` Casey Schaufler
@ 2025-05-15 21:02                     ` Paul Moore
  0 siblings, 0 replies; 126+ messages in thread
From: Paul Moore @ 2025-05-15 21:02 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Mimi Zohar, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Tetsuo Handa

On Thu, May 15, 2025 at 3:41 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> On 5/15/2025 11:13 AM, Paul Moore wrote:
> > On Thu, May 15, 2025 at 10:12 AM Casey Schaufler <casey@schaufler-ca.com> wrote:
> >> On 5/14/2025 3:11 PM, Paul Moore wrote:
> >>> On Wed, May 14, 2025 at 5:16 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> >>>> On 5/14/2025 1:57 PM, Paul Moore wrote:
> >>>>> On Wed, May 14, 2025 at 3:30 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> >>>>>> On 5/13/2025 1:23 PM, Paul Moore wrote:
> >>>>>>> On Tue, May 13, 2025 at 12:39 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> >>>>>>>> On 4/9/2025 11:50 AM, Paul Moore wrote:
> >>> ..
> >>>
> >>>>>> In my coming audit patch I changed where the counts of properties are
> >>>>>> maintained from the LSM infrastructure to the audit subsystem, where they are
> >>>>>> actually used. Instead of the LSM init code counting the property users, the
> >>>>>> individual LSM init functions call an audit function that keeps track. BPF
> >>>>>> could call that audit function if it loads a program that uses contexts. That
> >>>>>> could happen after init, and the audit system would handle it properly.
> >>>>>> Unloading the bpf program would be problematic. I honestly don't know whether
> >>>>>> that's permitted.
> >>>>> BPF programs can definitely go away, so that is something that would
> >>>>> need to be accounted for in any solution.  My understanding is that
> >>>>> once all references to a BPF program are gone, the BPF program is
> >>>>> unloaded from the kernel.
> >>>>>
> >>>>> Perhaps the answer is that whenever the BPF LSM is enabled at boot,
> >>>>> the audit subsystem always queries for subj/obj labels from the BPF
> >>>>> LSM and instead of using the normal audit placeholder for missing
> >>>>> values, "?", we simply don't log the BPF subj/obj fields.  I dislike
> >>>>> the special case nature of the solution, but the reality is that the
> >>>>> BPF is a bit "special" and we are going to need to have some special
> >>>>> code to deal with it.
> >>>> If BPF never calls audit_lsm_secctx() everything is fine, and the BPF
> >>>> context(s) never result in an aux record. If BPF does call audit_lsm_secctx()
> >>>> and there is another LSM that uses contexts you get the aux record, even
> >>>> if the BPF program goes away. You will get an aux record with only one context.
> >>>> This is not ideal, but provides the correct information. This all assumes that
> >>>> BPF programs can call into the audit system, and that they deal with multiple
> >>>> contexts within BPF. There could be a flag to audit_lsm_secctx() to delete the
> >>>> entry, but that seems potentially dangerous.
> >>> I think the answer to "can BPF programs call into the audit subsystem"
> >>> is dependent on if they have the proper BPF kfuncs for the audit API.
> >>> I don't recall seeing them post anything to the audit list about that,
> >>> but it's also possible they did it without telling anyone (ala move
> >>> fast, break things).  I don't think we would want to prevent BPF
> >>> programs from calling into the normal audit API that other subsystems
> >>> use, but we would need to look at that as it comes up.
> >> I suggest that until the "BPF auditing doesn't work!!!" crisis hits
> >> there's not a lot of point in going to heroic efforts to ensure all
> >> the bases are covered. I'll move forward assuming that an LSM could
> >> dynamically decide to call audit_lsm_secctx(), and that once it does
> >> it will always show up in the aux record, even if that means subj_bpf=?
> >> shows up every time.
> > My only concern is that I suspect most/all of the major distro enable
> > the BPF LSM by default which means that suddenly a lot of users/admins
> > are going to start seeing the multi-subj/obj labeling scheme only to
> > have an empty field logged.
>
> That will only occur if a BPF program says it want to provide contexts
> and then stops doing so, either by exiting or in error. As no BPF programs
> currently use audit, it seems that this is at worst a future problem.
> Should BPF programs develop the ability to use audit the behavior will need
> to be documented. I don't see how we can anticipate what they'll end up
> trying.

Okay, I must have misunderstood your proposal; I'll take a look once
it is posted, that should help clear things up.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 08/29] lsm: get rid of the lsm_names list and do some cleanup
  2025-04-09 18:49 ` [RFC PATCH 08/29] lsm: get rid of the lsm_names list and do some cleanup Paul Moore
  2025-04-09 23:13   ` Kees Cook
@ 2025-05-22 21:26   ` Casey Schaufler
  1 sibling, 0 replies; 126+ messages in thread
From: Casey Schaufler @ 2025-05-22 21:26 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Tetsuo Handa, Casey Schaufler

On 4/9/2025 11:49 AM, Paul Moore wrote:
> The LSM currently has a lot of code to maintain a list of the
> currently active LSMs in a human readable string, with the only
> user being the "/sys/kernel/security/lsm" code.  Let's drop all
> of that code and generate the string on an as-needed basis when
> userspace reads "/sys/kernel/security/lsm".
>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
>  include/linux/lsm_hooks.h |  1 -
>  security/inode.c          | 27 +++++++++++++++++++--
>  security/lsm_init.c       | 49 ---------------------------------------
>  3 files changed, 25 insertions(+), 52 deletions(-)
>
> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
> index 4cd17c9a229f..bc477fb20d02 100644
> --- a/include/linux/lsm_hooks.h
> +++ b/include/linux/lsm_hooks.h
> @@ -169,7 +169,6 @@ struct lsm_info {
>  
>  
>  /* DO NOT tamper with these variables outside of the LSM framework */
> -extern char *lsm_names;
>  extern struct lsm_static_calls_table static_calls_table __ro_after_init;
>  
>  /**
> diff --git a/security/inode.c b/security/inode.c
> index da3ab44c8e57..49bc3578bd23 100644
> --- a/security/inode.c
> +++ b/security/inode.c
> @@ -22,6 +22,8 @@
>  #include <linux/lsm_hooks.h>
>  #include <linux/magic.h>
>  
> +#include "lsm.h"
> +
>  static struct vfsmount *mount;
>  static int mount_count;
>  
> @@ -343,8 +345,29 @@ static struct dentry *lsm_dentry;
>  static ssize_t lsm_read(struct file *filp, char __user *buf, size_t count,
>  			loff_t *ppos)
>  {
> -	return simple_read_from_buffer(buf, count, ppos, lsm_names,
> -		strlen(lsm_names));
> +	int i;
> +	char *str;
> +	ssize_t rc, len = 0;
> +
> +	for (i = 0; i < lsm_count; i++)
> +		/* the '+ 1' accounts for either a comma or a NUL terminator */
> +		len += strlen(lsm_order[i]->id->name) + 1;
> +
> +	str = kmalloc(len, GFP_KERNEL);
> +	if (!str)
> +		return -ENOMEM;
> +	str[0] = '\0';
> +
> +	i = 0;
> +	while (i < lsm_count) {
> +		strcat(str, lsm_order[i]->id->name);
> +		if (++i < lsm_count)
> +			strcat(str, ",");
> +	}
> +
> +	rc = simple_read_from_buffer(buf, count, ppos, str, len);

This results in a trailing nul byte at the end of the string.

> +	kfree(str);
> +	return rc;
>  }
>  
>  static const struct file_operations lsm_ops = {
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 981ddb20f48e..978bb81b58fa 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -10,8 +10,6 @@
>  
>  #include "lsm.h"
>  
> -char *lsm_names;
> -
>  /* Pointers to LSM sections defined in include/asm-generic/vmlinux.lds.h */
>  extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
>  extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
> @@ -363,42 +361,6 @@ static void __init lsm_init_ordered(void)
>  	}
>  }
>  
> -static bool match_last_lsm(const char *list, const char *lsm)
> -{
> -	const char *last;
> -
> -	if (WARN_ON(!list || !lsm))
> -		return false;
> -	last = strrchr(list, ',');
> -	if (last)
> -		/* Pass the comma, strcmp() will check for '\0' */
> -		last++;
> -	else
> -		last = list;
> -	return !strcmp(last, lsm);
> -}
> -
> -static int lsm_append(const char *new, char **result)
> -{
> -	char *cp;
> -
> -	if (*result == NULL) {
> -		*result = kstrdup(new, GFP_KERNEL);
> -		if (*result == NULL)
> -			return -ENOMEM;
> -	} else {
> -		/* Check if it is the last registered name */
> -		if (match_last_lsm(*result, new))
> -			return 0;
> -		cp = kasprintf(GFP_KERNEL, "%s,%s", *result, new);
> -		if (cp == NULL)
> -			return -ENOMEM;
> -		kfree(*result);
> -		*result = cp;
> -	}
> -	return 0;
> -}
> -
>  static void __init lsm_static_call_init(struct security_hook_list *hl)
>  {
>  	struct lsm_static_call *scall = hl->scalls;
> @@ -435,15 +397,6 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
>  		hooks[i].lsmid = lsmid;
>  		lsm_static_call_init(&hooks[i]);
>  	}
> -
> -	/*
> -	 * Don't try to append during early_security_init(), we'll come back
> -	 * and fix this up afterwards.
> -	 */
> -	if (slab_is_available()) {
> -		if (lsm_append(lsmid->name, &lsm_names) < 0)
> -			panic("%s - Cannot get early memory.\n", __func__);
> -	}
>  }
>  
>  int __init early_security_init(void)
> @@ -480,8 +433,6 @@ int __init security_init(void)
>  	lsm_early_for_each_raw(lsm) {
>  		init_debug("  early started: %s (%s)\n", lsm->id->name,
>  			   is_enabled(lsm) ? "enabled" : "disabled");
> -		if (lsm->enabled)
> -			lsm_append(lsm->id->name, &lsm_names);
>  	}
>  
>  	/* Load LSMs in specified order. */

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 26/29] selinux: move initcalls to the LSM framework
  2025-04-09 18:50 ` [RFC PATCH 26/29] selinux: " Paul Moore
  2025-04-10 16:33   ` Stephen Smalley
@ 2025-05-23 15:12   ` Casey Schaufler
  1 sibling, 0 replies; 126+ messages in thread
From: Casey Schaufler @ 2025-05-23 15:12 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Mimi Zohar, Roberto Sassu, Fan Wu,
	Mickaël Salaün, Günther Noack, Kees Cook,
	Micah Morton, Tetsuo Handa, Casey Schaufler

On 4/9/2025 11:50 AM, Paul Moore wrote:
> SELinux currently has a number of initcalls so we've created a new
> function, selinux_initcall(), which wraps all of these initcalls so
> that we have a single initcall function that can be registered with the
> LSM framework.
>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
>  security/selinux/Makefile            |  2 +-
>  security/selinux/hooks.c             |  9 +++--
>  security/selinux/ibpkey.c            |  5 ++-
>  security/selinux/include/audit.h     |  5 +++
>  security/selinux/include/initcalls.h | 19 +++++++++++
>  security/selinux/initcalls.c         | 50 ++++++++++++++++++++++++++++
>  security/selinux/netif.c             |  5 ++-
>  security/selinux/netlink.c           |  5 ++-
>  security/selinux/netnode.c           |  5 ++-
>  security/selinux/netport.c           |  5 ++-
>  security/selinux/selinuxfs.c         |  5 ++-
>  security/selinux/ss/services.c       | 26 ++++-----------
>  12 files changed, 101 insertions(+), 40 deletions(-)
>  create mode 100644 security/selinux/include/initcalls.h
>  create mode 100644 security/selinux/initcalls.c
>
> diff --git a/security/selinux/Makefile b/security/selinux/Makefile
> index 66e56e9011df..72d3baf7900c 100644
> --- a/security/selinux/Makefile
> +++ b/security/selinux/Makefile
> @@ -15,7 +15,7 @@ ccflags-y := -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
>  ccflags-$(CONFIG_SECURITY_SELINUX_DEBUG) += -DDEBUG
>  
>  selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \
> -	     netnode.o netport.o status.o \
> +	     netnode.o netport.o status.o initcalls.o \
>  	     ss/ebitmap.o ss/hashtab.o ss/symtab.o ss/sidtab.o ss/avtab.o \
>  	     ss/policydb.o ss/services.o ss/conditional.o ss/mls.o ss/context.o
>  
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index f28a12a0a1c8..95b2399b1f4d 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -95,6 +95,7 @@
>  #include <linux/io_uring/cmd.h>
>  #include <uapi/linux/lsm.h>
>  
> +#include "initcalls.h"
>  #include "avc.h"
>  #include "objsec.h"
>  #include "netif.h"
> @@ -7535,6 +7536,10 @@ static __init int selinux_init(void)
>  	if (avc_add_callback(selinux_lsm_notifier_avc_callback, AVC_CALLBACK_RESET))
>  		panic("SELinux: Unable to register AVC LSM notifier callback\n");
>  
> +	if (avc_add_callback(selinux_audit_rule_avc_callback,
> +			     AVC_CALLBACK_RESET))
> +		panic("SELinux: Unable to register AVC audit callback\n");
> +
>  	if (selinux_enforcing_boot)
>  		pr_debug("SELinux:  Starting in enforcing mode\n");
>  	else
> @@ -7567,6 +7572,7 @@ DEFINE_LSM(selinux) = {
>  	.enabled = &selinux_enabled_boot,
>  	.blobs = &selinux_blob_sizes,
>  	.init = selinux_init,
> +	.initcall_device = selinux_initcall,
>  };
>  
>  #if defined(CONFIG_NETFILTER)
> @@ -7628,7 +7634,7 @@ static struct pernet_operations selinux_net_ops = {
>  	.exit = selinux_nf_unregister,
>  };
>  
> -static int __init selinux_nf_ip_init(void)
> +int __init selinux_nf_ip_init(void)
>  {
>  	int err;
>  
> @@ -7643,5 +7649,4 @@ static int __init selinux_nf_ip_init(void)
>  
>  	return 0;
>  }
> -__initcall(selinux_nf_ip_init);
>  #endif /* CONFIG_NETFILTER */
> diff --git a/security/selinux/ibpkey.c b/security/selinux/ibpkey.c
> index 48f537b41c58..2609913f338a 100644
> --- a/security/selinux/ibpkey.c
> +++ b/security/selinux/ibpkey.c
> @@ -23,6 +23,7 @@
>  #include <linux/list.h>
>  #include <linux/spinlock.h>
>  
> +#include "initcalls.h"
>  #include "ibpkey.h"
>  #include "objsec.h"
>  
> @@ -219,7 +220,7 @@ void sel_ib_pkey_flush(void)
>  	spin_unlock_irqrestore(&sel_ib_pkey_lock, flags);
>  }
>  
> -static __init int sel_ib_pkey_init(void)
> +int __init sel_ib_pkey_init(void)

Build failure if CONFIG_SECURITY_INFINIBAND is not set.

>  {
>  	int iter;
>  
> @@ -233,5 +234,3 @@ static __init int sel_ib_pkey_init(void)
>  
>  	return 0;
>  }
> -
> -subsys_initcall(sel_ib_pkey_init);
> diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h
> index d5b0425055e4..5989f8dd1e86 100644
> --- a/security/selinux/include/audit.h
> +++ b/security/selinux/include/audit.h
> @@ -15,6 +15,11 @@
>  #include <linux/audit.h>
>  #include <linux/types.h>
>  
> +/**
> + * XXX
> + */
> +int selinux_audit_rule_avc_callback(u32 event);
> +
>  /**
>   * selinux_audit_rule_init - alloc/init an selinux audit rule structure.
>   * @field: the field this rule refers to
> diff --git a/security/selinux/include/initcalls.h b/security/selinux/include/initcalls.h
> new file mode 100644
> index 000000000000..6674cf489473
> --- /dev/null
> +++ b/security/selinux/include/initcalls.h
> @@ -0,0 +1,19 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * SELinux initcalls
> + */
> +
> +#ifndef _SELINUX_INITCALLS_H
> +#define _SELINUX_INITCALLS_H
> +
> +int init_sel_fs(void);
> +int sel_netport_init(void);
> +int sel_netnode_init(void);
> +int sel_netif_init(void);
> +int sel_netlink_init(void);
> +int sel_ib_pkey_init(void);
> +int selinux_nf_ip_init(void);
> +
> +int selinux_initcall(void);
> +
> +#endif
> diff --git a/security/selinux/initcalls.c b/security/selinux/initcalls.c
> new file mode 100644
> index 000000000000..81f01f8ad215
> --- /dev/null
> +++ b/security/selinux/initcalls.c
> @@ -0,0 +1,50 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * SELinux initcalls
> + */
> +
> +#include <linux/init.h>
> +
> +#include "initcalls.h"
> +
> +/**
> + * selinux_initcall - Perform the SELinux initcalls
> + *
> + * Used as a device initcall in the SELinux LSM definition.
> + */
> +int __init selinux_initcall(void)
> +{
> +	int rc = 0, rc_tmp = 0;
> +
> +	rc_tmp = init_sel_fs();
> +	if (!rc && rc_tmp)
> +		rc = rc_tmp;
> +
> +	rc_tmp = sel_netport_init();
> +	if (!rc && rc_tmp)
> +		rc = rc_tmp;
> +
> +	rc_tmp = sel_netnode_init();
> +	if (!rc && rc_tmp)
> +		rc = rc_tmp;
> +
> +	rc_tmp = sel_netif_init();
> +	if (!rc && rc_tmp)
> +		rc = rc_tmp;
> +
> +	rc_tmp = sel_netlink_init();
> +	if (!rc && rc_tmp)
> +		rc = rc_tmp;
> +
> +	rc_tmp = sel_ib_pkey_init();
> +	if (!rc && rc_tmp)
> +		rc = rc_tmp;
> +
> +#if defined(CONFIG_NETFILTER)
> +	rc_tmp = selinux_nf_ip_init();
> +	if (!rc && rc_tmp)
> +		rc = rc_tmp;
> +#endif
> +
> +	return rc;
> +}
> diff --git a/security/selinux/netif.c b/security/selinux/netif.c
> index 43a0d3594b72..69f660721dc8 100644
> --- a/security/selinux/netif.c
> +++ b/security/selinux/netif.c
> @@ -22,6 +22,7 @@
>  #include <linux/rcupdate.h>
>  #include <net/net_namespace.h>
>  
> +#include "initcalls.h"
>  #include "security.h"
>  #include "objsec.h"
>  #include "netif.h"
> @@ -261,7 +262,7 @@ static struct notifier_block sel_netif_netdev_notifier = {
>  	.notifier_call = sel_netif_netdev_notifier_handler,
>  };
>  
> -static __init int sel_netif_init(void)
> +int __init sel_netif_init(void)
>  {
>  	int i;
>  
> @@ -276,5 +277,3 @@ static __init int sel_netif_init(void)
>  	return 0;
>  }
>  
> -__initcall(sel_netif_init);
> -
> diff --git a/security/selinux/netlink.c b/security/selinux/netlink.c
> index 1760aee712fd..eb40e4603475 100644
> --- a/security/selinux/netlink.c
> +++ b/security/selinux/netlink.c
> @@ -17,6 +17,7 @@
>  #include <net/net_namespace.h>
>  #include <net/netlink.h>
>  
> +#include "initcalls.h"
>  #include "security.h"
>  
>  static struct sock *selnl __ro_after_init;
> @@ -105,7 +106,7 @@ void selnl_notify_policyload(u32 seqno)
>  	selnl_notify(SELNL_MSG_POLICYLOAD, &seqno);
>  }
>  
> -static int __init selnl_init(void)
> +int __init sel_netlink_init(void)
>  {
>  	struct netlink_kernel_cfg cfg = {
>  		.groups	= SELNLGRP_MAX,
> @@ -117,5 +118,3 @@ static int __init selnl_init(void)
>  		panic("SELinux:  Cannot create netlink socket.");
>  	return 0;
>  }
> -
> -__initcall(selnl_init);
> diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c
> index 5c8c77e50aad..11b5eac30641 100644
> --- a/security/selinux/netnode.c
> +++ b/security/selinux/netnode.c
> @@ -30,6 +30,7 @@
>  #include <net/ip.h>
>  #include <net/ipv6.h>
>  
> +#include "initcalls.h"
>  #include "netnode.h"
>  #include "objsec.h"
>  
> @@ -287,7 +288,7 @@ void sel_netnode_flush(void)
>  	spin_unlock_bh(&sel_netnode_lock);
>  }
>  
> -static __init int sel_netnode_init(void)
> +int __init sel_netnode_init(void)
>  {
>  	int iter;
>  
> @@ -301,5 +302,3 @@ static __init int sel_netnode_init(void)
>  
>  	return 0;
>  }
> -
> -__initcall(sel_netnode_init);
> diff --git a/security/selinux/netport.c b/security/selinux/netport.c
> index 2e22ad9c2bd0..d1c12f58a628 100644
> --- a/security/selinux/netport.c
> +++ b/security/selinux/netport.c
> @@ -29,6 +29,7 @@
>  #include <net/ip.h>
>  #include <net/ipv6.h>
>  
> +#include "initcalls.h"
>  #include "netport.h"
>  #include "objsec.h"
>  
> @@ -220,7 +221,7 @@ void sel_netport_flush(void)
>  	spin_unlock_bh(&sel_netport_lock);
>  }
>  
> -static __init int sel_netport_init(void)
> +int __init sel_netport_init(void)
>  {
>  	int iter;
>  
> @@ -234,5 +235,3 @@ static __init int sel_netport_init(void)
>  
>  	return 0;
>  }
> -
> -__initcall(sel_netport_init);
> diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
> index 47480eb2189b..88d16c1dbb5a 100644
> --- a/security/selinux/selinuxfs.c
> +++ b/security/selinux/selinuxfs.c
> @@ -35,6 +35,7 @@
>  /* selinuxfs pseudo filesystem for exporting the security policy API.
>     Based on the proc code and the fs/nfsd/nfsctl.c code. */
>  
> +#include "initcalls.h"
>  #include "flask.h"
>  #include "avc.h"
>  #include "avc_ss.h"
> @@ -2131,7 +2132,7 @@ static struct file_system_type sel_fs_type = {
>  
>  struct path selinux_null __ro_after_init;
>  
> -static int __init init_sel_fs(void)
> +int __init init_sel_fs(void)
>  {
>  	struct qstr null_name = QSTR_INIT(NULL_FILE_NAME,
>  					  sizeof(NULL_FILE_NAME)-1);
> @@ -2175,5 +2176,3 @@ static int __init init_sel_fs(void)
>  
>  	return err;
>  }
> -
> -__initcall(init_sel_fs);
> diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
> index e431772c6168..d84a496e5f7f 100644
> --- a/security/selinux/ss/services.c
> +++ b/security/selinux/ss/services.c
> @@ -3534,6 +3534,13 @@ struct selinux_audit_rule {
>  	struct context au_ctxt;
>  };
>  
> +int selinux_audit_rule_avc_callback(u32 event)
> +{
> +	if (event == AVC_CALLBACK_RESET)
> +		return audit_update_lsm_rules();
> +	return 0;
> +}
> +
>  void selinux_audit_rule_free(void *vrule)
>  {
>  	struct selinux_audit_rule *rule = vrule;
> @@ -3784,25 +3791,6 @@ int selinux_audit_rule_match(struct lsm_prop *prop, u32 field, u32 op, void *vru
>  	return match;
>  }
>  
> -static int aurule_avc_callback(u32 event)
> -{
> -	if (event == AVC_CALLBACK_RESET)
> -		return audit_update_lsm_rules();
> -	return 0;
> -}
> -
> -static int __init aurule_init(void)
> -{
> -	int err;
> -
> -	err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET);
> -	if (err)
> -		panic("avc_add_callback() failed, error %d\n", err);
> -
> -	return err;
> -}
> -__initcall(aurule_init);
> -
>  #ifdef CONFIG_NETLABEL
>  /**
>   * security_netlbl_cache_add - Add an entry to the NetLabel cache

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 25/29] ima,evm: move initcalls to the LSM framework
  2025-04-09 18:50 ` [RFC PATCH 25/29] ima,evm: " Paul Moore
  2025-05-14 13:06   ` John Johansen
@ 2025-05-30 22:03   ` Mimi Zohar
  2025-06-11 20:27     ` Paul Moore
  1 sibling, 1 reply; 126+ messages in thread
From: Mimi Zohar @ 2025-05-30 22:03 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, linux-integrity, selinux
  Cc: John Johansen, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On Wed, 2025-04-09 at 14:50 -0400, Paul Moore wrote:
> This patch converts IMA and EVM to use the LSM frameworks's initcall
> mechanism.  There were two challenges to doing this conversion: the
> first simply being the number of initcalls across IMA and EVM, and the
> second was the number of resources shared between the two related,
> yet independent LSMs.

There are a number of the initcalls under integrity/platform/, which load arch
specific keys onto the platform and machine keyrings, which shouldn't be
included in this patch.

> 
> The first problem was resolved by the creation of two new functions,
> integrity_device_init() and integrity_late_init(), with each focused on
> calling all of the various IMA/EVM initcalls for a single initcall type.
> The second problem was resolved by registering both of these new
> functions as initcalls for each LSM and including code in each
> registered initcall to ensure it only executes once.

With the above change, there obviously will be a lot fewer initcalls, but it
might still make sense to keep the common ima/evm function.

Mimi

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 25/29] ima,evm: move initcalls to the LSM framework
  2025-05-14 13:06   ` John Johansen
@ 2025-06-11 20:09     ` Paul Moore
  0 siblings, 0 replies; 126+ messages in thread
From: Paul Moore @ 2025-06-11 20:09 UTC (permalink / raw)
  To: John Johansen
  Cc: linux-security-module, linux-integrity, selinux, Mimi Zohar,
	Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On Wed, May 14, 2025 at 9:06 AM John Johansen
<john.johansen@canonical.com> wrote:
> On 4/9/25 11:50, Paul Moore wrote:
> > This patch converts IMA and EVM to use the LSM frameworks's initcall
> > mechanism.  There were two challenges to doing this conversion: the
> > first simply being the number of initcalls across IMA and EVM, and the
> > second was the number of resources shared between the two related,
> > yet independent LSMs.
> >
> > The first problem was resolved by the creation of two new functions,
> > integrity_device_init() and integrity_late_init(), with each focused on
> > calling all of the various IMA/EVM initcalls for a single initcall type.
> > The second problem was resolved by registering both of these new
> > functions as initcalls for each LSM and including code in each
> > registered initcall to ensure it only executes once.
> >
> > Signed-off-by: Paul Moore <paul@paul-moore.com>
> > ---
> >   security/integrity/Makefile                   |  2 +-
> >   security/integrity/evm/evm_main.c             |  7 +-
> >   security/integrity/iint.c                     |  4 +-
> >   security/integrity/ima/ima_main.c             |  7 +-
> >   security/integrity/ima/ima_mok.c              |  4 +-
> >   security/integrity/initcalls.c                | 97 +++++++++++++++++++
> >   security/integrity/initcalls.h                | 23 +++++
> >   .../integrity/platform_certs/load_ipl_s390.c  |  4 +-
> >   .../integrity/platform_certs/load_powerpc.c   |  4 +-
> >   security/integrity/platform_certs/load_uefi.c |  4 +-
> >   .../platform_certs/machine_keyring.c          |  4 +-
> >   .../platform_certs/platform_keyring.c         | 14 ++-
> >   12 files changed, 147 insertions(+), 27 deletions(-)
> >   create mode 100644 security/integrity/initcalls.c
> >   create mode 100644 security/integrity/initcalls.h

...

> > diff --git a/security/integrity/initcalls.c b/security/integrity/initcalls.c
> > new file mode 100644
> > index 000000000000..de39754a1c2c
> > --- /dev/null
> > +++ b/security/integrity/initcalls.c
> > @@ -0,0 +1,97 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Platform certificate / keyring initcalls
> > + *
> > + */
> > +
> > +#include <linux/init.h>
> > +
> > +#include "initcalls.h"
> > +
> > +/**
> > + * integrity_device_init - device_initcalls for IMA/EVM
> > + *
> > + * This helper function wraps all of the device_initcalls for both IMA and EVM.
> > + * It can be called multiple times, e.g. once from IMA and once from EVM,
> > + * without problem as it maintains an internal static state variable which
> > + * ensures that any setup/initialization is only done once.
> > + */
> > +int __init integrity_device_init(void)
> > +{
> > +     int rc = 0, rc_tmp;
> if none of the below config options are defined then rc_tmp is unused and the build can kick out with
>
> ../security/integrity/initcalls.c:21:21: error: unused variable ‘rc_tmp’ [-Werror=unused-variable]

Thanks.  I fixed this by adding a __maybe_unused annotation as that
seemed like the cleanest fix.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 25/29] ima,evm: move initcalls to the LSM framework
  2025-05-30 22:03   ` Mimi Zohar
@ 2025-06-11 20:27     ` Paul Moore
  2025-06-13 20:34       ` Mimi Zohar
  0 siblings, 1 reply; 126+ messages in thread
From: Paul Moore @ 2025-06-11 20:27 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa

On Fri, May 30, 2025 at 6:04 PM Mimi Zohar <zohar@linux.ibm.com> wrote:
> On Wed, 2025-04-09 at 14:50 -0400, Paul Moore wrote:
> > This patch converts IMA and EVM to use the LSM frameworks's initcall
> > mechanism.  There were two challenges to doing this conversion: the
> > first simply being the number of initcalls across IMA and EVM, and the
> > second was the number of resources shared between the two related,
> > yet independent LSMs.
>
> There are a number of the initcalls under integrity/platform/, which load arch
> specific keys onto the platform and machine keyrings, which shouldn't be
> included in this patch.

I don't want to assume too much from your reply, but if the cert/key
loading under integrity/platform shouldn't be subject to the LSM
initcall rework, that implies that the integrity/platform cert/key
loading is independent of IMA/EVM and should perhaps live somewhere
else, e.g. security/keys?

Or am I misunderstanding something?

> > The first problem was resolved by the creation of two new functions,
> > integrity_device_init() and integrity_late_init(), with each focused on
> > calling all of the various IMA/EVM initcalls for a single initcall type.
> > The second problem was resolved by registering both of these new
> > functions as initcalls for each LSM and including code in each
> > registered initcall to ensure it only executes once.
>
> With the above change, there obviously will be a lot fewer initcalls, but it
> might still make sense to keep the common ima/evm function.

I'm not sure I understand, what do you mean by "common ima/evm
function"?  This patch doesn't remove any IMA/EVM functions, it adds
the integrity_device_init() and integrity_late_init() functions to
setup and populate some keyrings.

It's also worth mentioning that the goal of this patchset is not
necessarily to reduce initcalls, but rather to ensure that LSM
initcalls are only executed when the LSM is enabled, and to provide a
mechanism to notify kernel users when all of the LSMs have initialized
themselves.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 25/29] ima,evm: move initcalls to the LSM framework
  2025-06-11 20:27     ` Paul Moore
@ 2025-06-13 20:34       ` Mimi Zohar
  2025-07-21 21:59         ` Paul Moore
  0 siblings, 1 reply; 126+ messages in thread
From: Mimi Zohar @ 2025-06-13 20:34 UTC (permalink / raw)
  To: Paul Moore, David Howells
  Cc: linux-security-module, linux-integrity, selinux, John Johansen,
	Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa, Eric Snowberg

On Wed, 2025-06-11 at 16:27 -0400, Paul Moore wrote:
> On Fri, May 30, 2025 at 6:04 PM Mimi Zohar <zohar@linux.ibm.com> wrote:
> > On Wed, 2025-04-09 at 14:50 -0400, Paul Moore wrote:
> > > This patch converts IMA and EVM to use the LSM frameworks's initcall
> > > mechanism.  There were two challenges to doing this conversion: the
> > > first simply being the number of initcalls across IMA and EVM, and the
> > > second was the number of resources shared between the two related,
> > > yet independent LSMs.
> > 
> > There are a number of the initcalls under integrity/platform/, which load arch
> > specific keys onto the platform and machine keyrings, which shouldn't be
> > included in this patch.
> 
> I don't want to assume too much from your reply, but if the cert/key
> loading under integrity/platform shouldn't be subject to the LSM
> initcall rework, that implies that the integrity/platform cert/key
> loading is independent of IMA/EVM and should perhaps live somewhere
> else, e.g. security/keys?
> 
> Or am I misunderstanding something?

When the .platform keyring was upstreamed it was upstreamed for a very specific
purpose so that IMA could verify the kexec kernel image.  Afterwareds it was
immediately used to verify the pesigned kexec image.  Now it is being (ab)used
by other subsystems - ipe and dm-verity - and is being proposed by the "[PATCH
RFC 0/1] module: Optionally use .platform keyring for signatures verification".
From an integrity perspective this is definitely not a good idea.  The
discussion, which I'm sure you're aware of, is here:
https://lore.kernel.org/linux-integrity/20250602132535.897944-1-vkuznets@redhat.com/

It does not make any sense to move the code for the platform and machine
keyrings to security/keys.  If they need to move anywhere, it would be to the
certs/ directory.

> 
> > > The first problem was resolved by the creation of two new functions,
> > > integrity_device_init() and integrity_late_init(), with each focused on
> > > calling all of the various IMA/EVM initcalls for a single initcall type.
> > > The second problem was resolved by registering both of these new
> > > functions as initcalls for each LSM and including code in each
> > > registered initcall to ensure it only executes once.
> > 
> > With the above change, there obviously will be a lot fewer initcalls, but it
> > might still make sense to keep the common ima/evm function.
> 
> I'm not sure I understand, what do you mean by "common ima/evm
> function"?  This patch doesn't remove any IMA/EVM functions, it adds
> the integrity_device_init() and integrity_late_init() functions to
> setup and populate some keyrings.

"The above change" refers to not including the platform and the arch specific
calls or machine keyring initcalls.  By not including them, there are a lot
fewer initcalls in this ima,evm patch.

Mimi


^ permalink raw reply	[flat|nested] 126+ messages in thread

* Re: [RFC PATCH 25/29] ima,evm: move initcalls to the LSM framework
  2025-06-13 20:34       ` Mimi Zohar
@ 2025-07-21 21:59         ` Paul Moore
  0 siblings, 0 replies; 126+ messages in thread
From: Paul Moore @ 2025-07-21 21:59 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: David Howells, linux-security-module, linux-integrity, selinux,
	John Johansen, Roberto Sassu, Fan Wu, Mickaël Salaün,
	Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
	Tetsuo Handa, Eric Snowberg

On Fri, Jun 13, 2025 at 4:35 PM Mimi Zohar <zohar@linux.ibm.com> wrote:
> On Wed, 2025-06-11 at 16:27 -0400, Paul Moore wrote:
> > On Fri, May 30, 2025 at 6:04 PM Mimi Zohar <zohar@linux.ibm.com> wrote:
> > > On Wed, 2025-04-09 at 14:50 -0400, Paul Moore wrote:
> > > > This patch converts IMA and EVM to use the LSM frameworks's initcall
> > > > mechanism.  There were two challenges to doing this conversion: the
> > > > first simply being the number of initcalls across IMA and EVM, and the
> > > > second was the number of resources shared between the two related,
> > > > yet independent LSMs.
> > >
> > > There are a number of the initcalls under integrity/platform/, which load arch
> > > specific keys onto the platform and machine keyrings, which shouldn't be
> > > included in this patch.
> >
> > I don't want to assume too much from your reply, but if the cert/key
> > loading under integrity/platform shouldn't be subject to the LSM
> > initcall rework, that implies that the integrity/platform cert/key
> > loading is independent of IMA/EVM and should perhaps live somewhere
> > else, e.g. security/keys?
> >
> > Or am I misunderstanding something?
>
> When the .platform keyring was upstreamed it was upstreamed for a very specific
> purpose so that IMA could verify the kexec kernel image.  Afterwareds it was
> immediately used to verify the pesigned kexec image.  Now it is being (ab)used
> by other subsystems - ipe and dm-verity - and is being proposed by the "[PATCH
> RFC 0/1] module: Optionally use .platform keyring for signatures verification".
> From an integrity perspective this is definitely not a good idea.  The
> discussion, which I'm sure you're aware of, is here:
> https://lore.kernel.org/linux-integrity/20250602132535.897944-1-vkuznets@redhat.com/
>
> It does not make any sense to move the code for the platform and machine
> keyrings to security/keys.  If they need to move anywhere, it would be to the
> certs/ directory.

To bring some off-list discussions back on-list, and wrap up this
thread, Mimi has agreed to move the platform and machine keyring code
to the certs/ directory as they are no longer IMA/EVM-only keyrings.
I'll also be dropping them from the next revision of LSM
initialization rework patchset will be posted at some point this
evening (waiting on a testing refresh).

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 126+ messages in thread

end of thread, other threads:[~2025-07-21 21:59 UTC | newest]

Thread overview: 126+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-04-09 18:49 [RFC PATCH 0/29] Rework the LSM initialization Paul Moore
2025-04-09 18:49 ` [RFC PATCH 01/29] lsm: split the notifier code out into lsm_notifier.c Paul Moore
2025-04-09 21:17   ` Kees Cook
2025-04-15 12:14   ` John Johansen
2025-04-09 18:49 ` [RFC PATCH 02/29] lsm: split the init code out into lsm_init.c Paul Moore
2025-04-09 21:18   ` Kees Cook
2025-04-15 22:01   ` John Johansen
2025-04-09 18:49 ` [RFC PATCH 03/29] lsm: simplify prepare_lsm() and rename to lsm_prep_single() Paul Moore
2025-04-09 21:30   ` Kees Cook
2025-04-09 21:54     ` Paul Moore
2025-04-15 22:10   ` John Johansen
2025-04-09 18:49 ` [RFC PATCH 04/29] lsm: simplify ordered_lsm_init() and rename to lsm_init_ordered() Paul Moore
2025-04-09 21:38   ` Kees Cook
2025-04-09 22:31     ` Paul Moore
2025-04-09 18:49 ` [RFC PATCH 05/29] lsm: replace the name field with a pointer to the lsm_id struct Paul Moore
2025-04-09 21:40   ` Kees Cook
2025-04-15 22:20   ` John Johansen
2025-04-09 18:49 ` [RFC PATCH 06/29] lsm: cleanup and normalize the LSM order symbols naming Paul Moore
2025-04-09 23:00   ` Kees Cook
2025-04-15 22:23   ` John Johansen
2025-04-09 18:49 ` [RFC PATCH 07/29] lsm: rework lsm_active_cnt and lsm_idlist[] Paul Moore
2025-04-09 21:38   ` Casey Schaufler
2025-04-10 21:58     ` Paul Moore
2025-04-09 23:06   ` Kees Cook
2025-04-10 22:04     ` Paul Moore
2025-04-10 22:25       ` Kees Cook
2025-04-11  0:58         ` Casey Schaufler
2025-04-09 18:49 ` [RFC PATCH 08/29] lsm: get rid of the lsm_names list and do some cleanup Paul Moore
2025-04-09 23:13   ` Kees Cook
2025-04-10 22:47     ` Paul Moore
2025-04-11  2:15       ` Kees Cook
2025-04-11  3:14         ` Paul Moore
2025-04-15 22:30       ` John Johansen
2025-05-22 21:26   ` Casey Schaufler
2025-04-09 18:49 ` [RFC PATCH 09/29] lsm: cleanup and normalize the LSM enabled functions Paul Moore
2025-04-10  0:11   ` Kees Cook
2025-04-11  1:50     ` Paul Moore
2025-04-11  2:03       ` Paul Moore
2025-04-11  2:14       ` Paul Moore
2025-04-11  2:17         ` Kees Cook
2025-04-09 18:49 ` [RFC PATCH 10/29] lsm: cleanup the LSM blob size code Paul Moore
2025-04-09 23:29   ` Kees Cook
2025-04-15 23:02   ` John Johansen
2025-04-19  2:42   ` Fan Wu
2025-04-19  5:53     ` Kees Cook
2025-04-19 15:58       ` Fan Wu
2025-04-09 18:49 ` [RFC PATCH 11/29] lsm: cleanup initialize_lsm() and rename to lsm_init_single() Paul Moore
2025-04-09 23:30   ` Kees Cook
2025-04-15 23:04   ` John Johansen
2025-04-09 18:49 ` [RFC PATCH 12/29] lsm: cleanup the LSM ordered parsing Paul Moore
2025-04-09 18:49 ` [RFC PATCH 13/29] lsm: fold lsm_init_ordered() into security_init() Paul Moore
2025-04-09 18:49 ` [RFC PATCH 14/29] lsm: add missing function header comment blocks in lsm_init.c Paul Moore
2025-05-14 10:10   ` John Johansen
2025-04-09 18:50 ` [RFC PATCH 15/29] lsm: cleanup the debug and console output " Paul Moore
2025-04-09 18:50 ` [RFC PATCH 16/29] lsm: output available LSMs when debugging Paul Moore
2025-05-14 12:01   ` John Johansen
2025-04-09 18:50 ` [RFC PATCH 17/29] lsm: introduce an initcall mechanism into the LSM framework Paul Moore
2025-04-09 21:16   ` Kees Cook
2025-04-10 20:52     ` Paul Moore
2025-05-14 11:59   ` John Johansen
2025-04-09 18:50 ` [RFC PATCH 18/29] loadpin: move initcalls to " Paul Moore
2025-04-09 23:39   ` Kees Cook
2025-04-11  1:15     ` Paul Moore
2025-04-11  2:16       ` Kees Cook
2025-04-11  2:41         ` Paul Moore
2025-05-14 11:57   ` John Johansen
2025-04-09 18:50 ` [RFC PATCH 19/29] ipe: " Paul Moore
2025-04-09 23:40   ` Kees Cook
2025-04-14 21:19   ` Fan Wu
2025-04-15  1:58     ` Paul Moore
2025-05-14 12:02   ` John Johansen
2025-04-09 18:50 ` [RFC PATCH 20/29] smack: " Paul Moore
2025-04-09 23:42   ` Kees Cook
2025-04-11  2:30     ` Paul Moore
2025-04-10 17:30   ` Casey Schaufler
2025-04-10 17:47     ` Casey Schaufler
2025-04-11 20:09     ` Paul Moore
2025-04-14 21:04   ` Fan Wu
2025-04-15  1:54     ` Paul Moore
2025-04-09 18:50 ` [RFC PATCH 21/29] tomoyo: " Paul Moore
2025-04-09 23:43   ` Kees Cook
2025-05-14 12:05   ` John Johansen
2025-04-09 18:50 ` [RFC PATCH 22/29] safesetid: " Paul Moore
2025-04-09 23:43   ` Kees Cook
2025-04-11 19:20     ` Micah Morton
2025-04-11 20:45       ` Paul Moore
2025-05-14 12:18   ` John Johansen
2025-04-09 18:50 ` [RFC PATCH 23/29] apparmor: " Paul Moore
2025-04-09 23:44   ` Kees Cook
2025-05-14 13:33   ` John Johansen
2025-04-09 18:50 ` [RFC PATCH 24/29] lockdown: " Paul Moore
2025-04-09 23:44   ` Kees Cook
2025-05-14 13:31   ` John Johansen
2025-04-09 18:50 ` [RFC PATCH 25/29] ima,evm: " Paul Moore
2025-05-14 13:06   ` John Johansen
2025-06-11 20:09     ` Paul Moore
2025-05-30 22:03   ` Mimi Zohar
2025-06-11 20:27     ` Paul Moore
2025-06-13 20:34       ` Mimi Zohar
2025-07-21 21:59         ` Paul Moore
2025-04-09 18:50 ` [RFC PATCH 26/29] selinux: " Paul Moore
2025-04-10 16:33   ` Stephen Smalley
2025-04-11  3:24     ` Paul Moore
2025-05-23 15:12   ` Casey Schaufler
2025-04-09 18:50 ` [RFC PATCH 27/29] lsm: consolidate all of the LSM framework initcalls Paul Moore
2025-04-09 23:52   ` Kees Cook
2025-04-11  1:21     ` Paul Moore
2025-04-11  2:16       ` Kees Cook
2025-05-14 13:38   ` John Johansen
2025-04-09 18:50 ` [RFC PATCH 28/29] lsm: add a LSM_STARTED_ALL notification event Paul Moore
2025-04-09 23:53   ` Kees Cook
2025-05-14 13:34   ` John Johansen
2025-04-09 18:50 ` [RFC PATCH 29/29] lsm: add support for counting lsm_prop support among LSMs Paul Moore
2025-05-13 16:39   ` Casey Schaufler
2025-05-13 20:23     ` Paul Moore
2025-05-14 19:30       ` Casey Schaufler
2025-05-14 20:57         ` Paul Moore
2025-05-14 21:16           ` Casey Schaufler
2025-05-14 22:11             ` Paul Moore
2025-05-15 14:12               ` Casey Schaufler
2025-05-15 18:13                 ` Paul Moore
2025-05-15 19:41                   ` Casey Schaufler
2025-05-15 21:02                     ` Paul Moore
2025-04-10 14:13 ` [RFC PATCH 0/29] Rework the LSM initialization Casey Schaufler
2025-04-10 16:31   ` Kees Cook
2025-04-11  2:28   ` Paul Moore

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).