]> git.proxmox.com Git - efi-boot-shim.git/blob - tpm.c
Update upstream source from tag 'upstream/15.5'
[efi-boot-shim.git] / tpm.c
1 // SPDX-License-Identifier: BSD-2-Clause-Patent
2 #include "shim.h"
3
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;
13 static BOOLEAN tpm_defective = FALSE;
14
15 static BOOLEAN tpm_present(efi_tpm_protocol_t *tpm)
16 {
17 EFI_STATUS efi_status;
18 TCG_EFI_BOOT_SERVICE_CAPABILITY caps;
19 UINT32 flags;
20 EFI_PHYSICAL_ADDRESS eventlog, lastevent;
21
22 if (tpm_defective)
23 return FALSE;
24
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)
30 return FALSE;
31
32 return TRUE;
33 }
34
35 static EFI_STATUS tpm2_get_caps(efi_tpm2_protocol_t *tpm,
36 EFI_TCG2_BOOT_SERVICE_CAPABILITY *caps,
37 BOOLEAN *old_caps)
38 {
39 EFI_STATUS efi_status;
40
41 caps->Size = (UINT8)sizeof(*caps);
42
43 efi_status = tpm->get_capability(tpm, caps);
44 if (EFI_ERROR(efi_status))
45 return efi_status;
46
47 if (caps->StructureVersion.Major == 1 &&
48 caps->StructureVersion.Minor == 0)
49 *old_caps = TRUE;
50 else
51 *old_caps = FALSE;
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)
64 return TRUE;
65 }
66
67 if (caps->TPMPresentFlag)
68 return TRUE;
69
70 return FALSE;
71 }
72
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)
77 {
78 EFI_STATUS efi_status;
79
80 *tpm = NULL;
81 *tpm2 = NULL;
82 efi_status = LibLocateProtocol(&EFI_TPM2_GUID, (VOID **)tpm2);
83 /* TPM 2.0 */
84 if (!EFI_ERROR(efi_status)) {
85 BOOLEAN old_caps;
86 EFI_TCG2_BOOT_SERVICE_CAPABILITY caps;
87
88 efi_status = tpm2_get_caps(*tpm2, &caps, &old_caps);
89 if (EFI_ERROR(efi_status))
90 return efi_status;
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));
97 return EFI_SUCCESS;
98 }
99 } else {
100 efi_status = LibLocateProtocol(&EFI_TPM_GUID, (VOID **)tpm);
101 if (EFI_ERROR(efi_status))
102 return efi_status;
103
104 if (tpm_present(*tpm))
105 return EFI_SUCCESS;
106 }
107
108 return EFI_NOT_FOUND;
109 }
110
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)
114 {
115 EFI_STATUS efi_status;
116 efi_tpm_protocol_t *tpm;
117 efi_tpm2_protocol_t *tpm2;
118 BOOLEAN old_caps;
119 EFI_TCG2_BOOT_SERVICE_CAPABILITY caps;
120
121 efi_status = tpm_locate_protocol(&tpm, &tpm2, &old_caps, &caps);
122 if (EFI_ERROR(efi_status)) {
123 #ifdef REQUIRE_TPM
124 perror(L"TPM logging failed: %r\n", efi_status);
125 return efi_status;
126 #else
127 if (efi_status != EFI_NOT_FOUND) {
128 perror(L"TPM logging failed: %r\n", efi_status);
129 return efi_status;
130 }
131 #endif
132 } else if (tpm2) {
133 EFI_TCG2_EVENT *event;
134 UINTN event_size = sizeof(*event) - sizeof(event->Event) +
135 logsize;
136
137 event = AllocatePool(event_size);
138 if (!event) {
139 perror(L"Unable to allocate event structure\n");
140 return EFI_OUT_OF_RESOURCES;
141 }
142
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);
149 if (hash) {
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.
153 */
154 efi_status = tpm2->hash_log_extend_event(tpm2,
155 PE_COFF_IMAGE, buf, (UINT64) size, event);
156 }
157
158 if (!hash || EFI_ERROR(efi_status)) {
159 efi_status = tpm2->hash_log_extend_event(tpm2,
160 0, buf, (UINT64) size, event);
161 }
162 FreePool(event);
163 return efi_status;
164 } else if (tpm) {
165 TCG_PCR_EVENT *event;
166 UINT32 eventnum = 0;
167 EFI_PHYSICAL_ADDRESS lastevent;
168
169 efi_status = LibLocateProtocol(&EFI_TPM_GUID, (VOID **)&tpm);
170 if (EFI_ERROR(efi_status))
171 return EFI_SUCCESS;
172
173 if (!tpm_present(tpm))
174 return EFI_SUCCESS;
175
176 event = AllocatePool(sizeof(*event) + logsize);
177
178 if (!event) {
179 perror(L"Unable to allocate event structure\n");
180 return EFI_OUT_OF_RESOURCES;
181 }
182
183 event->PCRIndex = pcr;
184 event->EventType = type;
185 event->EventSize = logsize;
186 CopyMem(event->Event, (VOID *)log, logsize);
187 if (hash) {
188 /* TPM 1.2 devices require us to pass the Authenticode
189 hash rather than allowing the firmware to attempt
190 to calculate it */
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);
194 } else {
195 efi_status = tpm->log_extend_event(tpm, buf,
196 (UINT64)size, TPM_ALG_SHA, event, &eventnum,
197 &lastevent);
198 }
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;
204 }
205 FreePool(event);
206 return efi_status;
207 }
208
209 return EFI_SUCCESS;
210 }
211
212 EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
213 const CHAR8 *description)
214 {
215 return tpm_log_event_raw(buf, size, pcr, description,
216 strlen(description) + 1, EV_IPL, NULL);
217 }
218
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)
222 {
223 EFI_IMAGE_LOAD_EVENT *ImageLoad = NULL;
224 EFI_STATUS efi_status;
225 UINTN path_size = 0;
226
227 if (path)
228 path_size = DevicePathSize(path);
229
230 ImageLoad = AllocateZeroPool(sizeof(*ImageLoad) + path_size);
231 if (!ImageLoad) {
232 perror(L"Unable to allocate image load event structure\n");
233 return EFI_OUT_OF_RESOURCES;
234 }
235
236 ImageLoad->ImageLocationInMemory = buf;
237 ImageLoad->ImageLengthInMemory = size;
238 ImageLoad->ImageLinkTimeAddress = addr;
239
240 if (path_size > 0) {
241 CopyMem(ImageLoad->DevicePath, path, path_size);
242 ImageLoad->LengthOfDevicePath = path_size;
243 }
244
245 efi_status = tpm_log_event_raw(buf, size, pcr, (CHAR8 *)ImageLoad,
246 sizeof(*ImageLoad) + path_size,
247 EV_EFI_BOOT_SERVICES_APPLICATION,
248 (CHAR8 *)sha1hash);
249 FreePool(ImageLoad);
250
251 return efi_status;
252 }
253
254 typedef struct {
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;
261
262 static BOOLEAN tpm_data_measured(CHAR16 *VarName, EFI_GUID VendorGuid, UINTN VarSize, VOID *VarData)
263 {
264 UINTN i;
265
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)) {
271 return TRUE;
272 }
273 }
274
275 return FALSE;
276 }
277
278 static EFI_STATUS tpm_record_data_measurement(CHAR16 *VarName, EFI_GUID VendorGuid, UINTN VarSize, VOID *VarData)
279 {
280 if (measureddata == NULL) {
281 measureddata = AllocatePool(sizeof(*measureddata));
282 } else {
283 measureddata = ReallocatePool(measureddata, measuredcount * sizeof(*measureddata),
284 (measuredcount + 1) * sizeof(*measureddata));
285 }
286
287 if (measureddata == NULL)
288 return EFI_OUT_OF_RESOURCES;
289
290 measureddata[measuredcount].VariableName = AllocatePool(StrSize(VarName));
291 measureddata[measuredcount].VendorGuid = AllocatePool(sizeof(EFI_GUID));
292 measureddata[measuredcount].Data = AllocatePool(VarSize);
293
294 if (measureddata[measuredcount].VariableName == NULL ||
295 measureddata[measuredcount].VendorGuid == NULL ||
296 measureddata[measuredcount].Data == NULL) {
297 return EFI_OUT_OF_RESOURCES;
298 }
299
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;
304 measuredcount++;
305
306 return EFI_SUCCESS;
307 }
308
309 EFI_STATUS tpm_measure_variable(CHAR16 *VarName, EFI_GUID VendorGuid, UINTN VarSize, VOID *VarData)
310 {
311 EFI_STATUS efi_status;
312 UINTN VarNameLength;
313 EFI_VARIABLE_DATA_TREE *VarLog;
314 UINT32 VarLogSize;
315
316 /* Don't measure something that we've already measured */
317 if (tpm_data_measured(VarName, VendorGuid, VarSize, VarData))
318 return EFI_SUCCESS;
319
320 VarNameLength = StrLen (VarName);
321 VarLogSize = (UINT32)(sizeof (*VarLog) +
322 VarNameLength * sizeof (*VarName) +
323 VarSize -
324 sizeof (VarLog->UnicodeName) -
325 sizeof (VarLog->VariableData));
326
327 VarLog = (EFI_VARIABLE_DATA_TREE *) AllocateZeroPool (VarLogSize);
328 if (VarLog == NULL) {
329 return EFI_OUT_OF_RESOURCES;
330 }
331
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,
339 VarSize);
340
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);
344
345 FreePool(VarLog);
346
347 if (EFI_ERROR(efi_status))
348 return efi_status;
349
350 return tpm_record_data_measurement(VarName, VendorGuid, VarSize,
351 VarData);
352 }
353
354 EFI_STATUS
355 fallback_should_prefer_reset(void)
356 {
357 EFI_STATUS efi_status;
358 efi_tpm_protocol_t *tpm;
359 efi_tpm2_protocol_t *tpm2;
360
361 efi_status = tpm_locate_protocol(&tpm, &tpm2, NULL, NULL);
362 if (EFI_ERROR(efi_status))
363 return EFI_NOT_FOUND;
364 return EFI_SUCCESS;
365 }
366
367 #ifdef SHIM_UNIT_TEST
368 static void DESTRUCTOR
369 tpm_clean_up_measurements(void)
370 {
371 for (UINTN i = 0; i < measuredcount; i++) {
372 VARIABLE_RECORD *vr = &measureddata[i];
373
374 if (vr->VariableName)
375 FreePool(vr->VariableName);
376 if (vr->VendorGuid)
377 FreePool(vr->VendorGuid);
378 if (vr->Data)
379 FreePool(vr->Data);
380 }
381 if (measureddata)
382 FreePool(measureddata);
383
384 measuredcount = 0;
385 measureddata = NULL;
386 }
387 #endif