Each type of RoT devices should have a corresponding entry in ima_rots, a static array that represents entries' priority via their order. In case that `ima_rot=` is absent, the first device (which means with highest priority) that gets successfully initialized will be the RoT. Otherwise, the framework will only try to initialize the one specified by `ima_rot=`, and there will be no RoT if the initialization fails.
All necessary hooks and variables of the RoT entry should be set at least when .init() is finished. Signed-off-by: GONG Ruiqi <gongrui...@huawei.com> --- security/integrity/ima/Makefile | 2 +- security/integrity/ima/ima.h | 2 + security/integrity/ima/ima_init.c | 1 + security/integrity/ima/ima_rot.c | 98 +++++++++++++++++++++++++++++++ security/integrity/ima/ima_rot.h | 42 +++++++++++++ 5 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 security/integrity/ima/ima_rot.c create mode 100644 security/integrity/ima/ima_rot.h diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile index b376d38b4ee6..b3c8436d941c 100644 --- a/security/integrity/ima/Makefile +++ b/security/integrity/ima/Makefile @@ -7,7 +7,7 @@ obj-$(CONFIG_IMA) += ima.o ima_iint.o ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \ - ima_policy.o ima_template.o ima_template_lib.o + ima_policy.o ima_template.o ima_template_lib.o ima_rot.o ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o ima-$(CONFIG_IMA_APPRAISE_MODSIG) += ima_modsig.o ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index e3d71d8d56e3..d3375427dc24 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -23,6 +23,7 @@ #include <crypto/hash_info.h> #include "../integrity.h" +#include "ima_rot.h" enum ima_show_type { IMA_SHOW_BINARY, IMA_SHOW_BINARY_NO_FIELD_LEN, IMA_SHOW_BINARY_OLD_STRING_FMT, IMA_SHOW_ASCII }; @@ -64,6 +65,7 @@ extern struct ima_algo_desc *ima_algo_array __ro_after_init; extern int ima_appraise; extern struct tpm_chip *ima_tpm_chip; +extern struct ima_rot *ima_rot_inst; extern const char boot_aggregate_name[]; /* IMA event related data */ diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index a2f34f2d8ad7..15c51e1b369c 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -23,6 +23,7 @@ /* name for boot aggregate entry */ const char boot_aggregate_name[] = "boot_aggregate"; struct tpm_chip *ima_tpm_chip; +struct ima_rot *ima_rot_inst; /* Add the boot aggregate to the IMA measurement list and extend * the PCR register. diff --git a/security/integrity/ima/ima_rot.c b/security/integrity/ima/ima_rot.c new file mode 100644 index 000000000000..7a1ae056ea5d --- /dev/null +++ b/security/integrity/ima/ima_rot.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2025 Huawei Technologies Co., Ltd. + * + * Authors: + * GONG Ruiqi <gongrui...@huawei.com> + * + * File: ima_rot.c + * IMA rot layer + */ + +#include <linux/types.h> +#include <linux/list.h> +#include <linux/gfp_types.h> + +#include "ima.h" + +/* + * Meaning of preferred_rot_name's value: + * + * - NULL: User doesn't specify one. + * - NAME_UNKNOWN: User specifies an unknown RoT name. + * - (Valid RoT name): User specifies a valid name. + * + * Which corresponds to cases of `ima_rot=`. + */ +static const char *preferred_rot_name; +#define NAME_UNKNOWN "UNKNOWN" + +/* + * The list containing all possible RoT devices. + * + * The order of RoTs inside the list implies priority. + * IOW, RoT device that owns higher priority should be placed at the front. + */ +static struct ima_rot ima_rots[] = { +}; + +/** + * ima_rot_name() - Process RoT device name that user provides. + * @str: Name of RoT device. + * + * The back-end handler of `ima_rot=` kernel cmdline, by which users can specify + * the Root of Trust (RoT) device for IMA. How system will react to each case of + * this cmdline's value is explained as follows: + * + * - Absent: Choose an RoT device based on priority, try to initialize it and + * give up if it fails. + * + * - Invalid/Unknown RoT name: Give up RoT initialization. IMA will run without + * an RoT device. + * + * - Valid RoT name: Try to initialize this RoT device and give up if it fails. + * + * Return: Always return 1. + */ +static int __init ima_rot_name(char *str) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ima_rots); i++) { + if (!strcmp(str, ima_rots[i].name)) { + preferred_rot_name = str; + break; + } + } + + if (!preferred_rot_name) { + pr_info("%s is NOT implemented as an IMA RoT\n", str); + preferred_rot_name = NAME_UNKNOWN; + } + + return 1; +} +__setup("ima_rot=", ima_rot_name); + +/* + * Pick the most prioritized RoT that can be initialized successfully. + */ +struct ima_rot * __init ima_rot_init(void) +{ + int rc, i; + + for (i = 0; i < ARRAY_SIZE(ima_rots); i++) { + if (preferred_rot_name && strcmp(preferred_rot_name, ima_rots[i].name)) + continue; + + pr_info("IMA RoT initializing %s\n", ima_rots[i].name); + rc = ima_rots[i].init(&ima_rots[i]); + if (!rc) { + pr_info("%s initialized and taken as IMA RoT\n", ima_rots[i].name); + return &ima_rots[i]; + } + pr_debug("%s failed to self-initialize (%d)\n", ima_rots[i].name, rc); + } + + return NULL; +} diff --git a/security/integrity/ima/ima_rot.h b/security/integrity/ima/ima_rot.h new file mode 100644 index 000000000000..f88f8162d6c8 --- /dev/null +++ b/security/integrity/ima/ima_rot.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2025 Huawei Technologies Co., Ltd. + * + * Authors: + * GONG Ruiqi <gongrui...@huawei.com> + * + * File: ima_rot.h + * IMA rot layer + */ + +#ifndef __LINUX_IMA_ROT_H +#define __LINUX_IMA_ROT_H + +#include <linux/tpm.h> + +/** + * struct ima_rot - Root of Trust (RoT) device instance. + * @name: Name of the device. + * @default_pcr: Index of default (virtual) PCR. + * @nr_allocated_banks: Number of (virtual) TPM banks. + * @allocated_banks: Info of (virtual) TPM bank. + * @init: Initializes this device to be an IMA RoT. + * @extend: Performs a hash extend operation to the device's (virtual) PCR. + * @calc_boot_aggregate: Generate the initial value of IMA measurement list + * (i.e. boot aggregate). + * + * Attributes and methods necessary for a device working as an RoT for IMA. + */ +struct ima_rot { + const char *name; + int default_pcr; + int nr_allocated_banks; + struct tpm_bank_info *allocated_banks; + + int (*init)(struct ima_rot *rot); + int (*extend)(struct tpm_digest *digests_arg, const void *args); + int (*calc_boot_aggregate)(struct ima_digest_data *hash); +}; + +struct ima_rot *ima_rot_init(void); +#endif /* __LINUX_IMA_ROT_H */ -- 2.25.1