Angel Pons | 986d50e | 2020-04-02 23:48:53 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 2 | |
| 3 | #include <console/console.h> |
| 4 | #include <fmap.h> |
| 5 | #include <cbfs.h> |
| 6 | #include "crtm.h" |
| 7 | #include <string.h> |
| 8 | |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 9 | static int tcpa_log_initialized; |
| 10 | static inline int tcpa_log_available(void) |
| 11 | { |
| 12 | if (ENV_BOOTBLOCK) |
| 13 | return tcpa_log_initialized; |
| 14 | |
| 15 | return 1; |
| 16 | } |
| 17 | |
Arthur Heymans | 17cb5be | 2021-06-14 09:17:49 +0200 | [diff] [blame] | 18 | /* |
| 19 | * Initializes the Core Root of Trust for Measurements |
| 20 | * in coreboot. The initial code in a chain of trust must measure |
| 21 | * itself. |
| 22 | * |
| 23 | * Summary: |
| 24 | * + Measures the FMAP FMAP partition. |
| 25 | * + Measures bootblock in CBFS or BOOTBLOCK FMAP partition. |
| 26 | * + If vboot starts in romstage, it measures the romstage |
| 27 | * in CBFS. |
| 28 | * + Measure the verstage if it is compiled as separate |
| 29 | * stage. |
| 30 | * |
| 31 | * Takes the current vboot context as parameter for s3 checks. |
| 32 | * returns on success VB2_SUCCESS, else a vboot error. |
| 33 | */ |
| 34 | static uint32_t tspi_init_crtm(void) |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 35 | { |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 36 | /* Initialize TCPA PRERAM log. */ |
| 37 | if (!tcpa_log_available()) { |
| 38 | tcpa_preram_log_clear(); |
| 39 | tcpa_log_initialized = 1; |
| 40 | } else { |
| 41 | printk(BIOS_WARNING, "TSPI: CRTM already initialized!\n"); |
| 42 | return VB2_SUCCESS; |
| 43 | } |
| 44 | |
Arthur Heymans | f28dcbc | 2021-04-29 09:31:01 +0200 | [diff] [blame] | 45 | struct region_device fmap; |
| 46 | if (fmap_locate_area_as_rdev("FMAP", &fmap) == 0) { |
Arthur Heymans | b0ccac09 | 2021-05-06 09:33:25 +0200 | [diff] [blame] | 47 | if (tpm_measure_region(&fmap, TPM_CRTM_PCR, "FMAP: FMAP")) { |
Arthur Heymans | f28dcbc | 2021-04-29 09:31:01 +0200 | [diff] [blame] | 48 | printk(BIOS_ERR, |
| 49 | "TSPI: Couldn't measure FMAP into CRTM!\n"); |
| 50 | return VB2_ERROR_UNKNOWN; |
| 51 | } |
| 52 | } else { |
| 53 | printk(BIOS_ERR, "TSPI: Could not find FMAP!\n"); |
| 54 | } |
| 55 | |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 56 | /* measure bootblock from RO */ |
Werner Zeh | 823b7b3 | 2022-05-19 14:14:13 +0200 | [diff] [blame] | 57 | if (!CONFIG(ARCH_X86)) { |
| 58 | struct region_device bootblock_fmap; |
| 59 | if (fmap_locate_area_as_rdev("BOOTBLOCK", &bootblock_fmap) == 0) { |
| 60 | if (tpm_measure_region(&bootblock_fmap, |
| 61 | TPM_CRTM_PCR, |
| 62 | "FMAP: BOOTBLOCK")) |
| 63 | return VB2_ERROR_UNKNOWN; |
| 64 | } |
Arthur Heymans | 9642e97 | 2022-05-17 09:57:01 +0200 | [diff] [blame] | 65 | } else if (CONFIG(BOOTBLOCK_IN_CBFS)){ |
Julius Werner | 7e7cc1a | 2021-08-11 18:19:23 -0700 | [diff] [blame] | 66 | /* Mapping measures the file. We know we can safely map here because |
| 67 | bootblock-as-a-file is only used on x86, where we don't need cache to map. */ |
| 68 | enum cbfs_type type = CBFS_TYPE_BOOTBLOCK; |
| 69 | void *mapping = cbfs_ro_type_map("bootblock", NULL, &type); |
| 70 | if (!mapping) { |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 71 | printk(BIOS_INFO, |
| 72 | "TSPI: Couldn't measure bootblock into CRTM!\n"); |
| 73 | return VB2_ERROR_UNKNOWN; |
| 74 | } |
Julius Werner | 7e7cc1a | 2021-08-11 18:19:23 -0700 | [diff] [blame] | 75 | cbfs_unmap(mapping); |
Werner Zeh | 5c808e0 | 2022-05-19 09:16:28 +0200 | [diff] [blame] | 76 | } else { |
| 77 | /* Since none of the above conditions are met let the SOC code measure the |
| 78 | * bootblock. This accomplishes for cases where the bootblock is treated |
| 79 | * in a special way (e.g. part of IFWI or located in a different CBFS). */ |
| 80 | if (tspi_soc_measure_bootblock(TPM_CRTM_PCR)) { |
| 81 | printk(BIOS_INFO, |
| 82 | "TSPI: Couldn't measure bootblock into CRTM on SoC level!\n"); |
| 83 | return VB2_ERROR_UNKNOWN; |
| 84 | } |
| 85 | } |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 86 | |
| 87 | return VB2_SUCCESS; |
| 88 | } |
| 89 | |
| 90 | static bool is_runtime_data(const char *name) |
| 91 | { |
Duncan Laurie | ab673ce | 2020-06-12 10:41:32 -0700 | [diff] [blame] | 92 | const char *allowlist = CONFIG_TPM_MEASURED_BOOT_RUNTIME_DATA; |
| 93 | size_t allowlist_len = sizeof(CONFIG_TPM_MEASURED_BOOT_RUNTIME_DATA) - 1; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 94 | size_t name_len = strlen(name); |
harshit | aae1633 | 2020-05-12 12:55:39 +0530 | [diff] [blame] | 95 | const char *end; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 96 | |
Duncan Laurie | ab673ce | 2020-06-12 10:41:32 -0700 | [diff] [blame] | 97 | if (!allowlist_len || !name_len) |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 98 | return false; |
| 99 | |
Duncan Laurie | ab673ce | 2020-06-12 10:41:32 -0700 | [diff] [blame] | 100 | while ((end = strchr(allowlist, ' '))) { |
| 101 | if (end - allowlist == name_len && !strncmp(allowlist, name, name_len)) |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 102 | return true; |
Duncan Laurie | ab673ce | 2020-06-12 10:41:32 -0700 | [diff] [blame] | 103 | allowlist = end + 1; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 104 | } |
| 105 | |
Duncan Laurie | ab673ce | 2020-06-12 10:41:32 -0700 | [diff] [blame] | 106 | return !strcmp(allowlist, name); |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 107 | } |
| 108 | |
Julius Werner | 7e7cc1a | 2021-08-11 18:19:23 -0700 | [diff] [blame] | 109 | uint32_t tspi_cbfs_measurement(const char *name, uint32_t type, const struct vb2_hash *hash) |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 110 | { |
| 111 | uint32_t pcr_index; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 112 | char tcpa_metadata[TCPA_PCR_HASH_NAME]; |
| 113 | |
| 114 | if (!tcpa_log_available()) { |
| 115 | if (tspi_init_crtm() != VB2_SUCCESS) { |
| 116 | printk(BIOS_WARNING, |
Frans Hendriks | 4622a2f | 2020-10-22 15:12:32 +0200 | [diff] [blame] | 117 | "Initializing CRTM failed!\n"); |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 118 | return 0; |
| 119 | } |
Frans Hendriks | 4622a2f | 2020-10-22 15:12:32 +0200 | [diff] [blame] | 120 | printk(BIOS_DEBUG, "CRTM initialized.\n"); |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 121 | } |
| 122 | |
Julius Werner | 7e7cc1a | 2021-08-11 18:19:23 -0700 | [diff] [blame] | 123 | switch (type) { |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 124 | case CBFS_TYPE_MRC_CACHE: |
| 125 | pcr_index = TPM_RUNTIME_DATA_PCR; |
| 126 | break; |
Bill XIE | bad08c2 | 2020-02-13 11:11:35 +0800 | [diff] [blame] | 127 | /* |
| 128 | * mrc.bin is code executed on CPU, so it |
| 129 | * should not be considered runtime data |
| 130 | */ |
| 131 | case CBFS_TYPE_MRC: |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 132 | case CBFS_TYPE_STAGE: |
| 133 | case CBFS_TYPE_SELF: |
Julius Werner | 0057262 | 2022-05-26 20:29:42 -0700 | [diff] [blame^] | 134 | case CBFS_TYPE_FIT_PAYLOAD: |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 135 | pcr_index = TPM_CRTM_PCR; |
| 136 | break; |
| 137 | default: |
| 138 | if (is_runtime_data(name)) |
| 139 | pcr_index = TPM_RUNTIME_DATA_PCR; |
| 140 | else |
| 141 | pcr_index = TPM_CRTM_PCR; |
| 142 | break; |
| 143 | } |
| 144 | |
Julius Werner | 7e7cc1a | 2021-08-11 18:19:23 -0700 | [diff] [blame] | 145 | snprintf(tcpa_metadata, TCPA_PCR_HASH_NAME, "CBFS: %s", name); |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 146 | |
Julius Werner | 7e7cc1a | 2021-08-11 18:19:23 -0700 | [diff] [blame] | 147 | return tpm_extend_pcr(pcr_index, hash->algo, hash->raw, vb2_digest_size(hash->algo), |
| 148 | tcpa_metadata); |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 149 | } |
| 150 | |
| 151 | int tspi_measure_cache_to_pcr(void) |
| 152 | { |
| 153 | int i; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 154 | struct tcpa_table *tclt = tcpa_log_init(); |
| 155 | |
Arthur Heymans | d873fa8 | 2021-06-14 09:18:45 +0200 | [diff] [blame] | 156 | /* This means the table is empty. */ |
| 157 | if (!tcpa_log_available()) |
| 158 | return VB2_SUCCESS; |
| 159 | |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 160 | if (!tclt) { |
| 161 | printk(BIOS_WARNING, "TCPA: Log non-existent!\n"); |
| 162 | return VB2_ERROR_UNKNOWN; |
| 163 | } |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 164 | |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 165 | printk(BIOS_DEBUG, "TPM: Write digests cached in TCPA log to PCR\n"); |
| 166 | for (i = 0; i < tclt->num_entries; i++) { |
| 167 | struct tcpa_entry *tce = &tclt->entries[i]; |
| 168 | if (tce) { |
| 169 | printk(BIOS_DEBUG, "TPM: Write digest for" |
| 170 | " %s into PCR %d\n", |
| 171 | tce->name, tce->pcr); |
| 172 | int result = tlcl_extend(tce->pcr, |
| 173 | tce->digest, |
| 174 | NULL); |
| 175 | if (result != TPM_SUCCESS) { |
| 176 | printk(BIOS_ERR, "TPM: Writing digest" |
| 177 | " of %s into PCR failed with error" |
| 178 | " %d\n", |
| 179 | tce->name, result); |
| 180 | return VB2_ERROR_UNKNOWN; |
| 181 | } |
| 182 | } |
| 183 | } |
| 184 | |
| 185 | return VB2_SUCCESS; |
| 186 | } |