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