diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile index d823ac70ddc261b3065e3d1a8ccf893f0d9df06b..9f683951cb4cafc093d8fd0c743a50bfbd8c7db1 100644 --- a/security/integrity/ima/Makefile +++ b/security/integrity/ima/Makefile @@ -7,7 +7,7 @@ obj-$(CONFIG_IMA) += ima.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 @@ -15,9 +15,10 @@ ima-$(CONFIG_IMA_BLACKLIST_KEYRING) += ima_mok.o ima-$(CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS) += ima_asymmetric_keys.o ima-$(CONFIG_IMA_QUEUE_EARLY_BOOT_KEYS) += ima_queue_keys.o ima-$(CONFIG_IMA_DIGEST_LIST) += ima_digest_list.o +ima-$(CONFIG_TCG_TPM) += ima_tpm.o ifeq ($(CONFIG_EFI),y) ima-$(CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT) += ima_efi.o endif -ima-$(CONFIG_HISI_VIRTCCA_GUEST) += ima_cvm.o +ima-$(CONFIG_HISI_VIRTCCA_GUEST) += ima_virtcca.o diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index ceaae0e2c52a1e5e7759d19ab6498ae9a52ec48e..d33992a8824fed987698c3de2d5deb852264d5b2 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -23,6 +23,7 @@ #include #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 }; @@ -41,7 +42,7 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8, TPM_PCR10 = 10 }; #define IMA_TEMPLATE_IMA_NAME "ima" #define IMA_TEMPLATE_IMA_FMT "d|n" -#define NR_BANKS(chip) ((chip != NULL) ? chip->nr_allocated_banks : 0) +#define NR_BANKS(rot) ((rot != NULL) ? rot->nr_allocated_banks : 0) /* current content of the policy */ extern int ima_policy_flag; @@ -55,7 +56,7 @@ extern int ima_sha1_idx __ro_after_init; extern int ima_hash_algo_idx __ro_after_init; extern int ima_extra_slots __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[]; #ifdef CONFIG_IMA_DIGEST_LIST extern int ima_digest_list_pcr; diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index f8b329aeb5d6e29ae3470ffd027d2e11c2b1dbe3..16ef07622010c200fd7dc294dc80c33fbb6a213f 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -52,7 +52,7 @@ int ima_alloc_init_template(struct ima_event_data *event_data, if (!*entry) return -ENOMEM; - digests = kcalloc(NR_BANKS(ima_tpm_chip) + ima_extra_slots, + digests = kcalloc(NR_BANKS(ima_rot_inst) + ima_extra_slots, sizeof(*digests), GFP_NOFS); if (!digests) { kfree(*entry); diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 51ad29940f05ca4566c88a4980ab7530cb57644e..39f17d4ffc8f20cb071090153ce0d2bddf7ef776 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -21,6 +21,7 @@ #include #include "ima.h" +#include "ima_tpm.h" /* minimum file size for ahash use */ static unsigned long ima_ahash_minsize; @@ -99,7 +100,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_rot_inst) + ima_extra_slots; i++) if (ima_algo_array[i].tfm && ima_algo_array[i].algo == algo) return ima_algo_array[i].tfm; @@ -125,8 +126,8 @@ 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_rot_inst); i++) { + algo = ima_rot_inst->allocated_banks[i].crypto_id; if (algo == HASH_ALGO_SHA1) ima_sha1_idx = i; @@ -135,23 +136,23 @@ 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_rot_inst) + 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_rot_inst) + ima_extra_slots++; - ima_algo_array = kcalloc(NR_BANKS(ima_tpm_chip) + ima_extra_slots, + ima_algo_array = kcalloc(NR_BANKS(ima_rot_inst) + ima_extra_slots, sizeof(*ima_algo_array), GFP_KERNEL); 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; + for (i = 0; i < NR_BANKS(ima_rot_inst); i++) { + algo = ima_rot_inst->allocated_banks[i].crypto_id; ima_algo_array[i].algo = algo; /* unknown TPM algorithm */ @@ -175,7 +176,7 @@ int __init ima_init_crypto(void) } } - if (ima_sha1_idx >= NR_BANKS(ima_tpm_chip)) { + if (ima_sha1_idx >= NR_BANKS(ima_rot_inst)) { if (ima_hash_algo == HASH_ALGO_SHA1) { ima_algo_array[ima_sha1_idx].tfm = ima_shash_tfm; } else { @@ -190,7 +191,7 @@ int __init ima_init_crypto(void) ima_algo_array[ima_sha1_idx].algo = HASH_ALGO_SHA1; } - if (ima_hash_algo_idx >= NR_BANKS(ima_tpm_chip) && + if (ima_hash_algo_idx >= NR_BANKS(ima_rot_inst) && ima_hash_algo_idx != ima_sha1_idx) { ima_algo_array[ima_hash_algo_idx].tfm = ima_shash_tfm; ima_algo_array[ima_hash_algo_idx].algo = ima_hash_algo; @@ -198,7 +199,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_rot_inst) + ima_extra_slots; i++) { if (!ima_algo_array[i].tfm || ima_algo_array[i].tfm == ima_shash_tfm) continue; @@ -218,7 +219,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_rot_inst) + ima_extra_slots; i++) if (ima_algo_array[i].tfm == tfm) return; @@ -636,12 +637,12 @@ 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_rot_inst) + 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; + if (i < NR_BANKS(ima_rot_inst)) { + alg_id = ima_rot_inst->allocated_banks[i].alg_id; entry->digests[i].alg_id = alg_id; } @@ -777,15 +778,6 @@ int ima_calc_buffer_hash(const void *buf, loff_t len, return calc_buffer_shash(buf, len, hash); } -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 @@ -847,8 +839,8 @@ int ima_calc_boot_aggregate(struct ima_digest_data *hash) u16 crypto_id, alg_id; 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; + for (i = 0; i < NR_BANKS(ima_rot_inst); i++) { + crypto_id = ima_rot_inst->allocated_banks[i].crypto_id; if (crypto_id == hash->algo) { bank_idx = i; break; @@ -866,14 +858,14 @@ int ima_calc_boot_aggregate(struct ima_digest_data *hash) return 0; } - hash->algo = ima_tpm_chip->allocated_banks[bank_idx].crypto_id; + hash->algo = ima_rot_inst->allocated_banks[bank_idx].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; + alg_id = ima_rot_inst->allocated_banks[bank_idx].alg_id; rc = ima_calc_boot_aggregate_tfm(hash->digest, alg_id, tfm); ima_free_tfm(tfm); diff --git a/security/integrity/ima/ima_cvm.h b/security/integrity/ima/ima_cvm.h deleted file mode 100644 index 864243bd08440ec4eb967d81b8140845bf1c692c..0000000000000000000000000000000000000000 --- a/security/integrity/ima/ima_cvm.h +++ /dev/null @@ -1,36 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2024. Huawei Technologies Co., Ltd. All rights reserved. - */ -#ifndef __LINUX_IMA_CVM_H -#define __LINUX_IMA_CVM_H - -#include "ima.h" - -#ifdef CONFIG_HISI_VIRTCCA_GUEST -int __init ima_cvm_init(void); -bool ima_cvm_available(void); -int ima_cvm_extend(struct tpm_digest *digests_arg); -int ima_calc_cvm_boot_aggregate(struct ima_digest_data *hash); -#else -static inline int __init ima_cvm_init(void) -{ - return -ENODEV; -} - -static inline bool ima_cvm_available(void) -{ - return false; -} - -static inline int ima_cvm_extend(struct tpm_digest *digests_arg) -{ - return -ENODEV; -} - -static inline int ima_calc_cvm_boot_aggregate(struct ima_digest_data *hash) -{ - return -ENODEV; -} -#endif -#endif diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index aa750942e422e4068e0e339e595cff0f49d3343b..8909b358fcde9a37608a337c6e4e963535f2e3b4 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -19,11 +19,10 @@ #include #include "ima.h" -#include "ima_cvm.h" /* 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. @@ -58,16 +57,6 @@ static int __init ima_add_boot_aggregate(void) iint->ima_hash->algo = ima_hash_algo; iint->ima_hash->length = hash_digest_size[ima_hash_algo]; -#ifdef CONFIG_HISI_VIRTCCA_GUEST - if (ima_cvm_available()) { - result = ima_calc_cvm_boot_aggregate(&hash.hdr); - if (result < 0) { - audit_cause = "hashing_error"; - goto err_out; - } - } -#endif - /* * With TPM 2.0 hash agility, TPM chips could support multiple TPM * PCR banks, allowing firmware to configure and enable different @@ -80,8 +69,8 @@ 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) { - result = ima_calc_boot_aggregate(&hash.hdr); + if (ima_rot_inst) { + result = ima_rot_inst->calc_boot_aggregate(&hash.hdr); if (result < 0) { audit_cause = "hashing_error"; goto err_out; @@ -132,17 +121,9 @@ int __init ima_init(void) { int rc; -#ifdef CONFIG_HISI_VIRTCCA_GUEST - rc = ima_cvm_init(); - if (rc) { - pr_info("No CVM found, activating CVM-bypass!\n"); - ima_tpm_chip = tpm_default_chip(); - } -#else - ima_tpm_chip = tpm_default_chip(); -#endif - if (!ima_tpm_chip) - pr_info("No TPM chip found, activating TPM-bypass!\n"); + ima_rot_inst = ima_rot_init(); + if (!ima_rot_inst) + pr_info("No RoT found, activating RoT-bypass!\n"); rc = integrity_init_keyring(INTEGRITY_KEYRING_IMA); if (rc) diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index 06653c3f3417dee620aa0e4138cdb5e062a8a84b..296ad15fd5209aeef849a43eb59133646b85dfe9 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -18,7 +18,6 @@ #include #include #include "ima.h" -#include "ima_cvm.h" #define AUDIT_CAUSE_LEN_MAX 32 @@ -136,19 +135,6 @@ unsigned long ima_get_binary_runtime_size(void) return binary_runtime_size + sizeof(struct ima_kexec_hdr); } -static int ima_pcr_extend(struct tpm_digest *digests_arg, int pcr) -{ - int result = 0; - - if (!ima_tpm_chip) - 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); - return result; -} - /* * Add template entry to the measurement list and hash table, and * extend the pcr. @@ -164,9 +150,9 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, u8 *digest = entry->digests[ima_hash_algo_idx].digest; struct tpm_digest *digests_arg = entry->digests; const char *audit_cause = "hash_added"; - char tpm_audit_cause[AUDIT_CAUSE_LEN_MAX]; + char rot_audit_cause[AUDIT_CAUSE_LEN_MAX]; int audit_info = 1; - int result = 0, tpmresult = 0; + int result = 0, rotresult = 0; mutex_lock(&ima_extend_list_mutex); if (!violation && !IS_ENABLED(CONFIG_IMA_DISABLE_HTABLE)) { @@ -188,21 +174,12 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, if (violation) /* invalidate pcr */ digests_arg = digests; -#ifdef CONFIG_HISI_VIRTCCA_GUEST - tpmresult = ima_cvm_extend(digests_arg); - if (tpmresult != 0) { - snprintf(tpm_audit_cause, AUDIT_CAUSE_LEN_MAX, "TSI_error(%d)", - tpmresult); - audit_cause = tpm_audit_cause; - audit_info = 0; - } -#endif - - tpmresult = ima_pcr_extend(digests_arg, entry->pcr); - if (tpmresult != 0) { - snprintf(tpm_audit_cause, AUDIT_CAUSE_LEN_MAX, "TPM_error(%d)", - tpmresult); - audit_cause = tpm_audit_cause; + if (ima_rot_inst) + rotresult = ima_rot_inst->extend(digests_arg, &entry->pcr); + if (rotresult != 0) { + snprintf(rot_audit_cause, AUDIT_CAUSE_LEN_MAX, "%s_error(%d)", + ima_rot_inst->name, rotresult); + audit_cause = rot_audit_cause; audit_info = 0; } out: @@ -228,18 +205,18 @@ int __init ima_init_digests(void) u16 crypto_id; int i; - if (!ima_tpm_chip) + if (!ima_rot_inst) return 0; - digests = kcalloc(ima_tpm_chip->nr_allocated_banks, sizeof(*digests), + digests = kcalloc(ima_rot_inst->nr_allocated_banks, sizeof(*digests), 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 < ima_rot_inst->nr_allocated_banks; i++) { + digests[i].alg_id = ima_rot_inst->allocated_banks[i].alg_id; + digest_size = ima_rot_inst->allocated_banks[i].digest_size; + crypto_id = ima_rot_inst->allocated_banks[i].crypto_id; /* for unmapped TPM algorithms digest is still a padded SHA1 */ if (crypto_id == HASH_ALGO__LAST) diff --git a/security/integrity/ima/ima_rot.c b/security/integrity/ima/ima_rot.c new file mode 100644 index 0000000000000000000000000000000000000000..45d2ea314790498e8ec082f95beb2a9a2c18b9fb --- /dev/null +++ b/security/integrity/ima/ima_rot.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2024 Huawei Technologies Co., Ltd. + * + * Authors: + * GONG Ruiqi + * + * File: ima_rot.c + * IMA rot layer + */ + +#include +#include +#include + +#include "ima.h" +#include "ima_tpm.h" +#include "ima_virtcca.h" + +static const char *name_rot_prefered; + +/* + * 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[] = { +#ifdef CONFIG_TCG_TPM + { + .name = "tpm", + .init = ima_tpm_init, + .extend = ima_tpm_extend, + .calc_boot_aggregate = ima_tpm_calc_boot_aggregate, + }, +#endif +#ifdef CONFIG_HISI_VIRTCCA_GUEST + { + .name = "virtcca", + .init = ima_virtcca_init, + .extend = ima_virtcca_extend, + .calc_boot_aggregate = ima_calc_virtcca_boot_aggregate, + }, +#endif +}; + +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)) { + name_rot_prefered = str; + break; + } + } + + if (!name_rot_prefered) + pr_info("%s is NOT implemented as an IMA RoT\n", str); + + 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 (name_rot_prefered && strcmp(name_rot_prefered, 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_info("%s failed to self-initialize\n", ima_rots[i].name); + } + + return NULL; +} diff --git a/security/integrity/ima/ima_rot.h b/security/integrity/ima/ima_rot.h new file mode 100644 index 0000000000000000000000000000000000000000..ba6bec380ed4b0bb583453381300c44265f9f5e4 --- /dev/null +++ b/security/integrity/ima/ima_rot.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2024 Huawei Technologies Co., Ltd. + * + * Authors: + * GONG Ruiqi + * + * File: ima_rot.h + * IMA rot layer + */ + +#ifndef __LINUX_IMA_ROT_H +#define __LINUX_IMA_ROT_H + +#include + +struct ima_rot { + const char *name; + 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 */ diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index 04c49f05cb74fc156622c44e2f2784fd6cee645d..a6ece3557267d2e4439d2e63b8410ab346c0da79 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c @@ -367,7 +367,7 @@ static int ima_restore_template_data(struct ima_template_desc *template_desc, if (!*entry) return -ENOMEM; - digests = kcalloc(NR_BANKS(ima_tpm_chip) + ima_extra_slots, + digests = kcalloc(NR_BANKS(ima_rot_inst) + ima_extra_slots, sizeof(*digests), 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 3b2cb8f1002e617192e28aea2c0bbd5b60f4169d..4bcc77c092b6d6dd865440a9c8b15a57996950ae 100644 --- a/security/integrity/ima/ima_template_lib.c +++ b/security/integrity/ima/ima_template_lib.c @@ -356,7 +356,7 @@ int ima_eventdigest_init(struct ima_event_data *event_data, } if ((const char *)event_data->filename == boot_aggregate_name) { - if (ima_tpm_chip) { + if (ima_rot_inst) { hash.hdr.algo = HASH_ALGO_SHA1; result = ima_calc_boot_aggregate(&hash.hdr); diff --git a/security/integrity/ima/ima_tpm.c b/security/integrity/ima/ima_tpm.c new file mode 100644 index 0000000000000000000000000000000000000000..5c3dea3e071990a5ebad250885c20ff04730f012 --- /dev/null +++ b/security/integrity/ima/ima_tpm.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2024 Huawei Technologies Co., Ltd. + * + * Authors: + * GONG Ruiqi + * + * File: ima_rot_tpm.c + * TPM implementation of IMA RoT + */ + +#include +#include + +#include "ima.h" + +static struct tpm_chip *ima_tpm_chip; + +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"); +} + +static int ima_pcr_extend(struct tpm_digest *digests_arg, int pcr) +{ + int result = 0; + + if (!ima_tpm_chip) + 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); + return result; +} + +int ima_tpm_init(struct ima_rot *rot) +{ + ima_tpm_chip = tpm_default_chip(); + if (!ima_tpm_chip) + return -ENODEV; + + rot->nr_allocated_banks = ima_tpm_chip->nr_allocated_banks; + rot->allocated_banks = ima_tpm_chip->allocated_banks; + + return 0; +} + +int ima_tpm_extend(struct tpm_digest *digests_arg, const void *args) +{ + const int pcr = *(const int *)args; + + return ima_pcr_extend(digests_arg, pcr); +} + +int ima_tpm_calc_boot_aggregate(struct ima_digest_data *hash) +{ + return ima_calc_boot_aggregate(hash); +} diff --git a/security/integrity/ima/ima_tpm.h b/security/integrity/ima/ima_tpm.h new file mode 100644 index 0000000000000000000000000000000000000000..b93018ab5438ea6f4768eb43cb1c20105a1499fb --- /dev/null +++ b/security/integrity/ima/ima_tpm.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2024 Huawei Technologies Co., Ltd. + * + * Authors: + * GONG Ruiqi + * + * File: ima_tpm.h + * Hooks of TPM for IMA RoT + */ + +#ifndef __LINUX_IMA_IMA_TPM_H +#define __LINUX_IMA_IMA_TPM_H + +int ima_tpm_init(struct ima_rot *rot); +int ima_tpm_extend(struct tpm_digest *digests_arg, const void *args); +int ima_tpm_calc_boot_aggregate(struct ima_digest_data *hash); + +void ima_pcrread(u32 idx, struct tpm_digest *d); + +#endif /* __LINUX_IMA_IMA_TPM_H */ diff --git a/security/integrity/ima/ima_cvm.c b/security/integrity/ima/ima_virtcca.c similarity index 36% rename from security/integrity/ima/ima_cvm.c rename to security/integrity/ima/ima_virtcca.c index 0fe3c0da63b284a335d6ddadf82159bf3ba5ac98..15f7338564b324a18733223900b6a766982fe0c7 100644 --- a/security/integrity/ima/ima_cvm.c +++ b/security/integrity/ima/ima_virtcca.c @@ -4,43 +4,65 @@ */ #include #include -#include "ima_cvm.h" +#include "ima.h" -static bool ima_tsi_cvm; +#define CVM_IMA_SLOT_IDX 1 -bool ima_cvm_available(void) +static enum hash_algo virtcca_algo; + +static int ima_virtcca_init_algo(void) { - return ima_tsi_cvm; + unsigned long result; + struct virtcca_cvm_config cfg = { 0 }; + + result = tsi_get_cvm_config(&cfg); + if (result != TSI_SUCCESS) { + pr_info("Error reading cvm config\n"); + return -EFAULT; + } + + /* 0: SHA256, 1: SHA512 */ + virtcca_algo = cfg.algorithm ? HASH_ALGO_SHA512 : HASH_ALGO_SHA256; + + return 0; } -int __init ima_cvm_init(void) +int ima_virtcca_init(struct ima_rot *rot) { - int rc = -ENODEV; + int rc; + + if (!is_virtcca_cvm_world() || tsi_get_version() == SMCCC_RET_NOT_SUPPORTED) + return -ENODEV; - if (is_virtcca_cvm_world() && tsi_get_version() != SMCCC_RET_NOT_SUPPORTED) { - ima_tsi_cvm = true; - rc = 0; + rc = ima_virtcca_init_algo(); + if (rc) + return rc; + + if (virtcca_algo != ima_hash_algo) { + pr_info("VirtCCA's algo (%s) is different from ima_hash_algo (%s)\n", + hash_algo_name[virtcca_algo], hash_algo_name[ima_hash_algo]); + + rot->allocated_banks = kcalloc(1, sizeof(*rot->allocated_banks), GFP_KERNEL); + if (!rot->allocated_banks) + return -ENOMEM; + + rot->nr_allocated_banks = 1; + rot->allocated_banks[0].alg_id = (virtcca_algo == HASH_ALGO_SHA512) ? + TPM_ALG_SHA512 : TPM_ALG_SHA256; + rot->allocated_banks[0].digest_size = hash_digest_size[virtcca_algo]; + rot->allocated_banks[0].crypto_id = virtcca_algo; } - return rc; + return 0; } -int ima_calc_cvm_boot_aggregate(struct ima_digest_data *hash) +int ima_calc_virtcca_boot_aggregate(struct ima_digest_data *hash) { unsigned long result; - int hash_len; - struct virtcca_cvm_config cfg = { 0 }; struct virtcca_cvm_measurement cm = { 0 }; - result = tsi_get_cvm_config(&cfg); - if (result != TSI_SUCCESS) { - pr_err("Error reading cvm config for boot aggregate\n"); - return -EFAULT; - } - - /* 0: SHA256, 1: SHA512 */ - hash->algo = cfg.algorithm ? HASH_ALGO_SHA512 : HASH_ALGO_SHA256; - hash_len = hash_digest_size[hash->algo]; + hash->algo = virtcca_algo; + hash->length = hash_digest_size[virtcca_algo]; /* Read the measurement result of RIM as the boot aggregate */ cm.index = RIM_MEASUREMENT_SLOT; @@ -51,25 +73,21 @@ int ima_calc_cvm_boot_aggregate(struct ima_digest_data *hash) return -EFAULT; } - memcpy(hash->digest, cm.value, hash_len); + memcpy(hash->digest, cm.value, hash->length); return 0; } -int ima_cvm_extend(struct tpm_digest *digests_arg) +int ima_virtcca_extend(struct tpm_digest *digests_arg, const void *args) { struct virtcca_cvm_measurement_extend cme; + int algo_idx = (virtcca_algo != ima_hash_algo) ? 0 : ima_hash_algo_idx; - if (!ima_tsi_cvm) - return 0; - - /* Use index 1 as CVM IMA slot */ - cme.index = 1; - cme.size = hash_digest_size[ima_hash_algo]; + cme.index = CVM_IMA_SLOT_IDX; + cme.size = hash_digest_size[virtcca_algo]; if (digests_arg) - memcpy(cme.value, digests_arg[ima_hash_algo_idx].digest, - cme.size); + memcpy(cme.value, digests_arg[algo_idx].digest, cme.size); else memset(cme.value, 0xff, cme.size); diff --git a/security/integrity/ima/ima_virtcca.h b/security/integrity/ima/ima_virtcca.h new file mode 100644 index 0000000000000000000000000000000000000000..cffb9bdf301385620f4ca52ac18bd5bcbf8e66cc --- /dev/null +++ b/security/integrity/ima/ima_virtcca.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2024. Huawei Technologies Co., Ltd. All rights reserved. + */ +#ifndef __LINUX_IMA_VIRTCCA_H +#define __LINUX_IMA_VIRTCCA_H + +#include "ima.h" + +int ima_virtcca_init(struct ima_rot *rot); +int ima_calc_virtcca_boot_aggregate(struct ima_digest_data *hash); +int ima_virtcca_extend(struct tpm_digest *digests_arg, const void *args); +#endif