[RFC PATCH 17/29] lsm: introduce an initcall mechanism into the LSM framework
Kees Cook
kees at kernel.org
Wed Apr 9 21:16:37 UTC 2025
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 at 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 at kernel.org>
--
Kees Cook
More information about the Linux-security-module-archive
mailing list