]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c
SecurityPkg: Support CcMeasurementProtocol in DxeTpm2MeasureBootLib
[mirror_edk2.git] / SecurityPkg / Library / DxeTpm2MeasureBootLib / DxeTpm2MeasureBootLib.c
... / ...
CommitLineData
1/** @file\r
2 The library instance provides security service of TPM2 measure boot and\r
3 Confidential Computing (CC) measure boot.\r
4\r
5 Caution: This file requires additional review when modified.\r
6 This library will have external input - PE/COFF image and GPT partition.\r
7 This external input must be validated carefully to avoid security issue like\r
8 buffer overflow, integer overflow.\r
9\r
10 DxeTpm2MeasureBootLibImageRead() function will make sure the PE/COFF image content\r
11 read is within the image buffer.\r
12\r
13 Tcg2MeasurePeImage() function will accept untrusted PE/COFF image and validate its\r
14 data structure within this image buffer before use.\r
15\r
16 Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse\r
17 partition data carefully.\r
18\r
19Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>\r
20(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
21SPDX-License-Identifier: BSD-2-Clause-Patent\r
22\r
23**/\r
24\r
25#include <PiDxe.h>\r
26\r
27#include <Protocol/Tcg2Protocol.h>\r
28#include <Protocol/BlockIo.h>\r
29#include <Protocol/DiskIo.h>\r
30#include <Protocol/DevicePathToText.h>\r
31#include <Protocol/FirmwareVolumeBlock.h>\r
32\r
33#include <Guid/MeasuredFvHob.h>\r
34\r
35#include <Library/BaseLib.h>\r
36#include <Library/DebugLib.h>\r
37#include <Library/BaseMemoryLib.h>\r
38#include <Library/MemoryAllocationLib.h>\r
39#include <Library/DevicePathLib.h>\r
40#include <Library/UefiBootServicesTableLib.h>\r
41#include <Library/BaseCryptLib.h>\r
42#include <Library/PeCoffLib.h>\r
43#include <Library/SecurityManagementLib.h>\r
44#include <Library/HobLib.h>\r
45#include <Protocol/CcMeasurement.h>\r
46\r
47typedef struct {\r
48 EFI_TCG2_PROTOCOL *Tcg2Protocol;\r
49 EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol;\r
50} MEASURE_BOOT_PROTOCOLS;\r
51\r
52//\r
53// Flag to check GPT partition. It only need be measured once.\r
54//\r
55BOOLEAN mTcg2MeasureGptTableFlag = FALSE;\r
56UINTN mTcg2MeasureGptCount = 0;\r
57VOID *mTcg2FileBuffer;\r
58UINTN mTcg2ImageSize;\r
59//\r
60// Measured FV handle cache\r
61//\r
62EFI_HANDLE mTcg2CacheMeasuredHandle = NULL;\r
63MEASURED_HOB_DATA *mTcg2MeasuredHobData = NULL;\r
64\r
65/**\r
66 Reads contents of a PE/COFF image in memory buffer.\r
67\r
68 Caution: This function may receive untrusted input.\r
69 PE/COFF image is external input, so this function will make sure the PE/COFF image content\r
70 read is within the image buffer.\r
71\r
72 @param FileHandle Pointer to the file handle to read the PE/COFF image.\r
73 @param FileOffset Offset into the PE/COFF image to begin the read operation.\r
74 @param ReadSize On input, the size in bytes of the requested read operation.\r
75 On output, the number of bytes actually read.\r
76 @param Buffer Output buffer that contains the data read from the PE/COFF image.\r
77\r
78 @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size\r
79**/\r
80EFI_STATUS\r
81EFIAPI\r
82DxeTpm2MeasureBootLibImageRead (\r
83 IN VOID *FileHandle,\r
84 IN UINTN FileOffset,\r
85 IN OUT UINTN *ReadSize,\r
86 OUT VOID *Buffer\r
87 )\r
88{\r
89 UINTN EndPosition;\r
90\r
91 if ((FileHandle == NULL) || (ReadSize == NULL) || (Buffer == NULL)) {\r
92 return EFI_INVALID_PARAMETER;\r
93 }\r
94\r
95 if (MAX_ADDRESS - FileOffset < *ReadSize) {\r
96 return EFI_INVALID_PARAMETER;\r
97 }\r
98\r
99 EndPosition = FileOffset + *ReadSize;\r
100 if (EndPosition > mTcg2ImageSize) {\r
101 *ReadSize = (UINT32)(mTcg2ImageSize - FileOffset);\r
102 }\r
103\r
104 if (FileOffset >= mTcg2ImageSize) {\r
105 *ReadSize = 0;\r
106 }\r
107\r
108 CopyMem (Buffer, (UINT8 *)((UINTN)FileHandle + FileOffset), *ReadSize);\r
109\r
110 return EFI_SUCCESS;\r
111}\r
112\r
113/**\r
114 Measure GPT table data into TPM log.\r
115\r
116 Caution: This function may receive untrusted input.\r
117 The GPT partition table is external input, so this function should parse partition data carefully.\r
118\r
119 @param MeasureBootProtocols Pointer to the located MeasureBoot protocol instances (i.e. TCG2/CC protocol).\r
120 @param GptHandle Handle that GPT partition was installed.\r
121\r
122 @retval EFI_SUCCESS Successfully measure GPT table.\r
123 @retval EFI_UNSUPPORTED Not support GPT table on the given handle.\r
124 @retval EFI_DEVICE_ERROR Can't get GPT table because device error.\r
125 @retval EFI_OUT_OF_RESOURCES No enough resource to measure GPT table.\r
126 @retval other error value\r
127**/\r
128EFI_STATUS\r
129EFIAPI\r
130Tcg2MeasureGptTable (\r
131 IN MEASURE_BOOT_PROTOCOLS *MeasureBootProtocols,\r
132 IN EFI_HANDLE GptHandle\r
133 )\r
134{\r
135 EFI_STATUS Status;\r
136 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
137 EFI_DISK_IO_PROTOCOL *DiskIo;\r
138 EFI_PARTITION_TABLE_HEADER *PrimaryHeader;\r
139 EFI_PARTITION_ENTRY *PartitionEntry;\r
140 UINT8 *EntryPtr;\r
141 UINTN NumberOfPartition;\r
142 UINT32 Index;\r
143 UINT8 *EventPtr;\r
144 EFI_TCG2_EVENT *Tcg2Event;\r
145 EFI_CC_EVENT *CcEvent;\r
146 EFI_GPT_DATA *GptData;\r
147 UINT32 EventSize;\r
148 EFI_TCG2_PROTOCOL *Tcg2Protocol;\r
149 EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol;\r
150 EFI_CC_MR_INDEX MrIndex;\r
151\r
152 if (mTcg2MeasureGptCount > 0) {\r
153 return EFI_SUCCESS;\r
154 }\r
155\r
156 PrimaryHeader = NULL;\r
157 EntryPtr = NULL;\r
158 EventPtr = NULL;\r
159\r
160 Tcg2Protocol = MeasureBootProtocols->Tcg2Protocol;\r
161 CcProtocol = MeasureBootProtocols->CcProtocol;\r
162\r
163 if ((Tcg2Protocol == NULL) && (CcProtocol == NULL)) {\r
164 ASSERT (FALSE);\r
165 return EFI_UNSUPPORTED;\r
166 }\r
167\r
168 if (sizeof (EFI_CC_EVENT) != sizeof (EFI_TCG2_EVENT)) {\r
169 ASSERT (FALSE);\r
170 return EFI_UNSUPPORTED;\r
171 }\r
172\r
173 Status = gBS->HandleProtocol (GptHandle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);\r
174 if (EFI_ERROR (Status)) {\r
175 return EFI_UNSUPPORTED;\r
176 }\r
177\r
178 Status = gBS->HandleProtocol (GptHandle, &gEfiDiskIoProtocolGuid, (VOID **)&DiskIo);\r
179 if (EFI_ERROR (Status)) {\r
180 return EFI_UNSUPPORTED;\r
181 }\r
182\r
183 //\r
184 // Read the EFI Partition Table Header\r
185 //\r
186 PrimaryHeader = (EFI_PARTITION_TABLE_HEADER *)AllocatePool (BlockIo->Media->BlockSize);\r
187 if (PrimaryHeader == NULL) {\r
188 return EFI_OUT_OF_RESOURCES;\r
189 }\r
190\r
191 Status = DiskIo->ReadDisk (\r
192 DiskIo,\r
193 BlockIo->Media->MediaId,\r
194 1 * BlockIo->Media->BlockSize,\r
195 BlockIo->Media->BlockSize,\r
196 (UINT8 *)PrimaryHeader\r
197 );\r
198 if (EFI_ERROR (Status)) {\r
199 DEBUG ((DEBUG_ERROR, "Failed to Read Partition Table Header!\n"));\r
200 FreePool (PrimaryHeader);\r
201 return EFI_DEVICE_ERROR;\r
202 }\r
203\r
204 //\r
205 // PrimaryHeader->SizeOfPartitionEntry should not be zero\r
206 //\r
207 if (PrimaryHeader->SizeOfPartitionEntry == 0) {\r
208 DEBUG ((DEBUG_ERROR, "SizeOfPartitionEntry should not be zero!\n"));\r
209 FreePool (PrimaryHeader);\r
210 return EFI_BAD_BUFFER_SIZE;\r
211 }\r
212\r
213 //\r
214 // Read the partition entry.\r
215 //\r
216 EntryPtr = (UINT8 *)AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);\r
217 if (EntryPtr == NULL) {\r
218 FreePool (PrimaryHeader);\r
219 return EFI_OUT_OF_RESOURCES;\r
220 }\r
221\r
222 Status = DiskIo->ReadDisk (\r
223 DiskIo,\r
224 BlockIo->Media->MediaId,\r
225 MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),\r
226 PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry,\r
227 EntryPtr\r
228 );\r
229 if (EFI_ERROR (Status)) {\r
230 FreePool (PrimaryHeader);\r
231 FreePool (EntryPtr);\r
232 return EFI_DEVICE_ERROR;\r
233 }\r
234\r
235 //\r
236 // Count the valid partition\r
237 //\r
238 PartitionEntry = (EFI_PARTITION_ENTRY *)EntryPtr;\r
239 NumberOfPartition = 0;\r
240 for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {\r
241 if (!IsZeroGuid (&PartitionEntry->PartitionTypeGUID)) {\r
242 NumberOfPartition++;\r
243 }\r
244\r
245 PartitionEntry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry);\r
246 }\r
247\r
248 //\r
249 // Prepare Data for Measurement (CcProtocol and Tcg2Protocol)\r
250 //\r
251 EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions)\r
252 + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry);\r
253 EventPtr = (UINT8 *)AllocateZeroPool (EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event));\r
254 if (EventPtr == NULL) {\r
255 Status = EFI_OUT_OF_RESOURCES;\r
256 goto Exit;\r
257 }\r
258\r
259 Tcg2Event = (EFI_TCG2_EVENT *)EventPtr;\r
260 Tcg2Event->Size = EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event);\r
261 Tcg2Event->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER);\r
262 Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION;\r
263 Tcg2Event->Header.PCRIndex = 5;\r
264 Tcg2Event->Header.EventType = EV_EFI_GPT_EVENT;\r
265 GptData = (EFI_GPT_DATA *)Tcg2Event->Event;\r
266\r
267 //\r
268 // Copy the EFI_PARTITION_TABLE_HEADER and NumberOfPartition\r
269 //\r
270 CopyMem ((UINT8 *)GptData, (UINT8 *)PrimaryHeader, sizeof (EFI_PARTITION_TABLE_HEADER));\r
271 GptData->NumberOfPartitions = NumberOfPartition;\r
272 //\r
273 // Copy the valid partition entry\r
274 //\r
275 PartitionEntry = (EFI_PARTITION_ENTRY *)EntryPtr;\r
276 NumberOfPartition = 0;\r
277 for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {\r
278 if (!IsZeroGuid (&PartitionEntry->PartitionTypeGUID)) {\r
279 CopyMem (\r
280 (UINT8 *)&GptData->Partitions + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry,\r
281 (UINT8 *)PartitionEntry,\r
282 PrimaryHeader->SizeOfPartitionEntry\r
283 );\r
284 NumberOfPartition++;\r
285 }\r
286\r
287 PartitionEntry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry);\r
288 }\r
289\r
290 //\r
291 // Only one of TCG2_PROTOCOL or CC_MEASUREMENT_PROTOCOL is exposed.\r
292 // So Measure the GPT data with one of the protocol.\r
293 //\r
294 if (CcProtocol != NULL) {\r
295 //\r
296 // EFI_CC_EVENT share the same data structure with EFI_TCG2_EVENT\r
297 // except the MrIndex and PCRIndex in Header.\r
298 // Tcg2Event has been created and initialized before. So only the MrIndex need\r
299 // be adjusted.\r
300 //\r
301 Status = CcProtocol->MapPcrToMrIndex (CcProtocol, Tcg2Event->Header.PCRIndex, &MrIndex);\r
302 if (EFI_ERROR (Status)) {\r
303 DEBUG ((DEBUG_ERROR, "Cannot map PcrIndex(%d) to MrIndex\n", Tcg2Event->Header.PCRIndex));\r
304 goto Exit;\r
305 }\r
306\r
307 CcEvent = (EFI_CC_EVENT *)EventPtr;\r
308 CcEvent->Header.MrIndex = MrIndex;\r
309 Status = CcProtocol->HashLogExtendEvent (\r
310 CcProtocol,\r
311 0,\r
312 (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)GptData,\r
313 (UINT64)EventSize,\r
314 CcEvent\r
315 );\r
316 if (!EFI_ERROR (Status)) {\r
317 mTcg2MeasureGptCount++;\r
318 }\r
319\r
320 DEBUG ((DEBUG_INFO, "DxeTpm2MeasureBootHandler - Cc MeasureGptTable - %r\n", Status));\r
321 } else if (Tcg2Protocol != NULL) {\r
322 //\r
323 // If Tcg2Protocol is installed, then Measure GPT data with this protocol.\r
324 //\r
325 Status = Tcg2Protocol->HashLogExtendEvent (\r
326 Tcg2Protocol,\r
327 0,\r
328 (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)GptData,\r
329 (UINT64)EventSize,\r
330 Tcg2Event\r
331 );\r
332 if (!EFI_ERROR (Status)) {\r
333 mTcg2MeasureGptCount++;\r
334 }\r
335\r
336 DEBUG ((DEBUG_INFO, "DxeTpm2MeasureBootHandler - Tcg2 MeasureGptTable - %r\n", Status));\r
337 }\r
338\r
339Exit:\r
340 if (PrimaryHeader != NULL) {\r
341 FreePool (PrimaryHeader);\r
342 }\r
343\r
344 if (EntryPtr != NULL) {\r
345 FreePool (EntryPtr);\r
346 }\r
347\r
348 if (EventPtr != NULL) {\r
349 FreePool (EventPtr);\r
350 }\r
351\r
352 return Status;\r
353}\r
354\r
355/**\r
356 Measure PE image into TPM log based on the authenticode image hashing in\r
357 PE/COFF Specification 8.0 Appendix A.\r
358\r
359 Caution: This function may receive untrusted input.\r
360 PE/COFF image is external input, so this function will validate its data structure\r
361 within this image buffer before use.\r
362\r
363 @param[in] MeasureBootProtocols Pointer to the located MeasureBoot protocol instances.\r
364 @param[in] ImageAddress Start address of image buffer.\r
365 @param[in] ImageSize Image size\r
366 @param[in] LinkTimeBase Address that the image is loaded into memory.\r
367 @param[in] ImageType Image subsystem type.\r
368 @param[in] FilePath File path is corresponding to the input image.\r
369\r
370 @retval EFI_SUCCESS Successfully measure image.\r
371 @retval EFI_OUT_OF_RESOURCES No enough resource to measure image.\r
372 @retval EFI_UNSUPPORTED ImageType is unsupported or PE image is mal-format.\r
373 @retval other error value\r
374\r
375**/\r
376EFI_STATUS\r
377EFIAPI\r
378Tcg2MeasurePeImage (\r
379 IN MEASURE_BOOT_PROTOCOLS *MeasureBootProtocols,\r
380 IN EFI_PHYSICAL_ADDRESS ImageAddress,\r
381 IN UINTN ImageSize,\r
382 IN UINTN LinkTimeBase,\r
383 IN UINT16 ImageType,\r
384 IN EFI_DEVICE_PATH_PROTOCOL *FilePath\r
385 )\r
386{\r
387 EFI_STATUS Status;\r
388 EFI_TCG2_EVENT *Tcg2Event;\r
389 EFI_IMAGE_LOAD_EVENT *ImageLoad;\r
390 UINT32 FilePathSize;\r
391 UINT32 EventSize;\r
392 EFI_CC_EVENT *CcEvent;\r
393 EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol;\r
394 EFI_TCG2_PROTOCOL *Tcg2Protocol;\r
395 UINT8 *EventPtr;\r
396 EFI_CC_MR_INDEX MrIndex;\r
397\r
398 Status = EFI_UNSUPPORTED;\r
399 ImageLoad = NULL;\r
400 EventPtr = NULL;\r
401\r
402 Tcg2Protocol = MeasureBootProtocols->Tcg2Protocol;\r
403 CcProtocol = MeasureBootProtocols->CcProtocol;\r
404\r
405 if ((Tcg2Protocol == NULL) && (CcProtocol == NULL)) {\r
406 ASSERT (FALSE);\r
407 return EFI_UNSUPPORTED;\r
408 }\r
409\r
410 if (sizeof (EFI_CC_EVENT) != sizeof (EFI_TCG2_EVENT)) {\r
411 ASSERT (FALSE);\r
412 return EFI_UNSUPPORTED;\r
413 }\r
414\r
415 FilePathSize = (UINT32)GetDevicePathSize (FilePath);\r
416\r
417 //\r
418 // Determine destination PCR by BootPolicy\r
419 //\r
420 EventSize = sizeof (*ImageLoad) - sizeof (ImageLoad->DevicePath) + FilePathSize;\r
421 EventPtr = AllocateZeroPool (EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event));\r
422 if (EventPtr == NULL) {\r
423 return EFI_OUT_OF_RESOURCES;\r
424 }\r
425\r
426 Tcg2Event = (EFI_TCG2_EVENT *)EventPtr;\r
427 Tcg2Event->Size = EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event);\r
428 Tcg2Event->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER);\r
429 Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION;\r
430 ImageLoad = (EFI_IMAGE_LOAD_EVENT *)Tcg2Event->Event;\r
431\r
432 switch (ImageType) {\r
433 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:\r
434 Tcg2Event->Header.EventType = EV_EFI_BOOT_SERVICES_APPLICATION;\r
435 Tcg2Event->Header.PCRIndex = 4;\r
436 break;\r
437 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:\r
438 Tcg2Event->Header.EventType = EV_EFI_BOOT_SERVICES_DRIVER;\r
439 Tcg2Event->Header.PCRIndex = 2;\r
440 break;\r
441 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:\r
442 Tcg2Event->Header.EventType = EV_EFI_RUNTIME_SERVICES_DRIVER;\r
443 Tcg2Event->Header.PCRIndex = 2;\r
444 break;\r
445 default:\r
446 DEBUG ((\r
447 DEBUG_ERROR,\r
448 "Tcg2MeasurePeImage: Unknown subsystem type %d",\r
449 ImageType\r
450 ));\r
451 goto Finish;\r
452 }\r
453\r
454 ImageLoad->ImageLocationInMemory = ImageAddress;\r
455 ImageLoad->ImageLengthInMemory = ImageSize;\r
456 ImageLoad->ImageLinkTimeAddress = LinkTimeBase;\r
457 ImageLoad->LengthOfDevicePath = FilePathSize;\r
458 if ((FilePath != NULL) && (FilePathSize != 0)) {\r
459 CopyMem (ImageLoad->DevicePath, FilePath, FilePathSize);\r
460 }\r
461\r
462 //\r
463 // Log the PE data\r
464 //\r
465 if (CcProtocol != NULL) {\r
466 Status = CcProtocol->MapPcrToMrIndex (CcProtocol, Tcg2Event->Header.PCRIndex, &MrIndex);\r
467 if (EFI_ERROR (Status)) {\r
468 DEBUG ((DEBUG_ERROR, "Cannot map PcrIndex(%d) to MrIndex\n", Tcg2Event->Header.PCRIndex));\r
469 goto Finish;\r
470 }\r
471\r
472 CcEvent = (EFI_CC_EVENT *)EventPtr;\r
473 CcEvent->Header.MrIndex = MrIndex;\r
474\r
475 Status = CcProtocol->HashLogExtendEvent (\r
476 CcProtocol,\r
477 PE_COFF_IMAGE,\r
478 ImageAddress,\r
479 ImageSize,\r
480 CcEvent\r
481 );\r
482 DEBUG ((DEBUG_INFO, "DxeTpm2MeasureBootHandler - Cc MeasurePeImage - %r\n", Status));\r
483 } else if (Tcg2Protocol != NULL) {\r
484 Status = Tcg2Protocol->HashLogExtendEvent (\r
485 Tcg2Protocol,\r
486 PE_COFF_IMAGE,\r
487 ImageAddress,\r
488 ImageSize,\r
489 Tcg2Event\r
490 );\r
491 DEBUG ((DEBUG_INFO, "DxeTpm2MeasureBootHandler - Tcg2 MeasurePeImage - %r\n", Status));\r
492 }\r
493\r
494 if (Status == EFI_VOLUME_FULL) {\r
495 //\r
496 // Volume full here means the image is hashed and its result is extended to PCR.\r
497 // But the event log can't be saved since log area is full.\r
498 // Just return EFI_SUCCESS in order not to block the image load.\r
499 //\r
500 Status = EFI_SUCCESS;\r
501 }\r
502\r
503Finish:\r
504 if (EventPtr != NULL) {\r
505 FreePool (EventPtr);\r
506 }\r
507\r
508 return Status;\r
509}\r
510\r
511/**\r
512 Get the measure boot protocols.\r
513\r
514 There are 2 measure boot, TCG2 protocol based and Cc measurement protocol based.\r
515\r
516 @param MeasureBootProtocols Pointer to the located measure boot protocol instances.\r
517\r
518 @retval EFI_SUCCESS Sucessfully locate the measure boot protocol instances (at least one instance).\r
519 @retval EFI_UNSUPPORTED Measure boot is not supported.\r
520**/\r
521EFI_STATUS\r
522EFIAPI\r
523GetMeasureBootProtocols (\r
524 MEASURE_BOOT_PROTOCOLS *MeasureBootProtocols\r
525 )\r
526{\r
527 EFI_STATUS Status;\r
528 EFI_TCG2_PROTOCOL *Tcg2Protocol;\r
529 EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol;\r
530 EFI_TCG2_BOOT_SERVICE_CAPABILITY Tcg2ProtocolCapability;\r
531 EFI_CC_BOOT_SERVICE_CAPABILITY CcProtocolCapability;\r
532\r
533 CcProtocol = NULL;\r
534 Status = gBS->LocateProtocol (&gEfiCcMeasurementProtocolGuid, NULL, (VOID **)&CcProtocol);\r
535 if (EFI_ERROR (Status)) {\r
536 //\r
537 // Cc Measurement protocol is not installed.\r
538 //\r
539 DEBUG ((DEBUG_VERBOSE, "CcMeasurementProtocol is not installed. - %r\n", Status));\r
540 } else {\r
541 ZeroMem (&CcProtocolCapability, sizeof (CcProtocolCapability));\r
542 CcProtocolCapability.Size = sizeof (CcProtocolCapability);\r
543 Status = CcProtocol->GetCapability (CcProtocol, &CcProtocolCapability);\r
544 if (EFI_ERROR (Status) || (CcProtocolCapability.CcType.Type == EFI_CC_TYPE_NONE)) {\r
545 DEBUG ((DEBUG_ERROR, " CcProtocol->GetCapability returns : %x, %r\n", CcProtocolCapability.CcType.Type, Status));\r
546 CcProtocol = NULL;\r
547 }\r
548 }\r
549\r
550 Tcg2Protocol = NULL;\r
551 Status = gBS->LocateProtocol (&gEfiTcg2ProtocolGuid, NULL, (VOID **)&Tcg2Protocol);\r
552 if (EFI_ERROR (Status)) {\r
553 //\r
554 // Tcg2 protocol is not installed. So, TPM2 is not present.\r
555 //\r
556 DEBUG ((DEBUG_VERBOSE, "Tcg2Protocol is not installed. - %r\n", Status));\r
557 } else {\r
558 Tcg2ProtocolCapability.Size = (UINT8)sizeof (Tcg2ProtocolCapability);\r
559 Status = Tcg2Protocol->GetCapability (Tcg2Protocol, &Tcg2ProtocolCapability);\r
560 if (EFI_ERROR (Status) || (!Tcg2ProtocolCapability.TPMPresentFlag)) {\r
561 //\r
562 // TPM device doesn't work or activate.\r
563 //\r
564 DEBUG ((DEBUG_ERROR, "TPMPresentFlag=FALSE %r\n", Status));\r
565 Tcg2Protocol = NULL;\r
566 }\r
567 }\r
568\r
569 MeasureBootProtocols->Tcg2Protocol = Tcg2Protocol;\r
570 MeasureBootProtocols->CcProtocol = CcProtocol;\r
571\r
572 return (Tcg2Protocol == NULL && CcProtocol == NULL) ? EFI_UNSUPPORTED : EFI_SUCCESS;\r
573}\r
574\r
575/**\r
576 The security handler is used to abstract platform-specific policy\r
577 from the DXE core response to an attempt to use a file that returns a\r
578 given status for the authentication check from the section extraction protocol.\r
579\r
580 The possible responses in a given SAP implementation may include locking\r
581 flash upon failure to authenticate, attestation logging for all signed drivers,\r
582 and other exception operations. The File parameter allows for possible logging\r
583 within the SAP of the driver.\r
584\r
585 If the file specified by File with an authentication status specified by\r
586 AuthenticationStatus is safe for the DXE Core to use, then EFI_SUCCESS is returned.\r
587\r
588 If the file specified by File with an authentication status specified by\r
589 AuthenticationStatus is not safe for the DXE Core to use under any circumstances,\r
590 then EFI_ACCESS_DENIED is returned.\r
591\r
592 If the file specified by File with an authentication status specified by\r
593 AuthenticationStatus is not safe for the DXE Core to use right now, but it\r
594 might be possible to use it at a future time, then EFI_SECURITY_VIOLATION is\r
595 returned.\r
596\r
597 If check image specified by FileBuffer and File is NULL meanwhile, return EFI_ACCESS_DENIED.\r
598\r
599 @param[in] AuthenticationStatus This is the authentication status returned\r
600 from the securitymeasurement services for the\r
601 input file.\r
602 @param[in] File This is a pointer to the device path of the file that is\r
603 being dispatched. This will optionally be used for logging.\r
604 @param[in] FileBuffer File buffer matches the input file device path.\r
605 @param[in] FileSize Size of File buffer matches the input file device path.\r
606 @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.\r
607\r
608 @retval EFI_SUCCESS The file specified by DevicePath and non-NULL\r
609 FileBuffer did authenticate, and the platform policy dictates\r
610 that the DXE Foundation may use the file.\r
611 @retval other error value\r
612**/\r
613EFI_STATUS\r
614EFIAPI\r
615DxeTpm2MeasureBootHandler (\r
616 IN UINT32 AuthenticationStatus,\r
617 IN CONST EFI_DEVICE_PATH_PROTOCOL *File OPTIONAL,\r
618 IN VOID *FileBuffer,\r
619 IN UINTN FileSize,\r
620 IN BOOLEAN BootPolicy\r
621 )\r
622{\r
623 MEASURE_BOOT_PROTOCOLS MeasureBootProtocols;\r
624 EFI_STATUS Status;\r
625 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;\r
626 EFI_DEVICE_PATH_PROTOCOL *OrigDevicePathNode;\r
627 EFI_HANDLE Handle;\r
628 EFI_HANDLE TempHandle;\r
629 BOOLEAN ApplicationRequired;\r
630 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
631 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol;\r
632 EFI_PHYSICAL_ADDRESS FvAddress;\r
633 UINT32 Index;\r
634\r
635 MeasureBootProtocols.Tcg2Protocol = NULL;\r
636 MeasureBootProtocols.CcProtocol = NULL;\r
637\r
638 Status = GetMeasureBootProtocols (&MeasureBootProtocols);\r
639\r
640 if (EFI_ERROR (Status)) {\r
641 //\r
642 // None of Measured boot protocols (Tcg2, Cc) is installed.\r
643 // Don't do any measurement, and directly return EFI_SUCCESS.\r
644 //\r
645 DEBUG ((DEBUG_INFO, "None of Tcg2Protocol/CcMeasurementProtocol is installed.\n"));\r
646 return EFI_SUCCESS;\r
647 }\r
648\r
649 DEBUG ((\r
650 DEBUG_INFO,\r
651 "Tcg2Protocol = %p, CcMeasurementProtocol = %p\n",\r
652 MeasureBootProtocols.Tcg2Protocol,\r
653 MeasureBootProtocols.CcProtocol\r
654 ));\r
655\r
656 //\r
657 // Copy File Device Path\r
658 //\r
659 OrigDevicePathNode = DuplicateDevicePath (File);\r
660\r
661 //\r
662 // 1. Check whether this device path support BlockIo protocol.\r
663 // Is so, this device path may be a GPT device path.\r
664 //\r
665 DevicePathNode = OrigDevicePathNode;\r
666 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevicePathNode, &Handle);\r
667 if (!EFI_ERROR (Status) && !mTcg2MeasureGptTableFlag) {\r
668 //\r
669 // Find the gpt partition on the given devicepath\r
670 //\r
671 DevicePathNode = OrigDevicePathNode;\r
672 ASSERT (DevicePathNode != NULL);\r
673 while (!IsDevicePathEnd (DevicePathNode)) {\r
674 //\r
675 // Find the Gpt partition\r
676 //\r
677 if ((DevicePathType (DevicePathNode) == MEDIA_DEVICE_PATH) &&\r
678 (DevicePathSubType (DevicePathNode) == MEDIA_HARDDRIVE_DP))\r
679 {\r
680 //\r
681 // Check whether it is a gpt partition or not\r
682 //\r
683 if ((((HARDDRIVE_DEVICE_PATH *)DevicePathNode)->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER) &&\r
684 (((HARDDRIVE_DEVICE_PATH *)DevicePathNode)->SignatureType == SIGNATURE_TYPE_GUID))\r
685 {\r
686 //\r
687 // Change the partition device path to its parent device path (disk) and get the handle.\r
688 //\r
689 DevicePathNode->Type = END_DEVICE_PATH_TYPE;\r
690 DevicePathNode->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;\r
691 DevicePathNode = OrigDevicePathNode;\r
692 Status = gBS->LocateDevicePath (\r
693 &gEfiDiskIoProtocolGuid,\r
694 &DevicePathNode,\r
695 &Handle\r
696 );\r
697 if (!EFI_ERROR (Status)) {\r
698 //\r
699 // Measure GPT disk.\r
700 //\r
701 Status = Tcg2MeasureGptTable (&MeasureBootProtocols, Handle);\r
702\r
703 if (!EFI_ERROR (Status)) {\r
704 //\r
705 // GPT disk check done.\r
706 //\r
707 mTcg2MeasureGptTableFlag = TRUE;\r
708 }\r
709 }\r
710\r
711 FreePool (OrigDevicePathNode);\r
712 OrigDevicePathNode = DuplicateDevicePath (File);\r
713 ASSERT (OrigDevicePathNode != NULL);\r
714 break;\r
715 }\r
716 }\r
717\r
718 DevicePathNode = NextDevicePathNode (DevicePathNode);\r
719 }\r
720 }\r
721\r
722 //\r
723 // 2. Measure PE image.\r
724 //\r
725 ApplicationRequired = FALSE;\r
726\r
727 //\r
728 // Check whether this device path support FVB protocol.\r
729 //\r
730 DevicePathNode = OrigDevicePathNode;\r
731 Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &DevicePathNode, &Handle);\r
732 if (!EFI_ERROR (Status)) {\r
733 //\r
734 // Don't check FV image, and directly return EFI_SUCCESS.\r
735 // It can be extended to the specific FV authentication according to the different requirement.\r
736 //\r
737 if (IsDevicePathEnd (DevicePathNode)) {\r
738 return EFI_SUCCESS;\r
739 }\r
740\r
741 //\r
742 // The PE image from unmeasured Firmware volume need be measured\r
743 // The PE image from measured Firmware volume will be measured according to policy below.\r
744 // If it is driver, do not measure\r
745 // If it is application, still measure.\r
746 //\r
747 ApplicationRequired = TRUE;\r
748\r
749 if ((mTcg2CacheMeasuredHandle != Handle) && (mTcg2MeasuredHobData != NULL)) {\r
750 //\r
751 // Search for Root FV of this PE image\r
752 //\r
753 TempHandle = Handle;\r
754 do {\r
755 Status = gBS->HandleProtocol (\r
756 TempHandle,\r
757 &gEfiFirmwareVolumeBlockProtocolGuid,\r
758 (VOID **)&FvbProtocol\r
759 );\r
760 TempHandle = FvbProtocol->ParentHandle;\r
761 } while (!EFI_ERROR (Status) && FvbProtocol->ParentHandle != NULL);\r
762\r
763 //\r
764 // Search in measured FV Hob\r
765 //\r
766 Status = FvbProtocol->GetPhysicalAddress (FvbProtocol, &FvAddress);\r
767 if (EFI_ERROR (Status)) {\r
768 return Status;\r
769 }\r
770\r
771 ApplicationRequired = FALSE;\r
772\r
773 for (Index = 0; Index < mTcg2MeasuredHobData->Num; Index++) {\r
774 if (mTcg2MeasuredHobData->MeasuredFvBuf[Index].BlobBase == FvAddress) {\r
775 //\r
776 // Cache measured FV for next measurement\r
777 //\r
778 mTcg2CacheMeasuredHandle = Handle;\r
779 ApplicationRequired = TRUE;\r
780 break;\r
781 }\r
782 }\r
783 }\r
784 }\r
785\r
786 //\r
787 // File is not found.\r
788 //\r
789 if (FileBuffer == NULL) {\r
790 Status = EFI_SECURITY_VIOLATION;\r
791 goto Finish;\r
792 }\r
793\r
794 mTcg2ImageSize = FileSize;\r
795 mTcg2FileBuffer = FileBuffer;\r
796\r
797 //\r
798 // Measure PE Image\r
799 //\r
800 DevicePathNode = OrigDevicePathNode;\r
801 ZeroMem (&ImageContext, sizeof (ImageContext));\r
802 ImageContext.Handle = (VOID *)FileBuffer;\r
803 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)DxeTpm2MeasureBootLibImageRead;\r
804\r
805 //\r
806 // Get information about the image being loaded\r
807 //\r
808 Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
809 if (EFI_ERROR (Status)) {\r
810 //\r
811 // Check for invalid parameters.\r
812 //\r
813 if (File == NULL) {\r
814 Status = EFI_ACCESS_DENIED;\r
815 }\r
816\r
817 //\r
818 // The information can't be got from the invalid PeImage\r
819 //\r
820 goto Finish;\r
821 }\r
822\r
823 //\r
824 // Measure only application if Application flag is set\r
825 // Measure drivers and applications if Application flag is not set\r
826 //\r
827 if ((!ApplicationRequired) ||\r
828 (ApplicationRequired && (ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)))\r
829 {\r
830 //\r
831 // Print the image path to be measured.\r
832 //\r
833 DEBUG_CODE_BEGIN ();\r
834 CHAR16 *ToText;\r
835 ToText = ConvertDevicePathToText (\r
836 DevicePathNode,\r
837 FALSE,\r
838 TRUE\r
839 );\r
840 if (ToText != NULL) {\r
841 DEBUG ((DEBUG_INFO, "The measured image path is %s.\n", ToText));\r
842 FreePool (ToText);\r
843 }\r
844\r
845 DEBUG_CODE_END ();\r
846\r
847 //\r
848 // Measure PE image into TPM log.\r
849 //\r
850 Status = Tcg2MeasurePeImage (\r
851 &MeasureBootProtocols,\r
852 (EFI_PHYSICAL_ADDRESS)(UINTN)FileBuffer,\r
853 FileSize,\r
854 (UINTN)ImageContext.ImageAddress,\r
855 ImageContext.ImageType,\r
856 DevicePathNode\r
857 );\r
858 }\r
859\r
860 //\r
861 // Done, free the allocated resource.\r
862 //\r
863Finish:\r
864 if (OrigDevicePathNode != NULL) {\r
865 FreePool (OrigDevicePathNode);\r
866 }\r
867\r
868 DEBUG ((DEBUG_INFO, "DxeTpm2MeasureBootHandler - %r\n", Status));\r
869\r
870 return Status;\r
871}\r
872\r
873/**\r
874 Register the security handler to provide TPM measure boot service.\r
875\r
876 @param ImageHandle ImageHandle of the loaded driver.\r
877 @param SystemTable Pointer to the EFI System Table.\r
878\r
879 @retval EFI_SUCCESS Register successfully.\r
880 @retval EFI_OUT_OF_RESOURCES No enough memory to register this handler.\r
881**/\r
882EFI_STATUS\r
883EFIAPI\r
884DxeTpm2MeasureBootLibConstructor (\r
885 IN EFI_HANDLE ImageHandle,\r
886 IN EFI_SYSTEM_TABLE *SystemTable\r
887 )\r
888{\r
889 EFI_HOB_GUID_TYPE *GuidHob;\r
890\r
891 GuidHob = NULL;\r
892\r
893 GuidHob = GetFirstGuidHob (&gMeasuredFvHobGuid);\r
894\r
895 if (GuidHob != NULL) {\r
896 mTcg2MeasuredHobData = GET_GUID_HOB_DATA (GuidHob);\r
897 }\r
898\r
899 return RegisterSecurity2Handler (\r
900 DxeTpm2MeasureBootHandler,\r
901 EFI_AUTH_OPERATION_MEASURE_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED\r
902 );\r
903}\r