On 7/21/2025 4:21 PM, 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.
>
> Reviewed-by: Kees Cook <k...@kernel.org>
> Signed-off-by: Paul Moore <p...@paul-moore.com>

Reviewed-by: Casey Schaufler <ca...@schaufler-ca.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 ada9b5448409..ab739f9c2244 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
> @@ -455,3 +476,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);

Reply via email to