]> git.proxmox.com Git - efi-boot-shim.git/blame - tpm.c
New upstream version 15.7
[efi-boot-shim.git] / tpm.c
CommitLineData
031e5cce 1// SPDX-License-Identifier: BSD-2-Clause-Patent
f892ac66 2#include "shim.h"
d3819813 3
ab881f03
MTL
4typedef struct {
5 CHAR16 *VariableName;
6 EFI_GUID *VendorGuid;
7 VOID *Data;
8 UINTN Size;
9} VARIABLE_RECORD;
10
11UINTN measuredcount = 0;
12VARIABLE_RECORD *measureddata = NULL;
8529e0f7 13static BOOLEAN tpm_defective = FALSE;
ab881f03 14
d3819813
MTL
15static BOOLEAN tpm_present(efi_tpm_protocol_t *tpm)
16{
f892ac66 17 EFI_STATUS efi_status;
d3819813
MTL
18 TCG_EFI_BOOT_SERVICE_CAPABILITY caps;
19 UINT32 flags;
20 EFI_PHYSICAL_ADDRESS eventlog, lastevent;
21
8529e0f7
SM
22 if (tpm_defective)
23 return FALSE;
24
d3819813 25 caps.Size = (UINT8)sizeof(caps);
f892ac66
MTL
26 efi_status = tpm->status_check(tpm, &caps, &flags,
27 &eventlog, &lastevent);
28 if (EFI_ERROR(efi_status) ||
29 caps.TPMDeactivatedFlag || !caps.TPMPresentFlag)
d3819813
MTL
30 return FALSE;
31
32 return TRUE;
33}
34
f4173af1
MTL
35static EFI_STATUS tpm2_get_caps(efi_tpm2_protocol_t *tpm,
36 EFI_TCG2_BOOT_SERVICE_CAPABILITY *caps,
37 BOOLEAN *old_caps)
d3819813 38{
f892ac66 39 EFI_STATUS efi_status;
d3819813 40
f4173af1 41 caps->Size = (UINT8)sizeof(*caps);
d3819813 42
f892ac66
MTL
43 efi_status = tpm->get_capability(tpm, caps);
44 if (EFI_ERROR(efi_status))
45 return efi_status;
d3819813 46
f4173af1
MTL
47 if (caps->StructureVersion.Major == 1 &&
48 caps->StructureVersion.Minor == 0)
49 *old_caps = TRUE;
f892ac66
MTL
50 else
51 *old_caps = FALSE;
f4173af1
MTL
52
53 return EFI_SUCCESS;
54}
55
56static BOOLEAN tpm2_present(EFI_TCG2_BOOT_SERVICE_CAPABILITY *caps,
57 BOOLEAN old_caps)
58{
59 TREE_BOOT_SERVICE_CAPABILITY *caps_1_0;
60
61 if (old_caps) {
62 caps_1_0 = (TREE_BOOT_SERVICE_CAPABILITY *)caps;
63 if (caps_1_0->TrEEPresentFlag)
d3819813
MTL
64 return TRUE;
65 }
66
f4173af1
MTL
67 if (caps->TPMPresentFlag)
68 return TRUE;
69
d3819813
MTL
70 return FALSE;
71}
72
ab881f03
MTL
73static EFI_STATUS tpm_locate_protocol(efi_tpm_protocol_t **tpm,
74 efi_tpm2_protocol_t **tpm2,
75 BOOLEAN *old_caps_p,
76 EFI_TCG2_BOOT_SERVICE_CAPABILITY *capsp)
d3819813 77{
f892ac66 78 EFI_STATUS efi_status;
d3819813 79
ab881f03
MTL
80 *tpm = NULL;
81 *tpm2 = NULL;
f892ac66 82 efi_status = LibLocateProtocol(&EFI_TPM2_GUID, (VOID **)tpm2);
d3819813 83 /* TPM 2.0 */
f892ac66 84 if (!EFI_ERROR(efi_status)) {
f4173af1 85 BOOLEAN old_caps;
f4173af1 86 EFI_TCG2_BOOT_SERVICE_CAPABILITY caps;
d3819813 87
f892ac66
MTL
88 efi_status = tpm2_get_caps(*tpm2, &caps, &old_caps);
89 if (EFI_ERROR(efi_status))
90 return efi_status;
ab881f03
MTL
91
92 if (tpm2_present(&caps, old_caps)) {
93 if (old_caps_p)
94 *old_caps_p = old_caps;
95 if (capsp)
96 memcpy(capsp, &caps, sizeof(caps));
f4173af1 97 return EFI_SUCCESS;
ab881f03
MTL
98 }
99 } else {
f892ac66
MTL
100 efi_status = LibLocateProtocol(&EFI_TPM_GUID, (VOID **)tpm);
101 if (EFI_ERROR(efi_status))
102 return efi_status;
f4173af1 103
ab881f03 104 if (tpm_present(*tpm))
d3819813 105 return EFI_SUCCESS;
ab881f03
MTL
106 }
107
108 return EFI_NOT_FOUND;
109}
110
2dd2f760
SM
111static EFI_STATUS cc_log_event_raw(EFI_PHYSICAL_ADDRESS buf, UINTN size,
112 UINT8 pcr, const CHAR8 *log, UINTN logsize,
113 UINT32 type, BOOLEAN is_pe_image)
114{
115 EFI_STATUS efi_status;
116 EFI_CC_EVENT *event;
117 efi_cc_protocol_t *cc;
118 EFI_CC_MR_INDEX mr;
119 uint64_t flags = is_pe_image ? EFI_CC_FLAG_PE_COFF_IMAGE : 0;
120
121 efi_status = LibLocateProtocol(&EFI_CC_MEASUREMENT_PROTOCOL_GUID,
122 (VOID **)&cc);
123 if (EFI_ERROR(efi_status) || !cc)
124 return EFI_SUCCESS;
125
126 efi_status = cc->map_pcr_to_mr_index(cc, pcr, &mr);
127 if (EFI_ERROR(efi_status))
128 return EFI_NOT_FOUND;
129
130 UINTN event_size = sizeof(*event) - sizeof(event->Event) + logsize;
131
132 event = AllocatePool(event_size);
133 if (!event) {
134 perror(L"Unable to allocate event structure\n");
135 return EFI_OUT_OF_RESOURCES;
136 }
137
138 event->Header.HeaderSize = sizeof(EFI_CC_EVENT_HEADER);
139 event->Header.HeaderVersion = EFI_CC_EVENT_HEADER_VERSION;
140 event->Header.MrIndex = mr;
141 event->Header.EventType = type;
142 event->Size = event_size;
143 CopyMem(event->Event, (VOID *)log, logsize);
144 efi_status = cc->hash_log_extend_event(cc, flags, buf, (UINT64)size,
145 event);
146 FreePool(event);
147 return efi_status;
148}
149
ab881f03
MTL
150static EFI_STATUS tpm_log_event_raw(EFI_PHYSICAL_ADDRESS buf, UINTN size,
151 UINT8 pcr, const CHAR8 *log, UINTN logsize,
152 UINT32 type, CHAR8 *hash)
153{
f892ac66 154 EFI_STATUS efi_status;
ab881f03
MTL
155 efi_tpm_protocol_t *tpm;
156 efi_tpm2_protocol_t *tpm2;
157 BOOLEAN old_caps;
158 EFI_TCG2_BOOT_SERVICE_CAPABILITY caps;
159
2dd2f760
SM
160 /* CC guest like TDX or SEV will measure the buffer and log the event,
161 extend the result into a specific CC MR like TCG's PCR. It could
162 coexists with TCG's TPM 1.2 and TPM 2.
163 */
164 efi_status = cc_log_event_raw(buf, size, pcr, log, logsize, type,
165 (hash != NULL));
166 if (EFI_ERROR(efi_status))
167 return efi_status;
168
f892ac66
MTL
169 efi_status = tpm_locate_protocol(&tpm, &tpm2, &old_caps, &caps);
170 if (EFI_ERROR(efi_status)) {
171#ifdef REQUIRE_TPM
172 perror(L"TPM logging failed: %r\n", efi_status);
173 return efi_status;
174#else
175 if (efi_status != EFI_NOT_FOUND) {
176 perror(L"TPM logging failed: %r\n", efi_status);
177 return efi_status;
178 }
179#endif
ab881f03
MTL
180 } else if (tpm2) {
181 EFI_TCG2_EVENT *event;
031e5cce
SM
182 UINTN event_size = sizeof(*event) - sizeof(event->Event) +
183 logsize;
f4173af1 184
031e5cce 185 event = AllocatePool(event_size);
d3819813
MTL
186 if (!event) {
187 perror(L"Unable to allocate event structure\n");
188 return EFI_OUT_OF_RESOURCES;
189 }
190
191 event->Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER);
192 event->Header.HeaderVersion = 1;
193 event->Header.PCRIndex = pcr;
ab881f03 194 event->Header.EventType = type;
031e5cce 195 event->Size = event_size;
ab881f03
MTL
196 CopyMem(event->Event, (VOID *)log, logsize);
197 if (hash) {
198 /* TPM 2 systems will generate the appropriate hash
f892ac66
MTL
199 themselves if we pass PE_COFF_IMAGE. In case that
200 fails we fall back to measuring without it.
ab881f03 201 */
f892ac66
MTL
202 efi_status = tpm2->hash_log_extend_event(tpm2,
203 PE_COFF_IMAGE, buf, (UINT64) size, event);
204 }
205
206 if (!hash || EFI_ERROR(efi_status)) {
207 efi_status = tpm2->hash_log_extend_event(tpm2,
208 0, buf, (UINT64) size, event);
ab881f03 209 }
d3819813 210 FreePool(event);
f892ac66 211 return efi_status;
ab881f03 212 } else if (tpm) {
d3819813 213 TCG_PCR_EVENT *event;
f4173af1 214 UINT32 eventnum = 0;
d3819813
MTL
215 EFI_PHYSICAL_ADDRESS lastevent;
216
f892ac66
MTL
217 efi_status = LibLocateProtocol(&EFI_TPM_GUID, (VOID **)&tpm);
218 if (EFI_ERROR(efi_status))
d3819813
MTL
219 return EFI_SUCCESS;
220
221 if (!tpm_present(tpm))
222 return EFI_SUCCESS;
223
ab881f03 224 event = AllocatePool(sizeof(*event) + logsize);
d3819813
MTL
225
226 if (!event) {
227 perror(L"Unable to allocate event structure\n");
228 return EFI_OUT_OF_RESOURCES;
229 }
230
231 event->PCRIndex = pcr;
ab881f03
MTL
232 event->EventType = type;
233 event->EventSize = logsize;
234 CopyMem(event->Event, (VOID *)log, logsize);
235 if (hash) {
236 /* TPM 1.2 devices require us to pass the Authenticode
237 hash rather than allowing the firmware to attempt
238 to calculate it */
239 CopyMem(event->digest, hash, sizeof(event->digest));
f892ac66
MTL
240 efi_status = tpm->log_extend_event(tpm, 0, 0,
241 TPM_ALG_SHA, event, &eventnum, &lastevent);
ab881f03 242 } else {
f892ac66
MTL
243 efi_status = tpm->log_extend_event(tpm, buf,
244 (UINT64)size, TPM_ALG_SHA, event, &eventnum,
245 &lastevent);
ab881f03 246 }
8529e0f7
SM
247 if (efi_status == EFI_UNSUPPORTED) {
248 perror(L"Could not write TPM event: %r. Considering "
249 "the TPM as defective.\n", efi_status);
250 tpm_defective = TRUE;
251 efi_status = EFI_SUCCESS;
252 }
d3819813 253 FreePool(event);
f892ac66 254 return efi_status;
d3819813
MTL
255 }
256
257 return EFI_SUCCESS;
258}
ab881f03
MTL
259
260EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
261 const CHAR8 *description)
262{
263 return tpm_log_event_raw(buf, size, pcr, description,
031e5cce 264 strlen(description) + 1, EV_IPL, NULL);
ab881f03
MTL
265}
266
031e5cce
SM
267EFI_STATUS tpm_log_pe(EFI_PHYSICAL_ADDRESS buf, UINTN size,
268 EFI_PHYSICAL_ADDRESS addr, EFI_DEVICE_PATH *path,
269 UINT8 *sha1hash, UINT8 pcr)
ab881f03 270{
031e5cce
SM
271 EFI_IMAGE_LOAD_EVENT *ImageLoad = NULL;
272 EFI_STATUS efi_status;
273 UINTN path_size = 0;
274
275 if (path)
276 path_size = DevicePathSize(path);
277
278 ImageLoad = AllocateZeroPool(sizeof(*ImageLoad) + path_size);
279 if (!ImageLoad) {
280 perror(L"Unable to allocate image load event structure\n");
281 return EFI_OUT_OF_RESOURCES;
282 }
283
284 ImageLoad->ImageLocationInMemory = buf;
285 ImageLoad->ImageLengthInMemory = size;
286 ImageLoad->ImageLinkTimeAddress = addr;
287
288 if (path_size > 0) {
289 CopyMem(ImageLoad->DevicePath, path, path_size);
290 ImageLoad->LengthOfDevicePath = path_size;
291 }
292
293 efi_status = tpm_log_event_raw(buf, size, pcr, (CHAR8 *)ImageLoad,
294 sizeof(*ImageLoad) + path_size,
295 EV_EFI_BOOT_SERVICES_APPLICATION,
296 (CHAR8 *)sha1hash);
297 FreePool(ImageLoad);
298
299 return efi_status;
ab881f03
MTL
300}
301
302typedef struct {
303 EFI_GUID VariableName;
304 UINT64 UnicodeNameLength;
305 UINT64 VariableDataLength;
306 CHAR16 UnicodeName[1];
307 INT8 VariableData[1];
031e5cce 308} __attribute__ ((packed)) EFI_VARIABLE_DATA_TREE;
ab881f03
MTL
309
310static BOOLEAN tpm_data_measured(CHAR16 *VarName, EFI_GUID VendorGuid, UINTN VarSize, VOID *VarData)
311{
312 UINTN i;
313
314 for (i=0; i<measuredcount; i++) {
315 if ((StrCmp (VarName, measureddata[i].VariableName) == 0) &&
031e5cce 316 (CompareGuid (&VendorGuid, measureddata[i].VendorGuid) == 0) &&
ab881f03
MTL
317 (VarSize == measureddata[i].Size) &&
318 (CompareMem (VarData, measureddata[i].Data, VarSize) == 0)) {
319 return TRUE;
320 }
321 }
322
323 return FALSE;
324}
325
326static EFI_STATUS tpm_record_data_measurement(CHAR16 *VarName, EFI_GUID VendorGuid, UINTN VarSize, VOID *VarData)
327{
328 if (measureddata == NULL) {
329 measureddata = AllocatePool(sizeof(*measureddata));
330 } else {
331 measureddata = ReallocatePool(measureddata, measuredcount * sizeof(*measureddata),
332 (measuredcount + 1) * sizeof(*measureddata));
333 }
334
335 if (measureddata == NULL)
336 return EFI_OUT_OF_RESOURCES;
337
338 measureddata[measuredcount].VariableName = AllocatePool(StrSize(VarName));
339 measureddata[measuredcount].VendorGuid = AllocatePool(sizeof(EFI_GUID));
340 measureddata[measuredcount].Data = AllocatePool(VarSize);
341
342 if (measureddata[measuredcount].VariableName == NULL ||
343 measureddata[measuredcount].VendorGuid == NULL ||
344 measureddata[measuredcount].Data == NULL) {
345 return EFI_OUT_OF_RESOURCES;
346 }
347
348 StrCpy(measureddata[measuredcount].VariableName, VarName);
349 CopyMem(measureddata[measuredcount].VendorGuid, &VendorGuid, sizeof(EFI_GUID));
350 CopyMem(measureddata[measuredcount].Data, VarData, VarSize);
351 measureddata[measuredcount].Size = VarSize;
352 measuredcount++;
353
354 return EFI_SUCCESS;
355}
356
357EFI_STATUS tpm_measure_variable(CHAR16 *VarName, EFI_GUID VendorGuid, UINTN VarSize, VOID *VarData)
358{
f892ac66 359 EFI_STATUS efi_status;
ab881f03
MTL
360 UINTN VarNameLength;
361 EFI_VARIABLE_DATA_TREE *VarLog;
362 UINT32 VarLogSize;
363
364 /* Don't measure something that we've already measured */
365 if (tpm_data_measured(VarName, VendorGuid, VarSize, VarData))
366 return EFI_SUCCESS;
367
368 VarNameLength = StrLen (VarName);
369 VarLogSize = (UINT32)(sizeof (*VarLog) +
370 VarNameLength * sizeof (*VarName) +
371 VarSize -
372 sizeof (VarLog->UnicodeName) -
373 sizeof (VarLog->VariableData));
374
375 VarLog = (EFI_VARIABLE_DATA_TREE *) AllocateZeroPool (VarLogSize);
376 if (VarLog == NULL) {
377 return EFI_OUT_OF_RESOURCES;
378 }
379
380 CopyMem (&VarLog->VariableName, &VendorGuid,
381 sizeof(VarLog->VariableName));
382 VarLog->UnicodeNameLength = VarNameLength;
383 VarLog->VariableDataLength = VarSize;
384 CopyMem (VarLog->UnicodeName, VarName,
385 VarNameLength * sizeof (*VarName));
386 CopyMem ((CHAR16 *)VarLog->UnicodeName + VarNameLength, VarData,
387 VarSize);
388
f892ac66
MTL
389 efi_status = tpm_log_event_raw((EFI_PHYSICAL_ADDRESS)(intptr_t)VarLog,
390 VarLogSize, 7, (CHAR8 *)VarLog, VarLogSize,
391 EV_EFI_VARIABLE_AUTHORITY, NULL);
ab881f03
MTL
392
393 FreePool(VarLog);
394
f892ac66
MTL
395 if (EFI_ERROR(efi_status))
396 return efi_status;
ab881f03
MTL
397
398 return tpm_record_data_measurement(VarName, VendorGuid, VarSize,
399 VarData);
400}
401
402EFI_STATUS
403fallback_should_prefer_reset(void)
404{
f892ac66 405 EFI_STATUS efi_status;
ab881f03
MTL
406 efi_tpm_protocol_t *tpm;
407 efi_tpm2_protocol_t *tpm2;
408
f892ac66
MTL
409 efi_status = tpm_locate_protocol(&tpm, &tpm2, NULL, NULL);
410 if (EFI_ERROR(efi_status))
ab881f03
MTL
411 return EFI_NOT_FOUND;
412 return EFI_SUCCESS;
413}
8529e0f7
SM
414
415#ifdef SHIM_UNIT_TEST
416static void DESTRUCTOR
417tpm_clean_up_measurements(void)
418{
419 for (UINTN i = 0; i < measuredcount; i++) {
420 VARIABLE_RECORD *vr = &measureddata[i];
421
422 if (vr->VariableName)
423 FreePool(vr->VariableName);
424 if (vr->VendorGuid)
425 FreePool(vr->VendorGuid);
426 if (vr->Data)
427 FreePool(vr->Data);
428 }
429 if (measureddata)
430 FreePool(measureddata);
431
432 measuredcount = 0;
433 measureddata = NULL;
434}
435#endif