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> |
Sergii Dmytruk | 26203e7 | 2022-11-10 17:56:26 +0200 | [diff] [blame] | 5 | #include <bootstate.h> |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 6 | #include <cbfs.h> |
Sergii Dmytruk | 26203e7 | 2022-11-10 17:56:26 +0200 | [diff] [blame] | 7 | #include <symbols.h> |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 8 | #include "crtm.h" |
| 9 | #include <string.h> |
| 10 | |
Sergii Dmytruk | 2710df7 | 2022-11-10 00:40:51 +0200 | [diff] [blame] | 11 | static int tpm_log_initialized; |
| 12 | static inline int tpm_log_available(void) |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 13 | { |
| 14 | if (ENV_BOOTBLOCK) |
Sergii Dmytruk | 2710df7 | 2022-11-10 00:40:51 +0200 | [diff] [blame] | 15 | return tpm_log_initialized; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 16 | |
| 17 | return 1; |
| 18 | } |
| 19 | |
Arthur Heymans | 17cb5be | 2021-06-14 09:17:49 +0200 | [diff] [blame] | 20 | /* |
| 21 | * Initializes the Core Root of Trust for Measurements |
| 22 | * in coreboot. The initial code in a chain of trust must measure |
| 23 | * itself. |
| 24 | * |
| 25 | * Summary: |
| 26 | * + Measures the FMAP FMAP partition. |
| 27 | * + Measures bootblock in CBFS or BOOTBLOCK FMAP partition. |
| 28 | * + If vboot starts in romstage, it measures the romstage |
| 29 | * in CBFS. |
| 30 | * + Measure the verstage if it is compiled as separate |
| 31 | * stage. |
| 32 | * |
| 33 | * Takes the current vboot context as parameter for s3 checks. |
| 34 | * returns on success VB2_SUCCESS, else a vboot error. |
| 35 | */ |
| 36 | static uint32_t tspi_init_crtm(void) |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 37 | { |
Sergii Dmytruk | 2710df7 | 2022-11-10 00:40:51 +0200 | [diff] [blame] | 38 | /* Initialize TPM PRERAM log. */ |
| 39 | if (!tpm_log_available()) { |
| 40 | tpm_preram_log_clear(); |
| 41 | tpm_log_initialized = 1; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 42 | } else { |
| 43 | printk(BIOS_WARNING, "TSPI: CRTM already initialized!\n"); |
| 44 | return VB2_SUCCESS; |
| 45 | } |
| 46 | |
Arthur Heymans | f28dcbc | 2021-04-29 09:31:01 +0200 | [diff] [blame] | 47 | struct region_device fmap; |
| 48 | if (fmap_locate_area_as_rdev("FMAP", &fmap) == 0) { |
Sergii Dmytruk | 4129c26 | 2022-10-24 01:17:41 +0300 | [diff] [blame] | 49 | if (tpm_measure_region(&fmap, CONFIG_PCR_SRTM, "FMAP: FMAP")) { |
Arthur Heymans | f28dcbc | 2021-04-29 09:31:01 +0200 | [diff] [blame] | 50 | printk(BIOS_ERR, |
| 51 | "TSPI: Couldn't measure FMAP into CRTM!\n"); |
| 52 | return VB2_ERROR_UNKNOWN; |
| 53 | } |
| 54 | } else { |
| 55 | printk(BIOS_ERR, "TSPI: Could not find FMAP!\n"); |
| 56 | } |
| 57 | |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 58 | /* measure bootblock from RO */ |
Werner Zeh | 823b7b3 | 2022-05-19 14:14:13 +0200 | [diff] [blame] | 59 | if (!CONFIG(ARCH_X86)) { |
| 60 | struct region_device bootblock_fmap; |
| 61 | if (fmap_locate_area_as_rdev("BOOTBLOCK", &bootblock_fmap) == 0) { |
| 62 | if (tpm_measure_region(&bootblock_fmap, |
Sergii Dmytruk | 4129c26 | 2022-10-24 01:17:41 +0300 | [diff] [blame] | 63 | CONFIG_PCR_SRTM, |
Werner Zeh | 823b7b3 | 2022-05-19 14:14:13 +0200 | [diff] [blame] | 64 | "FMAP: BOOTBLOCK")) |
| 65 | return VB2_ERROR_UNKNOWN; |
| 66 | } |
Arthur Heymans | 9642e97 | 2022-05-17 09:57:01 +0200 | [diff] [blame] | 67 | } else if (CONFIG(BOOTBLOCK_IN_CBFS)){ |
Julius Werner | 7e7cc1a | 2021-08-11 18:19:23 -0700 | [diff] [blame] | 68 | /* Mapping measures the file. We know we can safely map here because |
| 69 | bootblock-as-a-file is only used on x86, where we don't need cache to map. */ |
| 70 | enum cbfs_type type = CBFS_TYPE_BOOTBLOCK; |
| 71 | void *mapping = cbfs_ro_type_map("bootblock", NULL, &type); |
| 72 | if (!mapping) { |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 73 | printk(BIOS_INFO, |
| 74 | "TSPI: Couldn't measure bootblock into CRTM!\n"); |
| 75 | return VB2_ERROR_UNKNOWN; |
| 76 | } |
Julius Werner | 7e7cc1a | 2021-08-11 18:19:23 -0700 | [diff] [blame] | 77 | cbfs_unmap(mapping); |
Werner Zeh | 5c808e0 | 2022-05-19 09:16:28 +0200 | [diff] [blame] | 78 | } else { |
| 79 | /* Since none of the above conditions are met let the SOC code measure the |
| 80 | * bootblock. This accomplishes for cases where the bootblock is treated |
| 81 | * in a special way (e.g. part of IFWI or located in a different CBFS). */ |
Sergii Dmytruk | 4129c26 | 2022-10-24 01:17:41 +0300 | [diff] [blame] | 82 | if (tspi_soc_measure_bootblock(CONFIG_PCR_SRTM)) { |
Werner Zeh | 5c808e0 | 2022-05-19 09:16:28 +0200 | [diff] [blame] | 83 | printk(BIOS_INFO, |
| 84 | "TSPI: Couldn't measure bootblock into CRTM on SoC level!\n"); |
| 85 | return VB2_ERROR_UNKNOWN; |
| 86 | } |
| 87 | } |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 88 | |
| 89 | return VB2_SUCCESS; |
| 90 | } |
| 91 | |
| 92 | static bool is_runtime_data(const char *name) |
| 93 | { |
Duncan Laurie | ab673ce | 2020-06-12 10:41:32 -0700 | [diff] [blame] | 94 | const char *allowlist = CONFIG_TPM_MEASURED_BOOT_RUNTIME_DATA; |
| 95 | size_t allowlist_len = sizeof(CONFIG_TPM_MEASURED_BOOT_RUNTIME_DATA) - 1; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 96 | size_t name_len = strlen(name); |
harshit | aae1633 | 2020-05-12 12:55:39 +0530 | [diff] [blame] | 97 | const char *end; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 98 | |
Duncan Laurie | ab673ce | 2020-06-12 10:41:32 -0700 | [diff] [blame] | 99 | if (!allowlist_len || !name_len) |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 100 | return false; |
| 101 | |
Duncan Laurie | ab673ce | 2020-06-12 10:41:32 -0700 | [diff] [blame] | 102 | while ((end = strchr(allowlist, ' '))) { |
| 103 | if (end - allowlist == name_len && !strncmp(allowlist, name, name_len)) |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 104 | return true; |
Duncan Laurie | ab673ce | 2020-06-12 10:41:32 -0700 | [diff] [blame] | 105 | allowlist = end + 1; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 106 | } |
| 107 | |
Duncan Laurie | ab673ce | 2020-06-12 10:41:32 -0700 | [diff] [blame] | 108 | return !strcmp(allowlist, name); |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 109 | } |
| 110 | |
Julius Werner | 7e7cc1a | 2021-08-11 18:19:23 -0700 | [diff] [blame] | 111 | 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] | 112 | { |
| 113 | uint32_t pcr_index; |
Sergii Dmytruk | 2710df7 | 2022-11-10 00:40:51 +0200 | [diff] [blame] | 114 | char tpm_log_metadata[TPM_CB_LOG_PCR_HASH_NAME]; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 115 | |
Sergii Dmytruk | 2710df7 | 2022-11-10 00:40:51 +0200 | [diff] [blame] | 116 | if (!tpm_log_available()) { |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 117 | if (tspi_init_crtm() != VB2_SUCCESS) { |
| 118 | printk(BIOS_WARNING, |
Frans Hendriks | 4622a2f | 2020-10-22 15:12:32 +0200 | [diff] [blame] | 119 | "Initializing CRTM failed!\n"); |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 120 | return 0; |
| 121 | } |
Frans Hendriks | 4622a2f | 2020-10-22 15:12:32 +0200 | [diff] [blame] | 122 | printk(BIOS_DEBUG, "CRTM initialized.\n"); |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 123 | } |
| 124 | |
Julius Werner | 7e7cc1a | 2021-08-11 18:19:23 -0700 | [diff] [blame] | 125 | switch (type) { |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 126 | case CBFS_TYPE_MRC_CACHE: |
Sergii Dmytruk | 4129c26 | 2022-10-24 01:17:41 +0300 | [diff] [blame] | 127 | pcr_index = CONFIG_PCR_RUNTIME_DATA; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 128 | break; |
Bill XIE | bad08c2 | 2020-02-13 11:11:35 +0800 | [diff] [blame] | 129 | /* |
| 130 | * mrc.bin is code executed on CPU, so it |
| 131 | * should not be considered runtime data |
| 132 | */ |
| 133 | case CBFS_TYPE_MRC: |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 134 | case CBFS_TYPE_STAGE: |
| 135 | case CBFS_TYPE_SELF: |
Julius Werner | 0057262 | 2022-05-26 20:29:42 -0700 | [diff] [blame] | 136 | case CBFS_TYPE_FIT_PAYLOAD: |
Sergii Dmytruk | 4129c26 | 2022-10-24 01:17:41 +0300 | [diff] [blame] | 137 | pcr_index = CONFIG_PCR_SRTM; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 138 | break; |
| 139 | default: |
| 140 | if (is_runtime_data(name)) |
Sergii Dmytruk | 4129c26 | 2022-10-24 01:17:41 +0300 | [diff] [blame] | 141 | pcr_index = CONFIG_PCR_RUNTIME_DATA; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 142 | else |
Sergii Dmytruk | 4129c26 | 2022-10-24 01:17:41 +0300 | [diff] [blame] | 143 | pcr_index = CONFIG_PCR_SRTM; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 144 | break; |
| 145 | } |
| 146 | |
Sergii Dmytruk | 2710df7 | 2022-11-10 00:40:51 +0200 | [diff] [blame] | 147 | snprintf(tpm_log_metadata, TPM_CB_LOG_PCR_HASH_NAME, "CBFS: %s", name); |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 148 | |
Julius Werner | 7e7cc1a | 2021-08-11 18:19:23 -0700 | [diff] [blame] | 149 | return tpm_extend_pcr(pcr_index, hash->algo, hash->raw, vb2_digest_size(hash->algo), |
Sergii Dmytruk | 2710df7 | 2022-11-10 00:40:51 +0200 | [diff] [blame] | 150 | tpm_log_metadata); |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 151 | } |
| 152 | |
Sergii Dmytruk | 26203e7 | 2022-11-10 17:56:26 +0200 | [diff] [blame] | 153 | void *tpm_log_init(void) |
| 154 | { |
| 155 | static void *tclt; |
| 156 | |
| 157 | /* We are dealing here with pre CBMEM environment. |
| 158 | * If cbmem isn't available use CAR or SRAM */ |
| 159 | if (!cbmem_possibly_online() && |
| 160 | !CONFIG(VBOOT_RETURN_FROM_VERSTAGE)) |
| 161 | return _tpm_log; |
| 162 | else if (ENV_CREATES_CBMEM |
| 163 | && !CONFIG(VBOOT_RETURN_FROM_VERSTAGE)) { |
| 164 | tclt = tpm_log_cbmem_init(); |
| 165 | if (!tclt) |
| 166 | return _tpm_log; |
| 167 | } else { |
| 168 | tclt = tpm_log_cbmem_init(); |
| 169 | } |
| 170 | |
| 171 | return tclt; |
| 172 | } |
| 173 | |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 174 | int tspi_measure_cache_to_pcr(void) |
| 175 | { |
| 176 | int i; |
Sergii Dmytruk | 26203e7 | 2022-11-10 17:56:26 +0200 | [diff] [blame] | 177 | int pcr; |
| 178 | const char *event_name; |
| 179 | const uint8_t *digest_data; |
| 180 | enum vb2_hash_algorithm digest_algo; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 181 | |
Arthur Heymans | d873fa8 | 2021-06-14 09:18:45 +0200 | [diff] [blame] | 182 | /* This means the table is empty. */ |
Sergii Dmytruk | 2710df7 | 2022-11-10 00:40:51 +0200 | [diff] [blame] | 183 | if (!tpm_log_available()) |
Arthur Heymans | d873fa8 | 2021-06-14 09:18:45 +0200 | [diff] [blame] | 184 | return VB2_SUCCESS; |
| 185 | |
Sergii Dmytruk | 26203e7 | 2022-11-10 17:56:26 +0200 | [diff] [blame] | 186 | if (tpm_log_init() == NULL) { |
Sergii Dmytruk | 2710df7 | 2022-11-10 00:40:51 +0200 | [diff] [blame] | 187 | printk(BIOS_WARNING, "TPM LOG: log non-existent!\n"); |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 188 | return VB2_ERROR_UNKNOWN; |
| 189 | } |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 190 | |
Sergii Dmytruk | 2710df7 | 2022-11-10 00:40:51 +0200 | [diff] [blame] | 191 | printk(BIOS_DEBUG, "TPM: Write digests cached in TPM log to PCR\n"); |
Sergii Dmytruk | 26203e7 | 2022-11-10 17:56:26 +0200 | [diff] [blame] | 192 | i = 0; |
| 193 | while (!tpm_log_get(i++, &pcr, &digest_data, &digest_algo, &event_name)) { |
| 194 | printk(BIOS_DEBUG, "TPM: Write digest for %s into PCR %d\n", event_name, pcr); |
| 195 | int result = tlcl_extend(pcr, digest_data, digest_algo); |
| 196 | if (result != TPM_SUCCESS) { |
| 197 | printk(BIOS_ERR, |
| 198 | "TPM: Writing digest of %s into PCR failed with error %d\n", |
| 199 | event_name, result); |
| 200 | return VB2_ERROR_UNKNOWN; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 201 | } |
| 202 | } |
| 203 | |
| 204 | return VB2_SUCCESS; |
| 205 | } |
Sergii Dmytruk | 26203e7 | 2022-11-10 17:56:26 +0200 | [diff] [blame] | 206 | |
| 207 | #if !CONFIG(VBOOT_RETURN_FROM_VERSTAGE) |
| 208 | static void recover_tpm_log(int is_recovery) |
| 209 | { |
| 210 | const void *preram_log = _tpm_log; |
| 211 | void *ram_log = tpm_log_cbmem_init(); |
| 212 | |
| 213 | if (tpm_log_get_size(preram_log) > MAX_PRERAM_TPM_LOG_ENTRIES) { |
| 214 | printk(BIOS_WARNING, "TPM LOG: pre-RAM log is too full, possible corruption\n"); |
| 215 | return; |
| 216 | } |
| 217 | |
| 218 | if (ram_log == NULL) { |
| 219 | printk(BIOS_WARNING, "TPM LOG: CBMEM not available, something went wrong\n"); |
| 220 | return; |
| 221 | } |
| 222 | |
| 223 | tpm_log_copy_entries(_tpm_log, ram_log); |
| 224 | } |
| 225 | CBMEM_CREATION_HOOK(recover_tpm_log); |
| 226 | #endif |
| 227 | |
| 228 | BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_BOOT, BS_ON_ENTRY, tpm_log_dump, NULL); |