2 The library instance provides security service of TPM2 measure boot and
3 Confidential Computing (CC) measure boot.
5 Caution: This file requires additional review when modified.
6 This library will have external input - PE/COFF image and GPT partition.
7 This external input must be validated carefully to avoid security issue like
8 buffer overflow, integer overflow.
10 DxeTpm2MeasureBootLibImageRead() function will make sure the PE/COFF image content
11 read is within the image buffer.
13 Tcg2MeasurePeImage() function will accept untrusted PE/COFF image and validate its
14 data structure within this image buffer before use.
16 Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse
17 partition data carefully.
19 Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
20 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
21 SPDX-License-Identifier: BSD-2-Clause-Patent
27 #include <Protocol/Tcg2Protocol.h>
28 #include <Protocol/BlockIo.h>
29 #include <Protocol/DiskIo.h>
30 #include <Protocol/DevicePathToText.h>
31 #include <Protocol/FirmwareVolumeBlock.h>
33 #include <Guid/MeasuredFvHob.h>
35 #include <Library/BaseLib.h>
36 #include <Library/DebugLib.h>
37 #include <Library/BaseMemoryLib.h>
38 #include <Library/MemoryAllocationLib.h>
39 #include <Library/DevicePathLib.h>
40 #include <Library/UefiBootServicesTableLib.h>
41 #include <Library/BaseCryptLib.h>
42 #include <Library/PeCoffLib.h>
43 #include <Library/SecurityManagementLib.h>
44 #include <Library/HobLib.h>
45 #include <Protocol/CcMeasurement.h>
48 EFI_TCG2_PROTOCOL
*Tcg2Protocol
;
49 EFI_CC_MEASUREMENT_PROTOCOL
*CcProtocol
;
50 } MEASURE_BOOT_PROTOCOLS
;
53 // Flag to check GPT partition. It only need be measured once.
55 BOOLEAN mTcg2MeasureGptTableFlag
= FALSE
;
56 UINTN mTcg2MeasureGptCount
= 0;
57 VOID
*mTcg2FileBuffer
;
60 // Measured FV handle cache
62 EFI_HANDLE mTcg2CacheMeasuredHandle
= NULL
;
63 MEASURED_HOB_DATA
*mTcg2MeasuredHobData
= NULL
;
66 Reads contents of a PE/COFF image in memory buffer.
68 Caution: This function may receive untrusted input.
69 PE/COFF image is external input, so this function will make sure the PE/COFF image content
70 read is within the image buffer.
72 @param FileHandle Pointer to the file handle to read the PE/COFF image.
73 @param FileOffset Offset into the PE/COFF image to begin the read operation.
74 @param ReadSize On input, the size in bytes of the requested read operation.
75 On output, the number of bytes actually read.
76 @param Buffer Output buffer that contains the data read from the PE/COFF image.
78 @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size
82 DxeTpm2MeasureBootLibImageRead (
85 IN OUT UINTN
*ReadSize
,
91 if ((FileHandle
== NULL
) || (ReadSize
== NULL
) || (Buffer
== NULL
)) {
92 return EFI_INVALID_PARAMETER
;
95 if (MAX_ADDRESS
- FileOffset
< *ReadSize
) {
96 return EFI_INVALID_PARAMETER
;
99 EndPosition
= FileOffset
+ *ReadSize
;
100 if (EndPosition
> mTcg2ImageSize
) {
101 *ReadSize
= (UINT32
)(mTcg2ImageSize
- FileOffset
);
104 if (FileOffset
>= mTcg2ImageSize
) {
108 CopyMem (Buffer
, (UINT8
*)((UINTN
)FileHandle
+ FileOffset
), *ReadSize
);
114 Measure GPT table data into TPM log.
116 Caution: This function may receive untrusted input.
117 The GPT partition table is external input, so this function should parse partition data carefully.
119 @param MeasureBootProtocols Pointer to the located MeasureBoot protocol instances (i.e. TCG2/CC protocol).
120 @param GptHandle Handle that GPT partition was installed.
122 @retval EFI_SUCCESS Successfully measure GPT table.
123 @retval EFI_UNSUPPORTED Not support GPT table on the given handle.
124 @retval EFI_DEVICE_ERROR Can't get GPT table because device error.
125 @retval EFI_OUT_OF_RESOURCES No enough resource to measure GPT table.
126 @retval other error value
130 Tcg2MeasureGptTable (
131 IN MEASURE_BOOT_PROTOCOLS
*MeasureBootProtocols
,
132 IN EFI_HANDLE GptHandle
136 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
137 EFI_DISK_IO_PROTOCOL
*DiskIo
;
138 EFI_PARTITION_TABLE_HEADER
*PrimaryHeader
;
139 EFI_PARTITION_ENTRY
*PartitionEntry
;
141 UINTN NumberOfPartition
;
144 EFI_TCG2_EVENT
*Tcg2Event
;
145 EFI_CC_EVENT
*CcEvent
;
146 EFI_GPT_DATA
*GptData
;
148 EFI_TCG2_PROTOCOL
*Tcg2Protocol
;
149 EFI_CC_MEASUREMENT_PROTOCOL
*CcProtocol
;
150 EFI_CC_MR_INDEX MrIndex
;
152 if (mTcg2MeasureGptCount
> 0) {
156 PrimaryHeader
= NULL
;
160 Tcg2Protocol
= MeasureBootProtocols
->Tcg2Protocol
;
161 CcProtocol
= MeasureBootProtocols
->CcProtocol
;
163 if ((Tcg2Protocol
== NULL
) && (CcProtocol
== NULL
)) {
165 return EFI_UNSUPPORTED
;
168 if (sizeof (EFI_CC_EVENT
) != sizeof (EFI_TCG2_EVENT
)) {
170 return EFI_UNSUPPORTED
;
173 Status
= gBS
->HandleProtocol (GptHandle
, &gEfiBlockIoProtocolGuid
, (VOID
**)&BlockIo
);
174 if (EFI_ERROR (Status
)) {
175 return EFI_UNSUPPORTED
;
178 Status
= gBS
->HandleProtocol (GptHandle
, &gEfiDiskIoProtocolGuid
, (VOID
**)&DiskIo
);
179 if (EFI_ERROR (Status
)) {
180 return EFI_UNSUPPORTED
;
184 // Read the EFI Partition Table Header
186 PrimaryHeader
= (EFI_PARTITION_TABLE_HEADER
*)AllocatePool (BlockIo
->Media
->BlockSize
);
187 if (PrimaryHeader
== NULL
) {
188 return EFI_OUT_OF_RESOURCES
;
191 Status
= DiskIo
->ReadDisk (
193 BlockIo
->Media
->MediaId
,
194 1 * BlockIo
->Media
->BlockSize
,
195 BlockIo
->Media
->BlockSize
,
196 (UINT8
*)PrimaryHeader
198 if (EFI_ERROR (Status
)) {
199 DEBUG ((DEBUG_ERROR
, "Failed to Read Partition Table Header!\n"));
200 FreePool (PrimaryHeader
);
201 return EFI_DEVICE_ERROR
;
205 // PrimaryHeader->SizeOfPartitionEntry should not be zero
207 if (PrimaryHeader
->SizeOfPartitionEntry
== 0) {
208 DEBUG ((DEBUG_ERROR
, "SizeOfPartitionEntry should not be zero!\n"));
209 FreePool (PrimaryHeader
);
210 return EFI_BAD_BUFFER_SIZE
;
214 // Read the partition entry.
216 EntryPtr
= (UINT8
*)AllocatePool (PrimaryHeader
->NumberOfPartitionEntries
* PrimaryHeader
->SizeOfPartitionEntry
);
217 if (EntryPtr
== NULL
) {
218 FreePool (PrimaryHeader
);
219 return EFI_OUT_OF_RESOURCES
;
222 Status
= DiskIo
->ReadDisk (
224 BlockIo
->Media
->MediaId
,
225 MultU64x32 (PrimaryHeader
->PartitionEntryLBA
, BlockIo
->Media
->BlockSize
),
226 PrimaryHeader
->NumberOfPartitionEntries
* PrimaryHeader
->SizeOfPartitionEntry
,
229 if (EFI_ERROR (Status
)) {
230 FreePool (PrimaryHeader
);
232 return EFI_DEVICE_ERROR
;
236 // Count the valid partition
238 PartitionEntry
= (EFI_PARTITION_ENTRY
*)EntryPtr
;
239 NumberOfPartition
= 0;
240 for (Index
= 0; Index
< PrimaryHeader
->NumberOfPartitionEntries
; Index
++) {
241 if (!IsZeroGuid (&PartitionEntry
->PartitionTypeGUID
)) {
245 PartitionEntry
= (EFI_PARTITION_ENTRY
*)((UINT8
*)PartitionEntry
+ PrimaryHeader
->SizeOfPartitionEntry
);
249 // Prepare Data for Measurement (CcProtocol and Tcg2Protocol)
251 EventSize
= (UINT32
)(sizeof (EFI_GPT_DATA
) - sizeof (GptData
->Partitions
)
252 + NumberOfPartition
* PrimaryHeader
->SizeOfPartitionEntry
);
253 EventPtr
= (UINT8
*)AllocateZeroPool (EventSize
+ sizeof (EFI_TCG2_EVENT
) - sizeof (Tcg2Event
->Event
));
254 if (EventPtr
== NULL
) {
255 Status
= EFI_OUT_OF_RESOURCES
;
259 Tcg2Event
= (EFI_TCG2_EVENT
*)EventPtr
;
260 Tcg2Event
->Size
= EventSize
+ sizeof (EFI_TCG2_EVENT
) - sizeof (Tcg2Event
->Event
);
261 Tcg2Event
->Header
.HeaderSize
= sizeof (EFI_TCG2_EVENT_HEADER
);
262 Tcg2Event
->Header
.HeaderVersion
= EFI_TCG2_EVENT_HEADER_VERSION
;
263 Tcg2Event
->Header
.PCRIndex
= 5;
264 Tcg2Event
->Header
.EventType
= EV_EFI_GPT_EVENT
;
265 GptData
= (EFI_GPT_DATA
*)Tcg2Event
->Event
;
268 // Copy the EFI_PARTITION_TABLE_HEADER and NumberOfPartition
270 CopyMem ((UINT8
*)GptData
, (UINT8
*)PrimaryHeader
, sizeof (EFI_PARTITION_TABLE_HEADER
));
271 GptData
->NumberOfPartitions
= NumberOfPartition
;
273 // Copy the valid partition entry
275 PartitionEntry
= (EFI_PARTITION_ENTRY
*)EntryPtr
;
276 NumberOfPartition
= 0;
277 for (Index
= 0; Index
< PrimaryHeader
->NumberOfPartitionEntries
; Index
++) {
278 if (!IsZeroGuid (&PartitionEntry
->PartitionTypeGUID
)) {
280 (UINT8
*)&GptData
->Partitions
+ NumberOfPartition
* PrimaryHeader
->SizeOfPartitionEntry
,
281 (UINT8
*)PartitionEntry
,
282 PrimaryHeader
->SizeOfPartitionEntry
287 PartitionEntry
= (EFI_PARTITION_ENTRY
*)((UINT8
*)PartitionEntry
+ PrimaryHeader
->SizeOfPartitionEntry
);
291 // Only one of TCG2_PROTOCOL or CC_MEASUREMENT_PROTOCOL is exposed.
292 // So Measure the GPT data with one of the protocol.
294 if (CcProtocol
!= NULL
) {
296 // EFI_CC_EVENT share the same data structure with EFI_TCG2_EVENT
297 // except the MrIndex and PCRIndex in Header.
298 // Tcg2Event has been created and initialized before. So only the MrIndex need
301 Status
= CcProtocol
->MapPcrToMrIndex (CcProtocol
, Tcg2Event
->Header
.PCRIndex
, &MrIndex
);
302 if (EFI_ERROR (Status
)) {
303 DEBUG ((DEBUG_ERROR
, "Cannot map PcrIndex(%d) to MrIndex\n", Tcg2Event
->Header
.PCRIndex
));
307 CcEvent
= (EFI_CC_EVENT
*)EventPtr
;
308 CcEvent
->Header
.MrIndex
= MrIndex
;
309 Status
= CcProtocol
->HashLogExtendEvent (
312 (EFI_PHYSICAL_ADDRESS
)(UINTN
)(VOID
*)GptData
,
316 if (!EFI_ERROR (Status
)) {
317 mTcg2MeasureGptCount
++;
320 DEBUG ((DEBUG_INFO
, "DxeTpm2MeasureBootHandler - Cc MeasureGptTable - %r\n", Status
));
321 } else if (Tcg2Protocol
!= NULL
) {
323 // If Tcg2Protocol is installed, then Measure GPT data with this protocol.
325 Status
= Tcg2Protocol
->HashLogExtendEvent (
328 (EFI_PHYSICAL_ADDRESS
)(UINTN
)(VOID
*)GptData
,
332 if (!EFI_ERROR (Status
)) {
333 mTcg2MeasureGptCount
++;
336 DEBUG ((DEBUG_INFO
, "DxeTpm2MeasureBootHandler - Tcg2 MeasureGptTable - %r\n", Status
));
340 if (PrimaryHeader
!= NULL
) {
341 FreePool (PrimaryHeader
);
344 if (EntryPtr
!= NULL
) {
348 if (EventPtr
!= NULL
) {
356 Measure PE image into TPM log based on the authenticode image hashing in
357 PE/COFF Specification 8.0 Appendix A.
359 Caution: This function may receive untrusted input.
360 PE/COFF image is external input, so this function will validate its data structure
361 within this image buffer before use.
363 @param[in] MeasureBootProtocols Pointer to the located MeasureBoot protocol instances.
364 @param[in] ImageAddress Start address of image buffer.
365 @param[in] ImageSize Image size
366 @param[in] LinkTimeBase Address that the image is loaded into memory.
367 @param[in] ImageType Image subsystem type.
368 @param[in] FilePath File path is corresponding to the input image.
370 @retval EFI_SUCCESS Successfully measure image.
371 @retval EFI_OUT_OF_RESOURCES No enough resource to measure image.
372 @retval EFI_UNSUPPORTED ImageType is unsupported or PE image is mal-format.
373 @retval other error value
379 IN MEASURE_BOOT_PROTOCOLS
*MeasureBootProtocols
,
380 IN EFI_PHYSICAL_ADDRESS ImageAddress
,
382 IN UINTN LinkTimeBase
,
384 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
388 EFI_TCG2_EVENT
*Tcg2Event
;
389 EFI_IMAGE_LOAD_EVENT
*ImageLoad
;
392 EFI_CC_EVENT
*CcEvent
;
393 EFI_CC_MEASUREMENT_PROTOCOL
*CcProtocol
;
394 EFI_TCG2_PROTOCOL
*Tcg2Protocol
;
396 EFI_CC_MR_INDEX MrIndex
;
398 Status
= EFI_UNSUPPORTED
;
402 Tcg2Protocol
= MeasureBootProtocols
->Tcg2Protocol
;
403 CcProtocol
= MeasureBootProtocols
->CcProtocol
;
405 if ((Tcg2Protocol
== NULL
) && (CcProtocol
== NULL
)) {
407 return EFI_UNSUPPORTED
;
410 if (sizeof (EFI_CC_EVENT
) != sizeof (EFI_TCG2_EVENT
)) {
412 return EFI_UNSUPPORTED
;
415 FilePathSize
= (UINT32
)GetDevicePathSize (FilePath
);
418 // Determine destination PCR by BootPolicy
420 EventSize
= sizeof (*ImageLoad
) - sizeof (ImageLoad
->DevicePath
) + FilePathSize
;
421 EventPtr
= AllocateZeroPool (EventSize
+ sizeof (EFI_TCG2_EVENT
) - sizeof (Tcg2Event
->Event
));
422 if (EventPtr
== NULL
) {
423 return EFI_OUT_OF_RESOURCES
;
426 Tcg2Event
= (EFI_TCG2_EVENT
*)EventPtr
;
427 Tcg2Event
->Size
= EventSize
+ sizeof (EFI_TCG2_EVENT
) - sizeof (Tcg2Event
->Event
);
428 Tcg2Event
->Header
.HeaderSize
= sizeof (EFI_TCG2_EVENT_HEADER
);
429 Tcg2Event
->Header
.HeaderVersion
= EFI_TCG2_EVENT_HEADER_VERSION
;
430 ImageLoad
= (EFI_IMAGE_LOAD_EVENT
*)Tcg2Event
->Event
;
433 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
:
434 Tcg2Event
->Header
.EventType
= EV_EFI_BOOT_SERVICES_APPLICATION
;
435 Tcg2Event
->Header
.PCRIndex
= 4;
437 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
:
438 Tcg2Event
->Header
.EventType
= EV_EFI_BOOT_SERVICES_DRIVER
;
439 Tcg2Event
->Header
.PCRIndex
= 2;
441 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
:
442 Tcg2Event
->Header
.EventType
= EV_EFI_RUNTIME_SERVICES_DRIVER
;
443 Tcg2Event
->Header
.PCRIndex
= 2;
448 "Tcg2MeasurePeImage: Unknown subsystem type %d",
454 ImageLoad
->ImageLocationInMemory
= ImageAddress
;
455 ImageLoad
->ImageLengthInMemory
= ImageSize
;
456 ImageLoad
->ImageLinkTimeAddress
= LinkTimeBase
;
457 ImageLoad
->LengthOfDevicePath
= FilePathSize
;
458 if ((FilePath
!= NULL
) && (FilePathSize
!= 0)) {
459 CopyMem (ImageLoad
->DevicePath
, FilePath
, FilePathSize
);
465 if (CcProtocol
!= NULL
) {
466 Status
= CcProtocol
->MapPcrToMrIndex (CcProtocol
, Tcg2Event
->Header
.PCRIndex
, &MrIndex
);
467 if (EFI_ERROR (Status
)) {
468 DEBUG ((DEBUG_ERROR
, "Cannot map PcrIndex(%d) to MrIndex\n", Tcg2Event
->Header
.PCRIndex
));
472 CcEvent
= (EFI_CC_EVENT
*)EventPtr
;
473 CcEvent
->Header
.MrIndex
= MrIndex
;
475 Status
= CcProtocol
->HashLogExtendEvent (
482 DEBUG ((DEBUG_INFO
, "DxeTpm2MeasureBootHandler - Cc MeasurePeImage - %r\n", Status
));
483 } else if (Tcg2Protocol
!= NULL
) {
484 Status
= Tcg2Protocol
->HashLogExtendEvent (
491 DEBUG ((DEBUG_INFO
, "DxeTpm2MeasureBootHandler - Tcg2 MeasurePeImage - %r\n", Status
));
494 if (Status
== EFI_VOLUME_FULL
) {
496 // Volume full here means the image is hashed and its result is extended to PCR.
497 // But the event log can't be saved since log area is full.
498 // Just return EFI_SUCCESS in order not to block the image load.
500 Status
= EFI_SUCCESS
;
504 if (EventPtr
!= NULL
) {
512 Get the measure boot protocols.
514 There are 2 measure boot, TCG2 protocol based and Cc measurement protocol based.
516 @param MeasureBootProtocols Pointer to the located measure boot protocol instances.
518 @retval EFI_SUCCESS Sucessfully locate the measure boot protocol instances (at least one instance).
519 @retval EFI_UNSUPPORTED Measure boot is not supported.
523 GetMeasureBootProtocols (
524 MEASURE_BOOT_PROTOCOLS
*MeasureBootProtocols
528 EFI_TCG2_PROTOCOL
*Tcg2Protocol
;
529 EFI_CC_MEASUREMENT_PROTOCOL
*CcProtocol
;
530 EFI_TCG2_BOOT_SERVICE_CAPABILITY Tcg2ProtocolCapability
;
531 EFI_CC_BOOT_SERVICE_CAPABILITY CcProtocolCapability
;
534 Status
= gBS
->LocateProtocol (&gEfiCcMeasurementProtocolGuid
, NULL
, (VOID
**)&CcProtocol
);
535 if (EFI_ERROR (Status
)) {
537 // Cc Measurement protocol is not installed.
539 DEBUG ((DEBUG_VERBOSE
, "CcMeasurementProtocol is not installed. - %r\n", Status
));
541 ZeroMem (&CcProtocolCapability
, sizeof (CcProtocolCapability
));
542 CcProtocolCapability
.Size
= sizeof (CcProtocolCapability
);
543 Status
= CcProtocol
->GetCapability (CcProtocol
, &CcProtocolCapability
);
544 if (EFI_ERROR (Status
) || (CcProtocolCapability
.CcType
.Type
== EFI_CC_TYPE_NONE
)) {
545 DEBUG ((DEBUG_ERROR
, " CcProtocol->GetCapability returns : %x, %r\n", CcProtocolCapability
.CcType
.Type
, Status
));
551 Status
= gBS
->LocateProtocol (&gEfiTcg2ProtocolGuid
, NULL
, (VOID
**)&Tcg2Protocol
);
552 if (EFI_ERROR (Status
)) {
554 // Tcg2 protocol is not installed. So, TPM2 is not present.
556 DEBUG ((DEBUG_VERBOSE
, "Tcg2Protocol is not installed. - %r\n", Status
));
558 Tcg2ProtocolCapability
.Size
= (UINT8
)sizeof (Tcg2ProtocolCapability
);
559 Status
= Tcg2Protocol
->GetCapability (Tcg2Protocol
, &Tcg2ProtocolCapability
);
560 if (EFI_ERROR (Status
) || (!Tcg2ProtocolCapability
.TPMPresentFlag
)) {
562 // TPM device doesn't work or activate.
564 DEBUG ((DEBUG_ERROR
, "TPMPresentFlag=FALSE %r\n", Status
));
569 MeasureBootProtocols
->Tcg2Protocol
= Tcg2Protocol
;
570 MeasureBootProtocols
->CcProtocol
= CcProtocol
;
572 return (Tcg2Protocol
== NULL
&& CcProtocol
== NULL
) ? EFI_UNSUPPORTED
: EFI_SUCCESS
;
576 The security handler is used to abstract platform-specific policy
577 from the DXE core response to an attempt to use a file that returns a
578 given status for the authentication check from the section extraction protocol.
580 The possible responses in a given SAP implementation may include locking
581 flash upon failure to authenticate, attestation logging for all signed drivers,
582 and other exception operations. The File parameter allows for possible logging
583 within the SAP of the driver.
585 If the file specified by File with an authentication status specified by
586 AuthenticationStatus is safe for the DXE Core to use, then EFI_SUCCESS is returned.
588 If the file specified by File with an authentication status specified by
589 AuthenticationStatus is not safe for the DXE Core to use under any circumstances,
590 then EFI_ACCESS_DENIED is returned.
592 If the file specified by File with an authentication status specified by
593 AuthenticationStatus is not safe for the DXE Core to use right now, but it
594 might be possible to use it at a future time, then EFI_SECURITY_VIOLATION is
597 If check image specified by FileBuffer and File is NULL meanwhile, return EFI_ACCESS_DENIED.
599 @param[in] AuthenticationStatus This is the authentication status returned
600 from the securitymeasurement services for the
602 @param[in] File This is a pointer to the device path of the file that is
603 being dispatched. This will optionally be used for logging.
604 @param[in] FileBuffer File buffer matches the input file device path.
605 @param[in] FileSize Size of File buffer matches the input file device path.
606 @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.
608 @retval EFI_SUCCESS The file specified by DevicePath and non-NULL
609 FileBuffer did authenticate, and the platform policy dictates
610 that the DXE Foundation may use the file.
611 @retval other error value
615 DxeTpm2MeasureBootHandler (
616 IN UINT32 AuthenticationStatus
,
617 IN CONST EFI_DEVICE_PATH_PROTOCOL
*File OPTIONAL
,
620 IN BOOLEAN BootPolicy
623 MEASURE_BOOT_PROTOCOLS MeasureBootProtocols
;
625 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
626 EFI_DEVICE_PATH_PROTOCOL
*OrigDevicePathNode
;
628 EFI_HANDLE TempHandle
;
629 BOOLEAN ApplicationRequired
;
630 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
631 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*FvbProtocol
;
632 EFI_PHYSICAL_ADDRESS FvAddress
;
635 MeasureBootProtocols
.Tcg2Protocol
= NULL
;
636 MeasureBootProtocols
.CcProtocol
= NULL
;
638 Status
= GetMeasureBootProtocols (&MeasureBootProtocols
);
640 if (EFI_ERROR (Status
)) {
642 // None of Measured boot protocols (Tcg2, Cc) is installed.
643 // Don't do any measurement, and directly return EFI_SUCCESS.
645 DEBUG ((DEBUG_INFO
, "None of Tcg2Protocol/CcMeasurementProtocol is installed.\n"));
651 "Tcg2Protocol = %p, CcMeasurementProtocol = %p\n",
652 MeasureBootProtocols
.Tcg2Protocol
,
653 MeasureBootProtocols
.CcProtocol
657 // Copy File Device Path
659 OrigDevicePathNode
= DuplicateDevicePath (File
);
662 // 1. Check whether this device path support BlockIo protocol.
663 // Is so, this device path may be a GPT device path.
665 DevicePathNode
= OrigDevicePathNode
;
666 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &DevicePathNode
, &Handle
);
667 if (!EFI_ERROR (Status
) && !mTcg2MeasureGptTableFlag
) {
669 // Find the gpt partition on the given devicepath
671 DevicePathNode
= OrigDevicePathNode
;
672 ASSERT (DevicePathNode
!= NULL
);
673 while (!IsDevicePathEnd (DevicePathNode
)) {
675 // Find the Gpt partition
677 if ((DevicePathType (DevicePathNode
) == MEDIA_DEVICE_PATH
) &&
678 (DevicePathSubType (DevicePathNode
) == MEDIA_HARDDRIVE_DP
))
681 // Check whether it is a gpt partition or not
683 if ((((HARDDRIVE_DEVICE_PATH
*)DevicePathNode
)->MBRType
== MBR_TYPE_EFI_PARTITION_TABLE_HEADER
) &&
684 (((HARDDRIVE_DEVICE_PATH
*)DevicePathNode
)->SignatureType
== SIGNATURE_TYPE_GUID
))
687 // Change the partition device path to its parent device path (disk) and get the handle.
689 DevicePathNode
->Type
= END_DEVICE_PATH_TYPE
;
690 DevicePathNode
->SubType
= END_ENTIRE_DEVICE_PATH_SUBTYPE
;
691 DevicePathNode
= OrigDevicePathNode
;
692 Status
= gBS
->LocateDevicePath (
693 &gEfiDiskIoProtocolGuid
,
697 if (!EFI_ERROR (Status
)) {
701 Status
= Tcg2MeasureGptTable (&MeasureBootProtocols
, Handle
);
703 if (!EFI_ERROR (Status
)) {
705 // GPT disk check done.
707 mTcg2MeasureGptTableFlag
= TRUE
;
711 FreePool (OrigDevicePathNode
);
712 OrigDevicePathNode
= DuplicateDevicePath (File
);
713 ASSERT (OrigDevicePathNode
!= NULL
);
718 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
723 // 2. Measure PE image.
725 ApplicationRequired
= FALSE
;
728 // Check whether this device path support FVB protocol.
730 DevicePathNode
= OrigDevicePathNode
;
731 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid
, &DevicePathNode
, &Handle
);
732 if (!EFI_ERROR (Status
)) {
734 // Don't check FV image, and directly return EFI_SUCCESS.
735 // It can be extended to the specific FV authentication according to the different requirement.
737 if (IsDevicePathEnd (DevicePathNode
)) {
742 // The PE image from unmeasured Firmware volume need be measured
743 // The PE image from measured Firmware volume will be measured according to policy below.
744 // If it is driver, do not measure
745 // If it is application, still measure.
747 ApplicationRequired
= TRUE
;
749 if ((mTcg2CacheMeasuredHandle
!= Handle
) && (mTcg2MeasuredHobData
!= NULL
)) {
751 // Search for Root FV of this PE image
755 Status
= gBS
->HandleProtocol (
757 &gEfiFirmwareVolumeBlockProtocolGuid
,
758 (VOID
**)&FvbProtocol
760 TempHandle
= FvbProtocol
->ParentHandle
;
761 } while (!EFI_ERROR (Status
) && FvbProtocol
->ParentHandle
!= NULL
);
764 // Search in measured FV Hob
766 Status
= FvbProtocol
->GetPhysicalAddress (FvbProtocol
, &FvAddress
);
767 if (EFI_ERROR (Status
)) {
771 ApplicationRequired
= FALSE
;
773 for (Index
= 0; Index
< mTcg2MeasuredHobData
->Num
; Index
++) {
774 if (mTcg2MeasuredHobData
->MeasuredFvBuf
[Index
].BlobBase
== FvAddress
) {
776 // Cache measured FV for next measurement
778 mTcg2CacheMeasuredHandle
= Handle
;
779 ApplicationRequired
= TRUE
;
787 // File is not found.
789 if (FileBuffer
== NULL
) {
790 Status
= EFI_SECURITY_VIOLATION
;
794 mTcg2ImageSize
= FileSize
;
795 mTcg2FileBuffer
= FileBuffer
;
800 DevicePathNode
= OrigDevicePathNode
;
801 ZeroMem (&ImageContext
, sizeof (ImageContext
));
802 ImageContext
.Handle
= (VOID
*)FileBuffer
;
803 ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
)DxeTpm2MeasureBootLibImageRead
;
806 // Get information about the image being loaded
808 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
809 if (EFI_ERROR (Status
)) {
811 // Check for invalid parameters.
814 Status
= EFI_ACCESS_DENIED
;
818 // The information can't be got from the invalid PeImage
824 // Measure only application if Application flag is set
825 // Measure drivers and applications if Application flag is not set
827 if ((!ApplicationRequired
) ||
828 (ApplicationRequired
&& (ImageContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
)))
831 // Print the image path to be measured.
835 ToText
= ConvertDevicePathToText (
840 if (ToText
!= NULL
) {
841 DEBUG ((DEBUG_INFO
, "The measured image path is %s.\n", ToText
));
848 // Measure PE image into TPM log.
850 Status
= Tcg2MeasurePeImage (
851 &MeasureBootProtocols
,
852 (EFI_PHYSICAL_ADDRESS
)(UINTN
)FileBuffer
,
854 (UINTN
)ImageContext
.ImageAddress
,
855 ImageContext
.ImageType
,
861 // Done, free the allocated resource.
864 if (OrigDevicePathNode
!= NULL
) {
865 FreePool (OrigDevicePathNode
);
868 DEBUG ((DEBUG_INFO
, "DxeTpm2MeasureBootHandler - %r\n", Status
));
874 Register the security handler to provide TPM measure boot service.
876 @param ImageHandle ImageHandle of the loaded driver.
877 @param SystemTable Pointer to the EFI System Table.
879 @retval EFI_SUCCESS Register successfully.
880 @retval EFI_OUT_OF_RESOURCES No enough memory to register this handler.
884 DxeTpm2MeasureBootLibConstructor (
885 IN EFI_HANDLE ImageHandle
,
886 IN EFI_SYSTEM_TABLE
*SystemTable
889 EFI_HOB_GUID_TYPE
*GuidHob
;
893 GuidHob
= GetFirstGuidHob (&gMeasuredFvHobGuid
);
895 if (GuidHob
!= NULL
) {
896 mTcg2MeasuredHobData
= GET_GUID_HOB_DATA (GuidHob
);
899 return RegisterSecurity2Handler (
900 DxeTpm2MeasureBootHandler
,
901 EFI_AUTH_OPERATION_MEASURE_IMAGE
| EFI_AUTH_OPERATION_IMAGE_REQUIRED