[PATCH RFC 2/3] security: IMA: introduce ima_mr structure
flat view
WARM3d
From: Yeoreum Yun <hidden>
Date: 2026-09-30 13:44:41
Also in:
linux-arm-kernel, linux-coco, linux-integrity, lkml
Subsystem:
extended verification module (evm), integrity measurement architecture (ima), security subsystem, the rest · Maintainers:
Mimi Zohar, Roberto Sassu, Dmitry Kasatkin, Paul Moore, James Morris, "Serge E. Hallyn", Linus Torvalds
This is preparatory patch to integrate tsm measurement registers with IMA.
To integrate tsm measurement registers, introcude ima_mr structure
which abstract measurements register and ima_mr_operation structure
which defines below operations to communicate with them:
- mr_init(): find and initialise to communicate measurement registers
- mr_get_bank_info: get information of bank of measurement registers.
- mr_calc_boot_aggregate: generate boot aggregate hash with
measurement registers.
- mr_extend: extend measurement registers.
Also, this patch adds ima_mr using TPM device using PCR as
measurement registers.
Signed-off-by: Yeoreum Yun <redacted>
---
security/integrity/ima/Makefile | 2 +-
security/integrity/ima/ima.h | 7 +-
security/integrity/ima/ima_api.c | 4 +-
security/integrity/ima/ima_crypto.c | 137 +++++++++-----------------
security/integrity/ima/ima_fs.c | 16 ++-
security/integrity/ima/ima_init.c | 7 +-
security/integrity/ima/ima_mr.c | 47 +++++++++
security/integrity/ima/ima_mr.h | 75 +++++++++++++++
security/integrity/ima/ima_mr_tpm.c | 155 ++++++++++++++++++++++++++++++
security/integrity/ima/ima_queue.c | 39 ++++----
security/integrity/ima/ima_template.c | 4 +-
security/integrity/ima/ima_template_lib.c | 2 +-
12 files changed, 365 insertions(+), 130 deletions(-)
diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile
index b376d38b4ee6..f2c46b405a00 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_mr.o ima_mr_tpm.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 10214f73ca1e..5e43d3140357 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h@@ -22,11 +22,11 @@ #include <linux/audit.h> #include <crypto/hash_info.h> +#include "ima_mr.h" #include "../integrity.h" enum ima_show_type { IMA_SHOW_BINARY, IMA_SHOW_BINARY_NO_FIELD_LEN, IMA_SHOW_BINARY_OLD_STRING_FMT, IMA_SHOW_ASCII }; -enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8, TPM_PCR10 = 10 }; /* * BINARY: current binary measurements list
@@ -50,8 +50,6 @@ enum binary_lists { #define IMA_TEMPLATE_IMA_NAME "ima" #define IMA_TEMPLATE_IMA_FMT "d|n" -#define NR_BANKS(chip) ((chip != NULL) ? chip->nr_allocated_banks : 0) - /* current content of the policy */ extern int ima_policy_flag;
@@ -75,7 +73,6 @@ extern int ima_extra_slots __ro_after_init; extern struct ima_algo_desc *ima_algo_array __ro_after_init; extern int ima_appraise; -extern struct tpm_chip *ima_tpm_chip; extern const char boot_aggregate_name[]; extern const char boot_aggregate_late_name[];
@@ -118,7 +115,7 @@ struct ima_template_desc { struct ima_template_entry { int pcr; - struct tpm_digest *digests; + mr_digest_t *digests; struct ima_template_desc *template_desc; /* template descriptor */ u32 template_data_len; struct ima_field_data template_data[]; /* template related data */
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index 122d127e108d..8a7194a26b81 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c@@ -40,7 +40,7 @@ int ima_alloc_init_template(struct ima_event_data *event_data, struct ima_template_desc *desc) { struct ima_template_desc *template_desc; - struct tpm_digest *digests; + mr_digest_t *digests; int i, result = 0; if (desc)
@@ -54,7 +54,7 @@ int ima_alloc_init_template(struct ima_event_data *event_data, return -ENOMEM; digests = kzalloc_objs(*digests, - NR_BANKS(ima_tpm_chip) + ima_extra_slots, + NR_BANKS(ima_mr) + ima_extra_slots, GFP_NOFS); if (!digests) { kfree(*entry);
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
index 0d72b48249ee..efa27ce5f128 100644
--- a/security/integrity/ima/ima_crypto.c
+++ b/security/integrity/ima/ima_crypto.c@@ -58,7 +58,7 @@ static struct crypto_shash *ima_alloc_tfm(enum hash_algo algo) if (algo == ima_hash_algo) return tfm; - for (i = 0; i < NR_BANKS(ima_tpm_chip) + ima_extra_slots; i++) + for (i = 0; i < NR_BANKS(ima_mr) + ima_extra_slots; i++) if (ima_algo_array[i].tfm && ima_algo_array[i].algo == algo) return ima_algo_array[i].tfm;
@@ -77,6 +77,7 @@ int __init ima_init_crypto(void) enum hash_algo algo; long rc; int i; + mr_bank_info_t bank_info; rc = ima_init_ima_crypto(); if (rc)
@@ -85,8 +86,12 @@ int __init ima_init_crypto(void) ima_sha1_idx = -1; ima_hash_algo_idx = -1; - for (i = 0; i < NR_BANKS(ima_tpm_chip); i++) { - algo = ima_tpm_chip->allocated_banks[i].crypto_id; + for (i = 0; i < NR_BANKS(ima_mr); i++) { + rc = ima_mr->ops->mr_get_bank_info(ima_mr, i, &bank_info); + if (rc) + return rc; + + algo = bank_info.crypto_id; if (algo == HASH_ALGO_SHA1) ima_sha1_idx = i;
@@ -95,24 +100,28 @@ int __init ima_init_crypto(void) } if (ima_sha1_idx < 0) { - ima_sha1_idx = NR_BANKS(ima_tpm_chip) + ima_extra_slots++; + ima_sha1_idx = NR_BANKS(ima_mr) + ima_extra_slots++; if (ima_hash_algo == HASH_ALGO_SHA1) ima_hash_algo_idx = ima_sha1_idx; } if (ima_hash_algo_idx < 0) - ima_hash_algo_idx = NR_BANKS(ima_tpm_chip) + ima_extra_slots++; + ima_hash_algo_idx = NR_BANKS(ima_mr) + ima_extra_slots++; ima_algo_array = kzalloc_objs(*ima_algo_array, - NR_BANKS(ima_tpm_chip) + ima_extra_slots); + NR_BANKS(ima_mr) + ima_extra_slots); if (!ima_algo_array) { rc = -ENOMEM; goto out; } - for (i = 0; i < NR_BANKS(ima_tpm_chip); i++) { - algo = ima_tpm_chip->allocated_banks[i].crypto_id; - digest_size = ima_tpm_chip->allocated_banks[i].digest_size; + for (i = 0; i < NR_BANKS(ima_mr); i++) { + rc = ima_mr->ops->mr_get_bank_info(ima_mr, i, &bank_info); + if (rc) + return rc; + + algo = bank_info.crypto_id; + digest_size = bank_info.digest_size; ima_algo_array[i].algo = algo; ima_algo_array[i].digest_size = digest_size;
@@ -137,7 +146,7 @@ int __init ima_init_crypto(void) } } - if (ima_sha1_idx >= NR_BANKS(ima_tpm_chip)) { + if (ima_sha1_idx >= NR_BANKS(ima_mr)) { if (ima_hash_algo == HASH_ALGO_SHA1) { ima_algo_array[ima_sha1_idx].tfm = ima_shash_tfm; } else {
@@ -153,7 +162,7 @@ int __init ima_init_crypto(void) ima_algo_array[ima_sha1_idx].digest_size = SHA1_DIGEST_SIZE; } - if (ima_hash_algo_idx >= NR_BANKS(ima_tpm_chip) && + if (ima_hash_algo_idx >= NR_BANKS(ima_mr) && ima_hash_algo_idx != ima_sha1_idx) { digest_size = hash_digest_size[ima_hash_algo]; ima_algo_array[ima_hash_algo_idx].tfm = ima_shash_tfm;
@@ -163,7 +172,7 @@ int __init ima_init_crypto(void) return 0; out_array: - for (i = 0; i < NR_BANKS(ima_tpm_chip) + ima_extra_slots; i++) { + for (i = 0; i < NR_BANKS(ima_mr) + ima_extra_slots; i++) { if (!ima_algo_array[i].tfm || ima_algo_array[i].tfm == ima_shash_tfm) continue;
@@ -183,7 +192,7 @@ static void ima_free_tfm(struct crypto_shash *tfm) if (tfm == ima_shash_tfm) return; - for (i = 0; i < NR_BANKS(ima_tpm_chip) + ima_extra_slots; i++) + for (i = 0; i < NR_BANKS(ima_mr) + ima_extra_slots; i++) if (ima_algo_array[i].tfm == tfm) return;
@@ -335,7 +344,7 @@ static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data, int ima_calc_field_array_hash(struct ima_field_data *field_data, struct ima_template_entry *entry) { - u16 alg_id; + mr_bank_info_t bank_info; int rc, i; rc = ima_calc_field_array_hash_tfm(field_data, entry, ima_sha1_idx);
@@ -344,13 +353,16 @@ int ima_calc_field_array_hash(struct ima_field_data *field_data, entry->digests[ima_sha1_idx].alg_id = TPM_ALG_SHA1; - for (i = 0; i < NR_BANKS(ima_tpm_chip) + ima_extra_slots; i++) { + for (i = 0; i < NR_BANKS(ima_mr) + ima_extra_slots; i++) { if (i == ima_sha1_idx) continue; - if (i < NR_BANKS(ima_tpm_chip)) { - alg_id = ima_tpm_chip->allocated_banks[i].alg_id; - entry->digests[i].alg_id = alg_id; + if (i < NR_BANKS(ima_mr)) { + rc = ima_mr->ops->mr_get_bank_info(ima_mr, i, &bank_info); + if (rc) + return rc; + + entry->digests[i].alg_id = bank_info.alg_id; } /* for unmapped TPM algorithms digest is still a padded SHA1 */
@@ -414,87 +426,26 @@ int ima_calc_buffer_hash(const void *buf, loff_t len, return rc; } -static void ima_pcrread(u32 idx, struct tpm_digest *d) -{ - if (!ima_tpm_chip) - return; - - if (tpm_pcr_read(ima_tpm_chip, idx, d) != 0) - pr_err("Error Communicating to TPM chip\n"); -} - -/* - * The boot_aggregate is a cumulative hash over TPM registers 0 - 7. With - * TPM 1.2 the boot_aggregate was based on reading the SHA1 PCRs, but with - * TPM 2.0 hash agility, TPM chips could support multiple TPM PCR banks, - * allowing firmware to configure and enable different banks. - * - * Knowing which TPM bank is read to calculate the boot_aggregate digest - * needs to be conveyed to a verifier. For this reason, use the same - * hash algorithm for reading the TPM PCRs as for calculating the boot - * aggregate digest as stored in the measurement list. - */ -static int ima_calc_boot_aggregate_tfm(char *digest, u16 alg_id, - struct crypto_shash *tfm) -{ - struct tpm_digest d = { .alg_id = alg_id, .digest = {0} }; - int rc; - u32 i; - SHASH_DESC_ON_STACK(shash, tfm); - - shash->tfm = tfm; - - pr_devel("calculating the boot-aggregate based on TPM bank: %04x\n", - d.alg_id); - - rc = crypto_shash_init(shash); - if (rc != 0) - return rc; - - /* cumulative digest over TPM registers 0-7 */ - for (i = TPM_PCR0; i < TPM_PCR8; i++) { - ima_pcrread(i, &d); - /* now accumulate with current aggregate */ - rc = crypto_shash_update(shash, d.digest, - crypto_shash_digestsize(tfm)); - if (rc != 0) - return rc; - } - /* - * Extend cumulative digest over TPM registers 8-9, which contain - * measurement for the kernel command line (reg. 8) and image (reg. 9) - * in a typical PCR allocation. Registers 8-9 are only included in - * non-SHA1 boot_aggregate digests to avoid ambiguity. - */ - if (alg_id != TPM_ALG_SHA1) { - for (i = TPM_PCR8; i < TPM_PCR10; i++) { - ima_pcrread(i, &d); - rc = crypto_shash_update(shash, d.digest, - crypto_shash_digestsize(tfm)); - } - } - if (!rc) - rc = crypto_shash_final(shash, digest); - return rc; -} - int ima_calc_boot_aggregate(struct ima_digest_data *hash) { struct crypto_shash *tfm; - u16 crypto_id, alg_id; + mr_bank_info_t bank_info; int rc, i, bank_idx = -1; - for (i = 0; i < ima_tpm_chip->nr_allocated_banks; i++) { - crypto_id = ima_tpm_chip->allocated_banks[i].crypto_id; - if (crypto_id == hash->algo) { + for (i = 0; i < NR_BANKS(ima_mr); i++) { + rc = ima_mr->ops->mr_get_bank_info(ima_mr, i, &bank_info); + if (rc) + return rc; + + if (bank_info.crypto_id == hash->algo) { bank_idx = i; break; } - if (crypto_id == HASH_ALGO_SHA256) + if (bank_info.crypto_id == HASH_ALGO_SHA256) bank_idx = i; - if (bank_idx == -1 && crypto_id == HASH_ALGO_SHA1) + if (bank_idx == -1 && bank_info.crypto_id == HASH_ALGO_SHA1) bank_idx = i; }
@@ -503,15 +454,19 @@ int ima_calc_boot_aggregate(struct ima_digest_data *hash) return 0; } - hash->algo = ima_tpm_chip->allocated_banks[bank_idx].crypto_id; + rc = ima_mr->ops->mr_get_bank_info(ima_mr, bank_idx, &bank_info); + if (rc) + return rc; + + hash->algo = bank_info.crypto_id; tfm = ima_alloc_tfm(hash->algo); if (IS_ERR(tfm)) return PTR_ERR(tfm); hash->length = crypto_shash_digestsize(tfm); - alg_id = ima_tpm_chip->allocated_banks[bank_idx].alg_id; - rc = ima_calc_boot_aggregate_tfm(hash->digest, alg_id, tfm); + rc = ima_mr->ops->mr_calc_boot_aggregate(ima_mr, bank_idx, + hash->digest, tfm); ima_free_tfm(tfm);
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 2a0bca554316..cfe1d5227e54 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c@@ -635,7 +635,9 @@ static int __init create_securityfs_measurement_lists(bool staging) const struct file_operations *binary_ops = &ima_measurements_ops; umode_t permissions = (S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP); const char *file_suffix = ""; - int count = NR_BANKS(ima_tpm_chip); + int count = NR_BANKS(ima_mr); + int rc; + mr_bank_info_t bank_info; if (staging) { ascii_ops = &ima_ascii_measurements_staged_ops;
@@ -643,7 +645,7 @@ static int __init create_securityfs_measurement_lists(bool staging) file_suffix = "_staged"; } - if (ima_sha1_idx >= NR_BANKS(ima_tpm_chip)) + if (ima_sha1_idx >= NR_BANKS(ima_mr)) count++; for (int i = 0; i < count; i++) {
@@ -651,10 +653,16 @@ static int __init create_securityfs_measurement_lists(bool staging) char file_name[NAME_MAX + 1]; struct dentry *dentry; + if (algo == HASH_ALGO__LAST) { + rc = ima_mr->ops->mr_get_bank_info(ima_mr, i, &bank_info); + if (rc) + return rc; + } + if (algo == HASH_ALGO__LAST) snprintf(file_name, sizeof(file_name), "ascii_runtime_measurements_tpm_alg_%x%s", - ima_tpm_chip->allocated_banks[i].alg_id, + bank_info.alg_id, file_suffix); else snprintf(file_name, sizeof(file_name),
@@ -669,7 +677,7 @@ static int __init create_securityfs_measurement_lists(bool staging) if (algo == HASH_ALGO__LAST) snprintf(file_name, sizeof(file_name), "binary_runtime_measurements_tpm_alg_%x%s", - ima_tpm_chip->allocated_banks[i].alg_id, + bank_info.alg_id, file_suffix); else snprintf(file_name, sizeof(file_name),
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index d53f4d89a53e..a1290e891fa4 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c@@ -23,7 +23,6 @@ /* name for boot aggregate entry */ const char boot_aggregate_name[] = "boot_aggregate"; const char boot_aggregate_late_name[] = "boot_aggregate_late"; -struct tpm_chip *ima_tpm_chip; /* Add the boot aggregate to the IMA measurement list and extend * the PCR register.
@@ -78,7 +77,7 @@ static int __init ima_add_boot_aggregate(void) * Ultimately select SHA1 also for TPM 2.0 if the SHA256 PCR bank * is not found. */ - if (ima_tpm_chip) { + if (ima_mr) { result = ima_calc_boot_aggregate(hash_hdr); if (result < 0) { audit_cause = "hashing_error";
@@ -126,9 +125,7 @@ int __init ima_init(void) { int rc; - ima_tpm_chip = tpm_default_chip(); - if (!ima_tpm_chip) - pr_info("No TPM chip found, activating TPM-bypass!\n"); + ima_init_mr(); rc = integrity_init_keyring(INTEGRITY_KEYRING_IMA); if (rc)
diff --git a/security/integrity/ima/ima_mr.c b/security/integrity/ima/ima_mr.c
new file mode 100644
index 000000000000..fe58eb968954
--- /dev/null
+++ b/security/integrity/ima/ima_mr.c@@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Arm Ltd + * + * Author: + * Yeoreum Yun <yeoreum.yun@arm.com> + */ + +#include <linux/kernel.h> +#include <linux/slab.h> + +#include "ima.h" + +struct ima_mr *ima_mr; + +static struct ima_mr_operations *ima_mr_ops[] = { + &ima_mr_tpm_operations, +}; + +void __init ima_init_mr(void) +{ + int rc, i; + + ima_mr = kmalloc_obj(*ima_mr); + if (!ima_mr) { + pr_info("Out of memory creating MR, activating MR-bypass!\n"); + return; + } + + rc = -ENODEV; + for (i = 0; i < ARRAY_SIZE(ima_mr_ops); i++) { + if (!ima_mr_ops[i]->supported) + continue; + + rc = ima_mr_ops[i]->mr_init(ima_mr); + if (!rc) { + pr_info("MR device found: %s\n", ima_mr_ops[i]->name); + break; + } + } + + if (rc) { + pr_info("No MR device found, activating MR-bypass!\n"); + kfree(ima_mr); + ima_mr = NULL; + } +}
diff --git a/security/integrity/ima/ima_mr.h b/security/integrity/ima/ima_mr.h
new file mode 100644
index 000000000000..23b85522da34
--- /dev/null
+++ b/security/integrity/ima/ima_mr.h@@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Arm Ltd + * + * Author: + * Yeoreum Yun <yeoreum.yun@arm.com> + */ + +#ifndef __LINUX_IMA_MR_H +#define __LINUX_IMA_MR_H + +#include <linux/types.h> +#include <linux/crypto.h> +#include <linux/hash.h> +#include <linux/tpm.h> + +#define NR_BANKS(mr) ((mr != NULL) ? mr->nr_banks : 0) + +typedef struct tpm_bank_info mr_bank_info_t; +typedef struct tpm_digest mr_digest_t; + +enum tpm_pcrs { + TPM_PCR0 = 0, + TPM_PCR1 = 1, + TPM_PCR2 = 2, + TPM_PCR7 = 7, + TPM_PCR8 = 8, + TPM_PCR10 = 10, + TPM_PCR16 = 16, +}; + +struct ima_mr_operations; + +struct ima_mr { + int nr_banks; + struct ima_mr_operations *ops; + void *data; +}; + +struct ima_mr_operations { + const char *name; + bool supported; + int (*mr_init)(struct ima_mr *mr); + int (*mr_get_bank_info)(struct ima_mr *mr, int bank, + mr_bank_info_t *info); + int (*mr_calc_boot_aggregate)(struct ima_mr *mr, int bank, + char *digest, struct crypto_shash *tfm); + int (*mr_extend)(struct ima_mr *mr, u32 pcr_idx, + mr_digest_t *digests); +}; + +extern struct ima_mr *ima_mr; +extern struct ima_mr_operations ima_mr_tpm_operations; + +void __init ima_init_mr(void); + +static __always_inline u16 hash_to_alg(u16 hash_id) +{ + switch (hash_id) { + case HASH_ALGO_SHA1: + return TPM_ALG_SHA1; + case HASH_ALGO_SHA256: + return TPM_ALG_SHA256; + case HASH_ALGO_SHA384: + return TPM_ALG_SHA384; + case HASH_ALGO_SHA512: + return TPM_ALG_SHA512; + case HASH_ALGO_SM3_256: + return TPM_ALG_SM3_256; + default: + return TPM_ALG_ERROR; + } +} + +#endif /* __LINUX_IMA_MR_H */
diff --git a/security/integrity/ima/ima_mr_tpm.c b/security/integrity/ima/ima_mr_tpm.c
new file mode 100644
index 000000000000..edee83d5a551
--- /dev/null
+++ b/security/integrity/ima/ima_mr_tpm.c@@ -0,0 +1,155 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Arm Ltd + * + * Author: + * Yeoreum Yun <yeoreum.yun@arm.com> + */ + +#include <linux/kernel.h> + +#include "ima.h" + +static int tpm_mr_init(struct ima_mr *mr) +{ + struct tpm_chip *tpm_chip; + + if (!mr) + return -EINVAL; + + tpm_chip = tpm_default_chip(); + if (!tpm_chip) { + pr_info("No TPM chip found!\n"); + return -ENODEV; + } + + mr->data = tpm_chip; + mr->nr_banks = tpm_chip->nr_allocated_banks; + mr->ops = &ima_mr_tpm_operations; + + return 0; +} + +static int tpm_mr_get_bank_info(struct ima_mr *mr, int bank, + mr_bank_info_t *info) +{ + struct tpm_chip *tpm_chip; + + if (!mr || !mr->data || !info || (bank >= mr->nr_banks)) + return -EINVAL; + + tpm_chip = mr->data; + info->alg_id = tpm_chip->allocated_banks[bank].alg_id; + info->digest_size = tpm_chip->allocated_banks[bank].digest_size; + info->crypto_id = tpm_chip->allocated_banks[bank].crypto_id; + + if (WARN_ON_ONCE((info->crypto_id != HASH_ALGO__LAST) && + (hash_to_alg(info->crypto_id) != info->alg_id))) + return -ENODEV; + + return 0; +} + +/* + * The boot_aggregate is a cumulative hash over TPM registers 0 - 7. With + * TPM 1.2 the boot_aggregate was based on reading the SHA1 PCRs, but with + * TPM 2.0 hash agility, TPM chips could support multiple TPM PCR banks, + * allowing firmware to configure and enable different banks. + * + * Knowing which TPM bank is read to calculate the boot_aggregate digest + * needs to be conveyed to a verifier. For this reason, use the same + * hash algorithm for reading the TPM PCRs as for calculating the boot + * aggregate digest as stored in the measurement list. + */ +static int tpm_mr_calc_boot_aggregate(struct ima_mr *mr, int bank, + char *digest, struct crypto_shash *tfm) +{ + int rc; + struct tpm_chip *tpm_chip; + mr_digest_t d = { .digest = {0} }; + u32 pcr_idx; + SHASH_DESC_ON_STACK(shash, tfm); + + if (!mr || !mr->data || !tfm || (bank >= mr->nr_banks)) + return -EINVAL; + + tpm_chip = mr->data; + d.alg_id = tpm_chip->allocated_banks[bank].alg_id; + + shash->tfm = tfm; + + pr_devel("calculating the boot-aggregate based on TPM bank: %04x\n", + d.alg_id); + + rc = crypto_shash_init(shash); + if (rc) + return rc; + + /* cumulative digest over TPM registers 0-7 */ + for (pcr_idx = TPM_PCR0; pcr_idx < TPM_PCR8; pcr_idx++) { + rc = tpm_pcr_read(tpm_chip, pcr_idx, &d); + rc = tpm_ret_to_err(rc); + if (rc) { + pr_err("Error Communicating to TPM chip\n"); + return rc; + } + + /* now accumulate with current aggregate */ + rc = crypto_shash_update(shash, d.digest, + crypto_shash_digestsize(tfm)); + if (rc) + return rc; + } + + /* + * Extend cumulative digest over TPM registers 8-9, which contain + * measurement for the kernel command line (reg. 8) and image (reg. 9) + * in a typical PCR allocation. Registers 8-9 are only included in + * non-SHA1 boot_aggregate digests to avoid ambiguity. + */ + if (d.alg_id != TPM_ALG_SHA1) { + for (pcr_idx = TPM_PCR8; pcr_idx < TPM_PCR10; pcr_idx++) { + rc = tpm_pcr_read(tpm_chip, pcr_idx, &d); + rc = tpm_ret_to_err(rc); + if (rc) { + pr_err("Error Communicating to TPM chip\n"); + return rc; + } + + rc = crypto_shash_update(shash, d.digest, + crypto_shash_digestsize(tfm)); + } + } + + if (!rc) + rc = crypto_shash_final(shash, digest); + return rc; +} + +static int tpm_mr_extend(struct ima_mr *mr, u32 pcr_idx, + mr_digest_t *digests) +{ + int rc; + struct tpm_chip *tpm_chip; + + if (!mr || !mr->data) + return -EINVAL; + + tpm_chip = mr->data; + + rc = tpm_pcr_extend(tpm_chip, pcr_idx, digests); + rc = tpm_ret_to_err(rc); + if (rc) + pr_err("Error Communicating to TPM chip, result: %d\n", rc); + + return rc; +} + +struct ima_mr_operations ima_mr_tpm_operations = { + .name = "TPM", + .supported = IS_BUILTIN(CONFIG_TCG_TPM), + .mr_init = tpm_mr_init, + .mr_get_bank_info = tpm_mr_get_bank_info, + .mr_calc_boot_aggregate = tpm_mr_calc_boot_aggregate, + .mr_extend = tpm_mr_extend, +};
diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
index 0f1b7e4113c4..637db7c338e2 100644
--- a/security/integrity/ima/ima_queue.c
+++ b/security/integrity/ima/ima_queue.c@@ -217,16 +217,15 @@ unsigned long ima_get_binary_runtime_size(enum binary_lists binary_list) return val + sizeof(struct ima_kexec_hdr); } -static int ima_pcr_extend(struct tpm_digest *digests_arg, int pcr) +static int ima_mr_extend(struct tpm_digest *digests_arg, int pcr) { int result = 0; - if (!ima_tpm_chip) + if (!ima_mr) return result; - result = tpm_pcr_extend(ima_tpm_chip, pcr, digests_arg); - if (result != 0) - pr_err("Error Communicating to TPM chip, result: %d\n", result); + result = ima_mr->ops->mr_extend(ima_mr, pcr, digests_arg); + return result; }
@@ -247,7 +246,7 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, const char *audit_cause = "hash_added"; char tpm_audit_cause[AUDIT_CAUSE_LEN_MAX]; int audit_info = 1; - int result = 0, tpmresult = 0; + int result = 0, mresult = 0; mutex_lock(&ima_extend_list_mutex);
@@ -281,10 +280,10 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, if (violation) /* invalidate pcr */ digests_arg = digests; - tpmresult = ima_pcr_extend(digests_arg, entry->pcr); - if (tpmresult != 0) { + mresult = ima_mr_extend(digests_arg, entry->pcr); + if (mresult != 0) { snprintf(tpm_audit_cause, AUDIT_CAUSE_LEN_MAX, "TPM_error(%d)", - tpmresult); + mresult); audit_cause = tpm_audit_cause; audit_info = 0; }
@@ -548,25 +547,27 @@ void __init ima_init_reboot_notifier(void) int __init ima_init_digests(void) { + int rc, i; + mr_bank_info_t bank_info; u16 digest_size; - u16 crypto_id; - int i; - if (!ima_tpm_chip) + if (!ima_mr) return 0; - digests = kzalloc_objs(*digests, ima_tpm_chip->nr_allocated_banks, - GFP_NOFS); + digests = kzalloc_objs(*digests, NR_BANKS(ima_mr), GFP_NOFS); if (!digests) return -ENOMEM; - for (i = 0; i < ima_tpm_chip->nr_allocated_banks; i++) { - digests[i].alg_id = ima_tpm_chip->allocated_banks[i].alg_id; - digest_size = ima_tpm_chip->allocated_banks[i].digest_size; - crypto_id = ima_tpm_chip->allocated_banks[i].crypto_id; + for (i = 0; i < NR_BANKS(ima_mr); i++) { + rc = ima_mr->ops->mr_get_bank_info(ima_mr, i, &bank_info); + if (rc) + return rc; + + digests[i].alg_id = bank_info.alg_id; + digest_size = bank_info.digest_size; /* for unmapped TPM algorithms digest is still a padded SHA1 */ - if (crypto_id == HASH_ALGO__LAST) + if (bank_info.crypto_id == HASH_ALGO__LAST) digest_size = SHA1_DIGEST_SIZE; memset(digests[i].digest, 0xff, digest_size);
diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c
index 7034573fb41e..3396e9df22a5 100644
--- a/security/integrity/ima/ima_template.c
+++ b/security/integrity/ima/ima_template.c@@ -358,7 +358,7 @@ static int ima_restore_template_data(struct ima_template_desc *template_desc, int template_data_size, struct ima_template_entry **entry) { - struct tpm_digest *digests; + mr_digest_t *digests; int ret = 0; int i;
@@ -368,7 +368,7 @@ static int ima_restore_template_data(struct ima_template_desc *template_desc, return -ENOMEM; digests = kzalloc_objs(*digests, - NR_BANKS(ima_tpm_chip) + ima_extra_slots, + NR_BANKS(ima_mr) + ima_extra_slots, GFP_NOFS); if (!digests) { kfree(*entry);
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
index 8a89236f926c..12386241b126 100644
--- a/security/integrity/ima/ima_template_lib.c
+++ b/security/integrity/ima/ima_template_lib.c@@ -365,7 +365,7 @@ int ima_eventdigest_init(struct ima_event_data *event_data, if ((const char *)event_data->filename == boot_aggregate_name || (const char *)event_data->filename == boot_aggregate_late_name) { - if (ima_tpm_chip) { + if (ima_mr) { hash.hdr.algo = HASH_ALGO_SHA1; result = ima_calc_boot_aggregate(hash_hdr);
--
2.43.0