]>
Commit | Line | Data |
---|---|---|
031e5cce | 1 | // SPDX-License-Identifier: BSD-2-Clause-Patent |
f892ac66 | 2 | #include "shim.h" |
d3819813 | 3 | |
ab881f03 MTL |
4 | typedef struct { |
5 | CHAR16 *VariableName; | |
6 | EFI_GUID *VendorGuid; | |
7 | VOID *Data; | |
8 | UINTN Size; | |
9 | } VARIABLE_RECORD; | |
10 | ||
11 | UINTN measuredcount = 0; | |
12 | VARIABLE_RECORD *measureddata = NULL; | |
8529e0f7 | 13 | static BOOLEAN tpm_defective = FALSE; |
ab881f03 | 14 | |
d3819813 MTL |
15 | static 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 |
35 | static 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 | ||
56 | static 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 |
73 | static 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 |
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) | |
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 |
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) | |
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 | |
260 | EFI_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 |
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) | |
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 | ||
302 | typedef 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 | |
310 | static 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 | ||
326 | static 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 | ||
357 | EFI_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 | ||
402 | EFI_STATUS | |
403 | fallback_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 | |
416 | static void DESTRUCTOR | |
417 | tpm_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 |