[RFC PATCH 25/29] ima,evm: move initcalls to the LSM framework

John Johansen john.johansen at canonical.com
Wed May 14 13:06:30 UTC 2025


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 at 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);




More information about the Linux-security-module-archive mailing list