1 // SPDX-License-Identifier: BSD-2-Clause-Patent
11 UINTN measuredcount
= 0;
12 VARIABLE_RECORD
*measureddata
= NULL
;
13 static BOOLEAN tpm_defective
= FALSE
;
15 static BOOLEAN
tpm_present(efi_tpm_protocol_t
*tpm
)
17 EFI_STATUS efi_status
;
18 TCG_EFI_BOOT_SERVICE_CAPABILITY caps
;
20 EFI_PHYSICAL_ADDRESS eventlog
, lastevent
;
25 caps
.Size
= (UINT8
)sizeof(caps
);
26 efi_status
= tpm
->status_check(tpm
, &caps
, &flags
,
27 &eventlog
, &lastevent
);
28 if (EFI_ERROR(efi_status
) ||
29 caps
.TPMDeactivatedFlag
|| !caps
.TPMPresentFlag
)
35 static EFI_STATUS
tpm2_get_caps(efi_tpm2_protocol_t
*tpm
,
36 EFI_TCG2_BOOT_SERVICE_CAPABILITY
*caps
,
39 EFI_STATUS efi_status
;
41 caps
->Size
= (UINT8
)sizeof(*caps
);
43 efi_status
= tpm
->get_capability(tpm
, caps
);
44 if (EFI_ERROR(efi_status
))
47 if (caps
->StructureVersion
.Major
== 1 &&
48 caps
->StructureVersion
.Minor
== 0)
56 static BOOLEAN
tpm2_present(EFI_TCG2_BOOT_SERVICE_CAPABILITY
*caps
,
59 TREE_BOOT_SERVICE_CAPABILITY
*caps_1_0
;
62 caps_1_0
= (TREE_BOOT_SERVICE_CAPABILITY
*)caps
;
63 if (caps_1_0
->TrEEPresentFlag
)
67 if (caps
->TPMPresentFlag
)
73 static EFI_STATUS
tpm_locate_protocol(efi_tpm_protocol_t
**tpm
,
74 efi_tpm2_protocol_t
**tpm2
,
76 EFI_TCG2_BOOT_SERVICE_CAPABILITY
*capsp
)
78 EFI_STATUS efi_status
;
82 efi_status
= LibLocateProtocol(&EFI_TPM2_GUID
, (VOID
**)tpm2
);
84 if (!EFI_ERROR(efi_status
)) {
86 EFI_TCG2_BOOT_SERVICE_CAPABILITY caps
;
88 efi_status
= tpm2_get_caps(*tpm2
, &caps
, &old_caps
);
89 if (EFI_ERROR(efi_status
))
92 if (tpm2_present(&caps
, old_caps
)) {
94 *old_caps_p
= old_caps
;
96 memcpy(capsp
, &caps
, sizeof(caps
));
100 efi_status
= LibLocateProtocol(&EFI_TPM_GUID
, (VOID
**)tpm
);
101 if (EFI_ERROR(efi_status
))
104 if (tpm_present(*tpm
))
108 return EFI_NOT_FOUND
;
111 static 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
)
115 EFI_STATUS efi_status
;
117 efi_cc_protocol_t
*cc
;
119 uint64_t flags
= is_pe_image
? EFI_CC_FLAG_PE_COFF_IMAGE
: 0;
121 efi_status
= LibLocateProtocol(&EFI_CC_MEASUREMENT_PROTOCOL_GUID
,
123 if (EFI_ERROR(efi_status
) || !cc
)
126 efi_status
= cc
->map_pcr_to_mr_index(cc
, pcr
, &mr
);
127 if (EFI_ERROR(efi_status
))
128 return EFI_NOT_FOUND
;
130 UINTN event_size
= sizeof(*event
) - sizeof(event
->Event
) + logsize
;
132 event
= AllocatePool(event_size
);
134 perror(L
"Unable to allocate event structure\n");
135 return EFI_OUT_OF_RESOURCES
;
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
,
150 static 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
)
154 EFI_STATUS efi_status
;
155 efi_tpm_protocol_t
*tpm
;
156 efi_tpm2_protocol_t
*tpm2
;
158 EFI_TCG2_BOOT_SERVICE_CAPABILITY caps
;
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.
164 efi_status
= cc_log_event_raw(buf
, size
, pcr
, log
, logsize
, type
,
166 if (EFI_ERROR(efi_status
))
169 efi_status
= tpm_locate_protocol(&tpm
, &tpm2
, &old_caps
, &caps
);
170 if (EFI_ERROR(efi_status
)) {
172 perror(L
"TPM logging failed: %r\n", efi_status
);
175 if (efi_status
!= EFI_NOT_FOUND
) {
176 perror(L
"TPM logging failed: %r\n", efi_status
);
181 EFI_TCG2_EVENT
*event
;
182 UINTN event_size
= sizeof(*event
) - sizeof(event
->Event
) +
185 event
= AllocatePool(event_size
);
187 perror(L
"Unable to allocate event structure\n");
188 return EFI_OUT_OF_RESOURCES
;
191 event
->Header
.HeaderSize
= sizeof(EFI_TCG2_EVENT_HEADER
);
192 event
->Header
.HeaderVersion
= 1;
193 event
->Header
.PCRIndex
= pcr
;
194 event
->Header
.EventType
= type
;
195 event
->Size
= event_size
;
196 CopyMem(event
->Event
, (VOID
*)log
, logsize
);
198 /* TPM 2 systems will generate the appropriate hash
199 themselves if we pass PE_COFF_IMAGE. In case that
200 fails we fall back to measuring without it.
202 efi_status
= tpm2
->hash_log_extend_event(tpm2
,
203 PE_COFF_IMAGE
, buf
, (UINT64
) size
, event
);
206 if (!hash
|| EFI_ERROR(efi_status
)) {
207 efi_status
= tpm2
->hash_log_extend_event(tpm2
,
208 0, buf
, (UINT64
) size
, event
);
213 TCG_PCR_EVENT
*event
;
215 EFI_PHYSICAL_ADDRESS lastevent
;
217 efi_status
= LibLocateProtocol(&EFI_TPM_GUID
, (VOID
**)&tpm
);
218 if (EFI_ERROR(efi_status
))
221 if (!tpm_present(tpm
))
224 event
= AllocatePool(sizeof(*event
) + logsize
);
227 perror(L
"Unable to allocate event structure\n");
228 return EFI_OUT_OF_RESOURCES
;
231 event
->PCRIndex
= pcr
;
232 event
->EventType
= type
;
233 event
->EventSize
= logsize
;
234 CopyMem(event
->Event
, (VOID
*)log
, logsize
);
236 /* TPM 1.2 devices require us to pass the Authenticode
237 hash rather than allowing the firmware to attempt
239 CopyMem(event
->digest
, hash
, sizeof(event
->digest
));
240 efi_status
= tpm
->log_extend_event(tpm
, 0, 0,
241 TPM_ALG_SHA
, event
, &eventnum
, &lastevent
);
243 efi_status
= tpm
->log_extend_event(tpm
, buf
,
244 (UINT64
)size
, TPM_ALG_SHA
, event
, &eventnum
,
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
;
260 EFI_STATUS
tpm_log_event(EFI_PHYSICAL_ADDRESS buf
, UINTN size
, UINT8 pcr
,
261 const CHAR8
*description
)
263 return tpm_log_event_raw(buf
, size
, pcr
, description
,
264 strlen(description
) + 1, EV_IPL
, NULL
);
267 EFI_STATUS
tpm_log_pe(EFI_PHYSICAL_ADDRESS buf
, UINTN size
,
268 EFI_PHYSICAL_ADDRESS addr
, EFI_DEVICE_PATH
*path
,
269 UINT8
*sha1hash
, UINT8 pcr
)
271 EFI_IMAGE_LOAD_EVENT
*ImageLoad
= NULL
;
272 EFI_STATUS efi_status
;
276 path_size
= DevicePathSize(path
);
278 ImageLoad
= AllocateZeroPool(sizeof(*ImageLoad
) + path_size
);
280 perror(L
"Unable to allocate image load event structure\n");
281 return EFI_OUT_OF_RESOURCES
;
284 ImageLoad
->ImageLocationInMemory
= buf
;
285 ImageLoad
->ImageLengthInMemory
= size
;
286 ImageLoad
->ImageLinkTimeAddress
= addr
;
289 CopyMem(ImageLoad
->DevicePath
, path
, path_size
);
290 ImageLoad
->LengthOfDevicePath
= path_size
;
293 efi_status
= tpm_log_event_raw(buf
, size
, pcr
, (CHAR8
*)ImageLoad
,
294 sizeof(*ImageLoad
) + path_size
,
295 EV_EFI_BOOT_SERVICES_APPLICATION
,
303 EFI_GUID VariableName
;
304 UINT64 UnicodeNameLength
;
305 UINT64 VariableDataLength
;
306 CHAR16 UnicodeName
[1];
307 INT8 VariableData
[1];
308 } __attribute__ ((packed
)) EFI_VARIABLE_DATA_TREE
;
310 static BOOLEAN
tpm_data_measured(CHAR16
*VarName
, EFI_GUID VendorGuid
, UINTN VarSize
, VOID
*VarData
)
314 for (i
=0; i
<measuredcount
; i
++) {
315 if ((StrCmp (VarName
, measureddata
[i
].VariableName
) == 0) &&
316 (CompareGuid (&VendorGuid
, measureddata
[i
].VendorGuid
) == 0) &&
317 (VarSize
== measureddata
[i
].Size
) &&
318 (CompareMem (VarData
, measureddata
[i
].Data
, VarSize
) == 0)) {
326 static EFI_STATUS
tpm_record_data_measurement(CHAR16
*VarName
, EFI_GUID VendorGuid
, UINTN VarSize
, VOID
*VarData
)
328 if (measureddata
== NULL
) {
329 measureddata
= AllocatePool(sizeof(*measureddata
));
331 measureddata
= ReallocatePool(measureddata
, measuredcount
* sizeof(*measureddata
),
332 (measuredcount
+ 1) * sizeof(*measureddata
));
335 if (measureddata
== NULL
)
336 return EFI_OUT_OF_RESOURCES
;
338 measureddata
[measuredcount
].VariableName
= AllocatePool(StrSize(VarName
));
339 measureddata
[measuredcount
].VendorGuid
= AllocatePool(sizeof(EFI_GUID
));
340 measureddata
[measuredcount
].Data
= AllocatePool(VarSize
);
342 if (measureddata
[measuredcount
].VariableName
== NULL
||
343 measureddata
[measuredcount
].VendorGuid
== NULL
||
344 measureddata
[measuredcount
].Data
== NULL
) {
345 return EFI_OUT_OF_RESOURCES
;
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
;
357 EFI_STATUS
tpm_measure_variable(CHAR16
*VarName
, EFI_GUID VendorGuid
, UINTN VarSize
, VOID
*VarData
)
359 EFI_STATUS efi_status
;
361 EFI_VARIABLE_DATA_TREE
*VarLog
;
364 /* Don't measure something that we've already measured */
365 if (tpm_data_measured(VarName
, VendorGuid
, VarSize
, VarData
))
368 VarNameLength
= StrLen (VarName
);
369 VarLogSize
= (UINT32
)(sizeof (*VarLog
) +
370 VarNameLength
* sizeof (*VarName
) +
372 sizeof (VarLog
->UnicodeName
) -
373 sizeof (VarLog
->VariableData
));
375 VarLog
= (EFI_VARIABLE_DATA_TREE
*) AllocateZeroPool (VarLogSize
);
376 if (VarLog
== NULL
) {
377 return EFI_OUT_OF_RESOURCES
;
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
,
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
);
395 if (EFI_ERROR(efi_status
))
398 return tpm_record_data_measurement(VarName
, VendorGuid
, VarSize
,
403 fallback_should_prefer_reset(void)
405 EFI_STATUS efi_status
;
406 efi_tpm_protocol_t
*tpm
;
407 efi_tpm2_protocol_t
*tpm2
;
409 efi_status
= tpm_locate_protocol(&tpm
, &tpm2
, NULL
, NULL
);
410 if (EFI_ERROR(efi_status
))
411 return EFI_NOT_FOUND
;
415 #ifdef SHIM_UNIT_TEST
416 static void DESTRUCTOR
417 tpm_clean_up_measurements(void)
419 for (UINTN i
= 0; i
< measuredcount
; i
++) {
420 VARIABLE_RECORD
*vr
= &measureddata
[i
];
422 if (vr
->VariableName
)
423 FreePool(vr
->VariableName
);
425 FreePool(vr
->VendorGuid
);
430 FreePool(measureddata
);