]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
lsm: introduce an initcall mechanism into the LSM framework
authorPaul Moore <paul@paul-moore.com>
Tue, 11 Feb 2025 17:18:35 +0000 (12:18 -0500)
committerPaul Moore <paul@paul-moore.com>
Wed, 22 Oct 2025 23:24:24 +0000 (19:24 -0400)
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.

Reviewed-by: Kees Cook <kees@kernel.org>
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: John Johansen <john.johhansen@canonical.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
include/linux/lsm_hooks.h
security/lsm_init.c

index 86e457aa88091cb49e57f6910d29e61eec375d72..b92008641242a4b162fc4a41db63ee4a3ccc74e4 100644 (file)
@@ -151,13 +151,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)                                                        \
index fd69bde9112eeeb13845d87208ba3b543d95835b..aacdac406ba5c97a8df28e633e0b7c1caef79fe6 100644 (file)
@@ -39,6 +39,27 @@ static __initdata struct lsm_info *lsm_exclusive;
        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
@@ -461,3 +482,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);