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
tpm_log_event_raw(EFI_PHYSICAL_ADDRESS buf
, UINTN size
,
112 UINT8 pcr
, const CHAR8
*log
, UINTN logsize
,
113 UINT32 type
, CHAR8
*hash
)
115 EFI_STATUS efi_status
;
116 efi_tpm_protocol_t
*tpm
;
117 efi_tpm2_protocol_t
*tpm2
;
119 EFI_TCG2_BOOT_SERVICE_CAPABILITY caps
;
121 efi_status
= tpm_locate_protocol(&tpm
, &tpm2
, &old_caps
, &caps
);
122 if (EFI_ERROR(efi_status
)) {
124 perror(L
"TPM logging failed: %r\n", efi_status
);
127 if (efi_status
!= EFI_NOT_FOUND
) {
128 perror(L
"TPM logging failed: %r\n", efi_status
);
133 EFI_TCG2_EVENT
*event
;
134 UINTN event_size
= sizeof(*event
) - sizeof(event
->Event
) +
137 event
= AllocatePool(event_size
);
139 perror(L
"Unable to allocate event structure\n");
140 return EFI_OUT_OF_RESOURCES
;
143 event
->Header
.HeaderSize
= sizeof(EFI_TCG2_EVENT_HEADER
);
144 event
->Header
.HeaderVersion
= 1;
145 event
->Header
.PCRIndex
= pcr
;
146 event
->Header
.EventType
= type
;
147 event
->Size
= event_size
;
148 CopyMem(event
->Event
, (VOID
*)log
, logsize
);
150 /* TPM 2 systems will generate the appropriate hash
151 themselves if we pass PE_COFF_IMAGE. In case that
152 fails we fall back to measuring without it.
154 efi_status
= tpm2
->hash_log_extend_event(tpm2
,
155 PE_COFF_IMAGE
, buf
, (UINT64
) size
, event
);
158 if (!hash
|| EFI_ERROR(efi_status
)) {
159 efi_status
= tpm2
->hash_log_extend_event(tpm2
,
160 0, buf
, (UINT64
) size
, event
);
165 TCG_PCR_EVENT
*event
;
167 EFI_PHYSICAL_ADDRESS lastevent
;
169 efi_status
= LibLocateProtocol(&EFI_TPM_GUID
, (VOID
**)&tpm
);
170 if (EFI_ERROR(efi_status
))
173 if (!tpm_present(tpm
))
176 event
= AllocatePool(sizeof(*event
) + logsize
);
179 perror(L
"Unable to allocate event structure\n");
180 return EFI_OUT_OF_RESOURCES
;
183 event
->PCRIndex
= pcr
;
184 event
->EventType
= type
;
185 event
->EventSize
= logsize
;
186 CopyMem(event
->Event
, (VOID
*)log
, logsize
);
188 /* TPM 1.2 devices require us to pass the Authenticode
189 hash rather than allowing the firmware to attempt
191 CopyMem(event
->digest
, hash
, sizeof(event
->digest
));
192 efi_status
= tpm
->log_extend_event(tpm
, 0, 0,
193 TPM_ALG_SHA
, event
, &eventnum
, &lastevent
);
195 efi_status
= tpm
->log_extend_event(tpm
, buf
,
196 (UINT64
)size
, TPM_ALG_SHA
, event
, &eventnum
,
199 if (efi_status
== EFI_UNSUPPORTED
) {
200 perror(L
"Could not write TPM event: %r. Considering "
201 "the TPM as defective.\n", efi_status
);
202 tpm_defective
= TRUE
;
203 efi_status
= EFI_SUCCESS
;
212 EFI_STATUS
tpm_log_event(EFI_PHYSICAL_ADDRESS buf
, UINTN size
, UINT8 pcr
,
213 const CHAR8
*description
)
215 return tpm_log_event_raw(buf
, size
, pcr
, description
,
216 strlen(description
) + 1, EV_IPL
, NULL
);
219 EFI_STATUS
tpm_log_pe(EFI_PHYSICAL_ADDRESS buf
, UINTN size
,
220 EFI_PHYSICAL_ADDRESS addr
, EFI_DEVICE_PATH
*path
,
221 UINT8
*sha1hash
, UINT8 pcr
)
223 EFI_IMAGE_LOAD_EVENT
*ImageLoad
= NULL
;
224 EFI_STATUS efi_status
;
228 path_size
= DevicePathSize(path
);
230 ImageLoad
= AllocateZeroPool(sizeof(*ImageLoad
) + path_size
);
232 perror(L
"Unable to allocate image load event structure\n");
233 return EFI_OUT_OF_RESOURCES
;
236 ImageLoad
->ImageLocationInMemory
= buf
;
237 ImageLoad
->ImageLengthInMemory
= size
;
238 ImageLoad
->ImageLinkTimeAddress
= addr
;
241 CopyMem(ImageLoad
->DevicePath
, path
, path_size
);
242 ImageLoad
->LengthOfDevicePath
= path_size
;
245 efi_status
= tpm_log_event_raw(buf
, size
, pcr
, (CHAR8
*)ImageLoad
,
246 sizeof(*ImageLoad
) + path_size
,
247 EV_EFI_BOOT_SERVICES_APPLICATION
,
255 EFI_GUID VariableName
;
256 UINT64 UnicodeNameLength
;
257 UINT64 VariableDataLength
;
258 CHAR16 UnicodeName
[1];
259 INT8 VariableData
[1];
260 } __attribute__ ((packed
)) EFI_VARIABLE_DATA_TREE
;
262 static BOOLEAN
tpm_data_measured(CHAR16
*VarName
, EFI_GUID VendorGuid
, UINTN VarSize
, VOID
*VarData
)
266 for (i
=0; i
<measuredcount
; i
++) {
267 if ((StrCmp (VarName
, measureddata
[i
].VariableName
) == 0) &&
268 (CompareGuid (&VendorGuid
, measureddata
[i
].VendorGuid
) == 0) &&
269 (VarSize
== measureddata
[i
].Size
) &&
270 (CompareMem (VarData
, measureddata
[i
].Data
, VarSize
) == 0)) {
278 static EFI_STATUS
tpm_record_data_measurement(CHAR16
*VarName
, EFI_GUID VendorGuid
, UINTN VarSize
, VOID
*VarData
)
280 if (measureddata
== NULL
) {
281 measureddata
= AllocatePool(sizeof(*measureddata
));
283 measureddata
= ReallocatePool(measureddata
, measuredcount
* sizeof(*measureddata
),
284 (measuredcount
+ 1) * sizeof(*measureddata
));
287 if (measureddata
== NULL
)
288 return EFI_OUT_OF_RESOURCES
;
290 measureddata
[measuredcount
].VariableName
= AllocatePool(StrSize(VarName
));
291 measureddata
[measuredcount
].VendorGuid
= AllocatePool(sizeof(EFI_GUID
));
292 measureddata
[measuredcount
].Data
= AllocatePool(VarSize
);
294 if (measureddata
[measuredcount
].VariableName
== NULL
||
295 measureddata
[measuredcount
].VendorGuid
== NULL
||
296 measureddata
[measuredcount
].Data
== NULL
) {
297 return EFI_OUT_OF_RESOURCES
;
300 StrCpy(measureddata
[measuredcount
].VariableName
, VarName
);
301 CopyMem(measureddata
[measuredcount
].VendorGuid
, &VendorGuid
, sizeof(EFI_GUID
));
302 CopyMem(measureddata
[measuredcount
].Data
, VarData
, VarSize
);
303 measureddata
[measuredcount
].Size
= VarSize
;
309 EFI_STATUS
tpm_measure_variable(CHAR16
*VarName
, EFI_GUID VendorGuid
, UINTN VarSize
, VOID
*VarData
)
311 EFI_STATUS efi_status
;
313 EFI_VARIABLE_DATA_TREE
*VarLog
;
316 /* Don't measure something that we've already measured */
317 if (tpm_data_measured(VarName
, VendorGuid
, VarSize
, VarData
))
320 VarNameLength
= StrLen (VarName
);
321 VarLogSize
= (UINT32
)(sizeof (*VarLog
) +
322 VarNameLength
* sizeof (*VarName
) +
324 sizeof (VarLog
->UnicodeName
) -
325 sizeof (VarLog
->VariableData
));
327 VarLog
= (EFI_VARIABLE_DATA_TREE
*) AllocateZeroPool (VarLogSize
);
328 if (VarLog
== NULL
) {
329 return EFI_OUT_OF_RESOURCES
;
332 CopyMem (&VarLog
->VariableName
, &VendorGuid
,
333 sizeof(VarLog
->VariableName
));
334 VarLog
->UnicodeNameLength
= VarNameLength
;
335 VarLog
->VariableDataLength
= VarSize
;
336 CopyMem (VarLog
->UnicodeName
, VarName
,
337 VarNameLength
* sizeof (*VarName
));
338 CopyMem ((CHAR16
*)VarLog
->UnicodeName
+ VarNameLength
, VarData
,
341 efi_status
= tpm_log_event_raw((EFI_PHYSICAL_ADDRESS
)(intptr_t)VarLog
,
342 VarLogSize
, 7, (CHAR8
*)VarLog
, VarLogSize
,
343 EV_EFI_VARIABLE_AUTHORITY
, NULL
);
347 if (EFI_ERROR(efi_status
))
350 return tpm_record_data_measurement(VarName
, VendorGuid
, VarSize
,
355 fallback_should_prefer_reset(void)
357 EFI_STATUS efi_status
;
358 efi_tpm_protocol_t
*tpm
;
359 efi_tpm2_protocol_t
*tpm2
;
361 efi_status
= tpm_locate_protocol(&tpm
, &tpm2
, NULL
, NULL
);
362 if (EFI_ERROR(efi_status
))
363 return EFI_NOT_FOUND
;
367 #ifdef SHIM_UNIT_TEST
368 static void DESTRUCTOR
369 tpm_clean_up_measurements(void)
371 for (UINTN i
= 0; i
< measuredcount
; i
++) {
372 VARIABLE_RECORD
*vr
= &measureddata
[i
];
374 if (vr
->VariableName
)
375 FreePool(vr
->VariableName
);
377 FreePool(vr
->VendorGuid
);
382 FreePool(measureddata
);