2 The library instance provides security service of TPM measure boot.
4 Caution: This file requires additional review when modified.
5 This library will have external input - PE/COFF image and GPT partition.
6 This external input must be validated carefully to avoid security issue like
7 buffer overflow, integer overflow.
9 DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content
10 read is within the image buffer.
12 TcgMeasurePeImage() function will accept untrusted PE/COFF image and validate its
13 data structure within this image buffer before use.
15 TcgMeasureGptTable() function will receive untrusted GPT partition table, and parse
16 partition data carefully.
18 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
19 SPDX-License-Identifier: BSD-2-Clause-Patent
25 #include <Protocol/TcgService.h>
26 #include <Protocol/BlockIo.h>
27 #include <Protocol/DiskIo.h>
28 #include <Protocol/FirmwareVolumeBlock.h>
30 #include <Guid/MeasuredFvHob.h>
32 #include <Library/BaseLib.h>
33 #include <Library/DebugLib.h>
34 #include <Library/BaseMemoryLib.h>
35 #include <Library/MemoryAllocationLib.h>
36 #include <Library/DevicePathLib.h>
37 #include <Library/UefiBootServicesTableLib.h>
38 #include <Library/BaseCryptLib.h>
39 #include <Library/PeCoffLib.h>
40 #include <Library/SecurityManagementLib.h>
41 #include <Library/HobLib.h>
44 // Flag to check GPT partition. It only need be measured once.
46 BOOLEAN mMeasureGptTableFlag
= FALSE
;
47 UINTN mMeasureGptCount
= 0;
51 // Measured FV handle cache
53 EFI_HANDLE mCacheMeasuredHandle
= NULL
;
54 MEASURED_HOB_DATA
*mMeasuredHobData
= NULL
;
57 Reads contents of a PE/COFF image in memory buffer.
59 Caution: This function may receive untrusted input.
60 PE/COFF image is external input, so this function will make sure the PE/COFF image content
61 read is within the image buffer.
63 @param FileHandle Pointer to the file handle to read the PE/COFF image.
64 @param FileOffset Offset into the PE/COFF image to begin the read operation.
65 @param ReadSize On input, the size in bytes of the requested read operation.
66 On output, the number of bytes actually read.
67 @param Buffer Output buffer that contains the data read from the PE/COFF image.
69 @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size
73 DxeTpmMeasureBootLibImageRead (
76 IN OUT UINTN
*ReadSize
,
82 if ((FileHandle
== NULL
) || (ReadSize
== NULL
) || (Buffer
== NULL
)) {
83 return EFI_INVALID_PARAMETER
;
86 if (MAX_ADDRESS
- FileOffset
< *ReadSize
) {
87 return EFI_INVALID_PARAMETER
;
90 EndPosition
= FileOffset
+ *ReadSize
;
91 if (EndPosition
> mTpmImageSize
) {
92 *ReadSize
= (UINT32
)(mTpmImageSize
- FileOffset
);
95 if (FileOffset
>= mTpmImageSize
) {
99 CopyMem (Buffer
, (UINT8
*)((UINTN
)FileHandle
+ FileOffset
), *ReadSize
);
105 Measure GPT table data into TPM log.
107 Caution: This function may receive untrusted input.
108 The GPT partition table is external input, so this function should parse partition data carefully.
110 @param TcgProtocol Pointer to the located TCG protocol instance.
111 @param GptHandle Handle that GPT partition was installed.
113 @retval EFI_SUCCESS Successfully measure GPT table.
114 @retval EFI_UNSUPPORTED Not support GPT table on the given handle.
115 @retval EFI_DEVICE_ERROR Can't get GPT table because device error.
116 @retval EFI_OUT_OF_RESOURCES No enough resource to measure GPT table.
117 @retval other error value
122 IN EFI_TCG_PROTOCOL
*TcgProtocol
,
123 IN EFI_HANDLE GptHandle
127 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
128 EFI_DISK_IO_PROTOCOL
*DiskIo
;
129 EFI_PARTITION_TABLE_HEADER
*PrimaryHeader
;
130 EFI_PARTITION_ENTRY
*PartitionEntry
;
132 UINTN NumberOfPartition
;
134 TCG_PCR_EVENT
*TcgEvent
;
135 EFI_GPT_DATA
*GptData
;
138 EFI_PHYSICAL_ADDRESS EventLogLastEntry
;
140 if (mMeasureGptCount
> 0) {
144 Status
= gBS
->HandleProtocol (GptHandle
, &gEfiBlockIoProtocolGuid
, (VOID
**)&BlockIo
);
145 if (EFI_ERROR (Status
)) {
146 return EFI_UNSUPPORTED
;
149 Status
= gBS
->HandleProtocol (GptHandle
, &gEfiDiskIoProtocolGuid
, (VOID
**)&DiskIo
);
150 if (EFI_ERROR (Status
)) {
151 return EFI_UNSUPPORTED
;
155 // Read the EFI Partition Table Header
157 PrimaryHeader
= (EFI_PARTITION_TABLE_HEADER
*)AllocatePool (BlockIo
->Media
->BlockSize
);
158 if (PrimaryHeader
== NULL
) {
159 return EFI_OUT_OF_RESOURCES
;
162 Status
= DiskIo
->ReadDisk (
164 BlockIo
->Media
->MediaId
,
165 1 * BlockIo
->Media
->BlockSize
,
166 BlockIo
->Media
->BlockSize
,
167 (UINT8
*)PrimaryHeader
169 if (EFI_ERROR (Status
)) {
170 DEBUG ((DEBUG_ERROR
, "Failed to Read Partition Table Header!\n"));
171 FreePool (PrimaryHeader
);
172 return EFI_DEVICE_ERROR
;
176 // Read the partition entry.
178 EntryPtr
= (UINT8
*)AllocatePool (PrimaryHeader
->NumberOfPartitionEntries
* PrimaryHeader
->SizeOfPartitionEntry
);
179 if (EntryPtr
== NULL
) {
180 FreePool (PrimaryHeader
);
181 return EFI_OUT_OF_RESOURCES
;
184 Status
= DiskIo
->ReadDisk (
186 BlockIo
->Media
->MediaId
,
187 MultU64x32 (PrimaryHeader
->PartitionEntryLBA
, BlockIo
->Media
->BlockSize
),
188 PrimaryHeader
->NumberOfPartitionEntries
* PrimaryHeader
->SizeOfPartitionEntry
,
191 if (EFI_ERROR (Status
)) {
192 FreePool (PrimaryHeader
);
194 return EFI_DEVICE_ERROR
;
198 // Count the valid partition
200 PartitionEntry
= (EFI_PARTITION_ENTRY
*)EntryPtr
;
201 NumberOfPartition
= 0;
202 for (Index
= 0; Index
< PrimaryHeader
->NumberOfPartitionEntries
; Index
++) {
203 if (!IsZeroGuid (&PartitionEntry
->PartitionTypeGUID
)) {
207 PartitionEntry
= (EFI_PARTITION_ENTRY
*)((UINT8
*)PartitionEntry
+ PrimaryHeader
->SizeOfPartitionEntry
);
211 // Prepare Data for Measurement
213 EventSize
= (UINT32
)(sizeof (EFI_GPT_DATA
) - sizeof (GptData
->Partitions
)
214 + NumberOfPartition
* PrimaryHeader
->SizeOfPartitionEntry
);
215 TcgEvent
= (TCG_PCR_EVENT
*)AllocateZeroPool (EventSize
+ sizeof (TCG_PCR_EVENT_HDR
));
216 if (TcgEvent
== NULL
) {
217 FreePool (PrimaryHeader
);
219 return EFI_OUT_OF_RESOURCES
;
222 TcgEvent
->PCRIndex
= 5;
223 TcgEvent
->EventType
= EV_EFI_GPT_EVENT
;
224 TcgEvent
->EventSize
= EventSize
;
225 GptData
= (EFI_GPT_DATA
*)TcgEvent
->Event
;
228 // Copy the EFI_PARTITION_TABLE_HEADER and NumberOfPartition
230 CopyMem ((UINT8
*)GptData
, (UINT8
*)PrimaryHeader
, sizeof (EFI_PARTITION_TABLE_HEADER
));
231 GptData
->NumberOfPartitions
= NumberOfPartition
;
233 // Copy the valid partition entry
235 PartitionEntry
= (EFI_PARTITION_ENTRY
*)EntryPtr
;
236 NumberOfPartition
= 0;
237 for (Index
= 0; Index
< PrimaryHeader
->NumberOfPartitionEntries
; Index
++) {
238 if (!IsZeroGuid (&PartitionEntry
->PartitionTypeGUID
)) {
240 (UINT8
*)&GptData
->Partitions
+ NumberOfPartition
* PrimaryHeader
->SizeOfPartitionEntry
,
241 (UINT8
*)PartitionEntry
,
242 PrimaryHeader
->SizeOfPartitionEntry
247 PartitionEntry
= (EFI_PARTITION_ENTRY
*)((UINT8
*)PartitionEntry
+ PrimaryHeader
->SizeOfPartitionEntry
);
251 // Measure the GPT data
254 Status
= TcgProtocol
->HashLogExtendEvent (
256 (EFI_PHYSICAL_ADDRESS
)(UINTN
)(VOID
*)GptData
,
257 (UINT64
)TcgEvent
->EventSize
,
263 if (!EFI_ERROR (Status
)) {
267 FreePool (PrimaryHeader
);
275 Measure PE image into TPM log based on the authenticode image hashing in
276 PE/COFF Specification 8.0 Appendix A.
278 Caution: This function may receive untrusted input.
279 PE/COFF image is external input, so this function will validate its data structure
280 within this image buffer before use.
282 Notes: PE/COFF image has been checked by BasePeCoffLib PeCoffLoaderGetImageInfo() in
283 its caller function DxeTpmMeasureBootHandler().
285 @param[in] TcgProtocol Pointer to the located TCG protocol instance.
286 @param[in] ImageAddress Start address of image buffer.
287 @param[in] ImageSize Image size
288 @param[in] LinkTimeBase Address that the image is loaded into memory.
289 @param[in] ImageType Image subsystem type.
290 @param[in] FilePath File path is corresponding to the input image.
292 @retval EFI_SUCCESS Successfully measure image.
293 @retval EFI_OUT_OF_RESOURCES No enough resource to measure image.
294 @retval EFI_UNSUPPORTED ImageType is unsupported or PE image is mal-format.
295 @retval other error value
301 IN EFI_TCG_PROTOCOL
*TcgProtocol
,
302 IN EFI_PHYSICAL_ADDRESS ImageAddress
,
304 IN UINTN LinkTimeBase
,
306 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
310 TCG_PCR_EVENT
*TcgEvent
;
311 EFI_IMAGE_LOAD_EVENT
*ImageLoad
;
315 EFI_IMAGE_DOS_HEADER
*DosHdr
;
316 UINT32 PeCoffHeaderOffset
;
317 EFI_IMAGE_SECTION_HEADER
*Section
;
320 UINTN SumOfBytesHashed
;
321 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
326 EFI_PHYSICAL_ADDRESS EventLogLastEntry
;
327 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
328 UINT32 NumberOfRvaAndSizes
;
332 Status
= EFI_UNSUPPORTED
;
334 SectionHeader
= NULL
;
336 FilePathSize
= (UINT32
)GetDevicePathSize (FilePath
);
339 // Determine destination PCR by BootPolicy
341 EventSize
= sizeof (*ImageLoad
) - sizeof (ImageLoad
->DevicePath
) + FilePathSize
;
342 TcgEvent
= AllocateZeroPool (EventSize
+ sizeof (TCG_PCR_EVENT
));
343 if (TcgEvent
== NULL
) {
344 return EFI_OUT_OF_RESOURCES
;
347 TcgEvent
->EventSize
= EventSize
;
348 ImageLoad
= (EFI_IMAGE_LOAD_EVENT
*)TcgEvent
->Event
;
351 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
:
352 TcgEvent
->EventType
= EV_EFI_BOOT_SERVICES_APPLICATION
;
353 TcgEvent
->PCRIndex
= 4;
355 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
:
356 TcgEvent
->EventType
= EV_EFI_BOOT_SERVICES_DRIVER
;
357 TcgEvent
->PCRIndex
= 2;
359 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
:
360 TcgEvent
->EventType
= EV_EFI_RUNTIME_SERVICES_DRIVER
;
361 TcgEvent
->PCRIndex
= 2;
366 "TcgMeasurePeImage: Unknown subsystem type %d",
372 ImageLoad
->ImageLocationInMemory
= ImageAddress
;
373 ImageLoad
->ImageLengthInMemory
= ImageSize
;
374 ImageLoad
->ImageLinkTimeAddress
= LinkTimeBase
;
375 ImageLoad
->LengthOfDevicePath
= FilePathSize
;
376 if ((FilePath
!= NULL
) && (FilePathSize
!= 0)) {
377 CopyMem (ImageLoad
->DevicePath
, FilePath
, FilePathSize
);
381 // Check PE/COFF image
383 DosHdr
= (EFI_IMAGE_DOS_HEADER
*)(UINTN
)ImageAddress
;
384 PeCoffHeaderOffset
= 0;
385 if (DosHdr
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
386 PeCoffHeaderOffset
= DosHdr
->e_lfanew
;
389 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINT8
*)(UINTN
)ImageAddress
+ PeCoffHeaderOffset
);
390 if (Hdr
.Pe32
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
395 // PE/COFF Image Measurement
397 // NOTE: The following codes/steps are based upon the authenticode image hashing in
398 // PE/COFF Specification 8.0 Appendix A.
402 // 1. Load the image header into memory.
404 // 2. Initialize a SHA hash context.
405 CtxSize
= Sha1GetContextSize ();
406 Sha1Ctx
= AllocatePool (CtxSize
);
407 if (Sha1Ctx
== NULL
) {
408 Status
= EFI_OUT_OF_RESOURCES
;
412 HashStatus
= Sha1Init (Sha1Ctx
);
418 // Measuring PE/COFF Image Header;
419 // But CheckSum field and SECURITY data directory (certificate) are excluded
423 // 3. Calculate the distance from the base of the image header to the image checksum address.
424 // 4. Hash the image header from its base to beginning of the image checksum.
426 HashBase
= (UINT8
*)(UINTN
)ImageAddress
;
427 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
431 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
432 HashSize
= (UINTN
)(&Hdr
.Pe32
->OptionalHeader
.CheckSum
) - (UINTN
)HashBase
;
437 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
438 HashSize
= (UINTN
)(&Hdr
.Pe32Plus
->OptionalHeader
.CheckSum
) - (UINTN
)HashBase
;
441 HashStatus
= Sha1Update (Sha1Ctx
, HashBase
, HashSize
);
447 // 5. Skip over the image checksum (it occupies a single ULONG).
449 if (NumberOfRvaAndSizes
<= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
) {
451 // 6. Since there is no Cert Directory in optional header, hash everything
452 // from the end of the checksum to the end of image header.
454 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
458 HashBase
= (UINT8
*)&Hdr
.Pe32
->OptionalHeader
.CheckSum
+ sizeof (UINT32
);
459 HashSize
= Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
- (UINTN
)(HashBase
- ImageAddress
);
464 HashBase
= (UINT8
*)&Hdr
.Pe32Plus
->OptionalHeader
.CheckSum
+ sizeof (UINT32
);
465 HashSize
= Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
- (UINTN
)(HashBase
- ImageAddress
);
469 HashStatus
= Sha1Update (Sha1Ctx
, HashBase
, HashSize
);
476 // 7. Hash everything from the end of the checksum to the start of the Cert Directory.
478 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
482 HashBase
= (UINT8
*)&Hdr
.Pe32
->OptionalHeader
.CheckSum
+ sizeof (UINT32
);
483 HashSize
= (UINTN
)(&Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
]) - (UINTN
)HashBase
;
488 HashBase
= (UINT8
*)&Hdr
.Pe32Plus
->OptionalHeader
.CheckSum
+ sizeof (UINT32
);
489 HashSize
= (UINTN
)(&Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
]) - (UINTN
)HashBase
;
493 HashStatus
= Sha1Update (Sha1Ctx
, HashBase
, HashSize
);
500 // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)
501 // 9. Hash everything from the end of the Cert Directory to the end of image header.
503 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
507 HashBase
= (UINT8
*)&Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
+ 1];
508 HashSize
= Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
- (UINTN
)(HashBase
- ImageAddress
);
513 HashBase
= (UINT8
*)&Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
+ 1];
514 HashSize
= Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
- (UINTN
)(HashBase
- ImageAddress
);
518 HashStatus
= Sha1Update (Sha1Ctx
, HashBase
, HashSize
);
526 // 10. Set the SUM_OF_BYTES_HASHED to the size of the header
528 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
532 SumOfBytesHashed
= Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
;
537 SumOfBytesHashed
= Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
;
541 // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER
542 // structures in the image. The 'NumberOfSections' field of the image
543 // header indicates how big the table should be. Do not include any
544 // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.
546 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*)AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER
) * Hdr
.Pe32
->FileHeader
.NumberOfSections
);
547 if (SectionHeader
== NULL
) {
548 Status
= EFI_OUT_OF_RESOURCES
;
553 // 12. Using the 'PointerToRawData' in the referenced section headers as
554 // a key, arrange the elements in the table in ascending order. In other
555 // words, sort the section headers according to the disk-file offset of
558 Section
= (EFI_IMAGE_SECTION_HEADER
*)(
559 (UINT8
*)(UINTN
)ImageAddress
+
562 sizeof (EFI_IMAGE_FILE_HEADER
) +
563 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
565 for (Index
= 0; Index
< Hdr
.Pe32
->FileHeader
.NumberOfSections
; Index
++) {
567 while ((Pos
> 0) && (Section
->PointerToRawData
< SectionHeader
[Pos
- 1].PointerToRawData
)) {
568 CopyMem (&SectionHeader
[Pos
], &SectionHeader
[Pos
- 1], sizeof (EFI_IMAGE_SECTION_HEADER
));
572 CopyMem (&SectionHeader
[Pos
], Section
, sizeof (EFI_IMAGE_SECTION_HEADER
));
577 // 13. Walk through the sorted table, bring the corresponding section
578 // into memory, and hash the entire section (using the 'SizeOfRawData'
579 // field in the section header to determine the amount of data to hash).
580 // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .
581 // 15. Repeat steps 13 and 14 for all the sections in the sorted table.
583 for (Index
= 0; Index
< Hdr
.Pe32
->FileHeader
.NumberOfSections
; Index
++) {
584 Section
= (EFI_IMAGE_SECTION_HEADER
*)&SectionHeader
[Index
];
585 if (Section
->SizeOfRawData
== 0) {
589 HashBase
= (UINT8
*)(UINTN
)ImageAddress
+ Section
->PointerToRawData
;
590 HashSize
= (UINTN
)Section
->SizeOfRawData
;
592 HashStatus
= Sha1Update (Sha1Ctx
, HashBase
, HashSize
);
597 SumOfBytesHashed
+= HashSize
;
601 // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra
602 // data in the file that needs to be added to the hash. This data begins
603 // at file offset SUM_OF_BYTES_HASHED and its length is:
604 // FileSize - (CertDirectory->Size)
606 if (ImageSize
> SumOfBytesHashed
) {
607 HashBase
= (UINT8
*)(UINTN
)ImageAddress
+ SumOfBytesHashed
;
609 if (NumberOfRvaAndSizes
<= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
) {
612 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
616 CertSize
= Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
;
621 CertSize
= Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
;
625 if (ImageSize
> CertSize
+ SumOfBytesHashed
) {
626 HashSize
= (UINTN
)(ImageSize
- CertSize
- SumOfBytesHashed
);
628 HashStatus
= Sha1Update (Sha1Ctx
, HashBase
, HashSize
);
632 } else if (ImageSize
< CertSize
+ SumOfBytesHashed
) {
638 // 17. Finalize the SHA hash.
640 HashStatus
= Sha1Final (Sha1Ctx
, (UINT8
*)&TcgEvent
->Digest
);
649 Status
= TcgProtocol
->HashLogExtendEvent (
651 (EFI_PHYSICAL_ADDRESS
)(UINTN
)(VOID
*)NULL
,
658 if (Status
== EFI_OUT_OF_RESOURCES
) {
660 // Out of resource here means the image is hashed and its result is extended to PCR.
661 // But the event log can't be saved since log area is full.
662 // Just return EFI_SUCCESS in order not to block the image load.
664 Status
= EFI_SUCCESS
;
670 if (SectionHeader
!= NULL
) {
671 FreePool (SectionHeader
);
674 if (Sha1Ctx
!= NULL
) {
682 The security handler is used to abstract platform-specific policy
683 from the DXE core response to an attempt to use a file that returns a
684 given status for the authentication check from the section extraction protocol.
686 The possible responses in a given SAP implementation may include locking
687 flash upon failure to authenticate, attestation logging for all signed drivers,
688 and other exception operations. The File parameter allows for possible logging
689 within the SAP of the driver.
691 If the file specified by File with an authentication status specified by
692 AuthenticationStatus is safe for the DXE Core to use, then EFI_SUCCESS is returned.
694 If the file specified by File with an authentication status specified by
695 AuthenticationStatus is not safe for the DXE Core to use under any circumstances,
696 then EFI_ACCESS_DENIED is returned.
698 If the file specified by File with an authentication status specified by
699 AuthenticationStatus is not safe for the DXE Core to use right now, but it
700 might be possible to use it at a future time, then EFI_SECURITY_VIOLATION is
703 If check image specified by FileBuffer and File is NULL meanwhile, return EFI_ACCESS_DENIED.
705 @param[in] AuthenticationStatus This is the authentication status returned
706 from the securitymeasurement services for the
708 @param[in] File This is a pointer to the device path of the file that is
709 being dispatched. This will optionally be used for logging.
710 @param[in] FileBuffer File buffer matches the input file device path.
711 @param[in] FileSize Size of File buffer matches the input file device path.
712 @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.
714 @retval EFI_SUCCESS The file specified by DevicePath and non-NULL
715 FileBuffer did authenticate, and the platform policy dictates
716 that the DXE Foundation may use the file.
717 @retval other error value
721 DxeTpmMeasureBootHandler (
722 IN UINT32 AuthenticationStatus
,
723 IN CONST EFI_DEVICE_PATH_PROTOCOL
*File OPTIONAL
,
726 IN BOOLEAN BootPolicy
729 EFI_TCG_PROTOCOL
*TcgProtocol
;
731 TCG_EFI_BOOT_SERVICE_CAPABILITY ProtocolCapability
;
732 UINT32 TCGFeatureFlags
;
733 EFI_PHYSICAL_ADDRESS EventLogLocation
;
734 EFI_PHYSICAL_ADDRESS EventLogLastEntry
;
735 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
736 EFI_DEVICE_PATH_PROTOCOL
*OrigDevicePathNode
;
738 EFI_HANDLE TempHandle
;
739 BOOLEAN ApplicationRequired
;
740 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
741 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*FvbProtocol
;
742 EFI_PHYSICAL_ADDRESS FvAddress
;
745 Status
= gBS
->LocateProtocol (&gEfiTcgProtocolGuid
, NULL
, (VOID
**)&TcgProtocol
);
746 if (EFI_ERROR (Status
)) {
748 // TCG protocol is not installed. So, TPM is not present.
749 // Don't do any measurement, and directly return EFI_SUCCESS.
754 ProtocolCapability
.Size
= (UINT8
)sizeof (ProtocolCapability
);
755 Status
= TcgProtocol
->StatusCheck (
762 if (EFI_ERROR (Status
) || ProtocolCapability
.TPMDeactivatedFlag
|| (!ProtocolCapability
.TPMPresentFlag
)) {
764 // TPM device doesn't work or activate.
770 // Copy File Device Path
772 OrigDevicePathNode
= DuplicateDevicePath (File
);
775 // 1. Check whether this device path support BlockIo protocol.
776 // Is so, this device path may be a GPT device path.
778 DevicePathNode
= OrigDevicePathNode
;
779 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &DevicePathNode
, &Handle
);
780 if (!EFI_ERROR (Status
) && !mMeasureGptTableFlag
) {
782 // Find the gpt partition on the given devicepath
784 DevicePathNode
= OrigDevicePathNode
;
785 ASSERT (DevicePathNode
!= NULL
);
786 while (!IsDevicePathEnd (DevicePathNode
)) {
788 // Find the Gpt partition
790 if ((DevicePathType (DevicePathNode
) == MEDIA_DEVICE_PATH
) &&
791 (DevicePathSubType (DevicePathNode
) == MEDIA_HARDDRIVE_DP
))
794 // Check whether it is a gpt partition or not
796 if ((((HARDDRIVE_DEVICE_PATH
*)DevicePathNode
)->MBRType
== MBR_TYPE_EFI_PARTITION_TABLE_HEADER
) &&
797 (((HARDDRIVE_DEVICE_PATH
*)DevicePathNode
)->SignatureType
== SIGNATURE_TYPE_GUID
))
800 // Change the partition device path to its parent device path (disk) and get the handle.
802 DevicePathNode
->Type
= END_DEVICE_PATH_TYPE
;
803 DevicePathNode
->SubType
= END_ENTIRE_DEVICE_PATH_SUBTYPE
;
804 DevicePathNode
= OrigDevicePathNode
;
805 Status
= gBS
->LocateDevicePath (
806 &gEfiDiskIoProtocolGuid
,
810 if (!EFI_ERROR (Status
)) {
814 Status
= TcgMeasureGptTable (TcgProtocol
, Handle
);
815 if (!EFI_ERROR (Status
)) {
817 // GPT disk check done.
819 mMeasureGptTableFlag
= TRUE
;
823 FreePool (OrigDevicePathNode
);
824 OrigDevicePathNode
= DuplicateDevicePath (File
);
825 ASSERT (OrigDevicePathNode
!= NULL
);
830 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
835 // 2. Measure PE image.
837 ApplicationRequired
= FALSE
;
840 // Check whether this device path support FVB protocol.
842 DevicePathNode
= OrigDevicePathNode
;
843 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid
, &DevicePathNode
, &Handle
);
844 if (!EFI_ERROR (Status
)) {
846 // Don't check FV image, and directly return EFI_SUCCESS.
847 // It can be extended to the specific FV authentication according to the different requirement.
849 if (IsDevicePathEnd (DevicePathNode
)) {
854 // The PE image from unmeasured Firmware volume need be measured
855 // The PE image from measured Firmware volume will be measured according to policy below.
856 // If it is driver, do not measure
857 // If it is application, still measure.
859 ApplicationRequired
= TRUE
;
861 if ((mCacheMeasuredHandle
!= Handle
) && (mMeasuredHobData
!= NULL
)) {
863 // Search for Root FV of this PE image
867 Status
= gBS
->HandleProtocol (
869 &gEfiFirmwareVolumeBlockProtocolGuid
,
870 (VOID
**)&FvbProtocol
872 TempHandle
= FvbProtocol
->ParentHandle
;
873 } while (!EFI_ERROR (Status
) && FvbProtocol
->ParentHandle
!= NULL
);
876 // Search in measured FV Hob
878 Status
= FvbProtocol
->GetPhysicalAddress (FvbProtocol
, &FvAddress
);
879 if (EFI_ERROR (Status
)) {
883 ApplicationRequired
= FALSE
;
885 for (Index
= 0; Index
< mMeasuredHobData
->Num
; Index
++) {
886 if (mMeasuredHobData
->MeasuredFvBuf
[Index
].BlobBase
== FvAddress
) {
888 // Cache measured FV for next measurement
890 mCacheMeasuredHandle
= Handle
;
891 ApplicationRequired
= TRUE
;
899 // File is not found.
901 if (FileBuffer
== NULL
) {
902 Status
= EFI_SECURITY_VIOLATION
;
906 mTpmImageSize
= FileSize
;
907 mFileBuffer
= FileBuffer
;
912 DevicePathNode
= OrigDevicePathNode
;
913 ZeroMem (&ImageContext
, sizeof (ImageContext
));
914 ImageContext
.Handle
= (VOID
*)FileBuffer
;
915 ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
)DxeTpmMeasureBootLibImageRead
;
918 // Get information about the image being loaded
920 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
921 if (EFI_ERROR (Status
)) {
923 // Check for invalid parameters.
926 return EFI_ACCESS_DENIED
;
930 // The information can't be got from the invalid PeImage
936 // Measure only application if Application flag is set
937 // Measure drivers and applications if Application flag is not set
939 if ((!ApplicationRequired
) ||
940 (ApplicationRequired
&& (ImageContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
)))
943 // Print the image path to be measured.
947 ToText
= ConvertDevicePathToText (
952 if (ToText
!= NULL
) {
953 DEBUG ((DEBUG_INFO
, "The measured image path is %s.\n", ToText
));
960 // Measure PE image into TPM log.
962 Status
= TcgMeasurePeImage (
964 (EFI_PHYSICAL_ADDRESS
)(UINTN
)FileBuffer
,
966 (UINTN
)ImageContext
.ImageAddress
,
967 ImageContext
.ImageType
,
973 // Done, free the allocated resource.
976 if (OrigDevicePathNode
!= NULL
) {
977 FreePool (OrigDevicePathNode
);
984 Register the security handler to provide TPM measure boot service.
986 @param ImageHandle ImageHandle of the loaded driver.
987 @param SystemTable Pointer to the EFI System Table.
989 @retval EFI_SUCCESS Register successfully.
990 @retval EFI_OUT_OF_RESOURCES No enough memory to register this handler.
994 DxeTpmMeasureBootLibConstructor (
995 IN EFI_HANDLE ImageHandle
,
996 IN EFI_SYSTEM_TABLE
*SystemTable
999 EFI_HOB_GUID_TYPE
*GuidHob
;
1003 GuidHob
= GetFirstGuidHob (&gMeasuredFvHobGuid
);
1005 if (GuidHob
!= NULL
) {
1006 mMeasuredHobData
= GET_GUID_HOB_DATA (GuidHob
);
1009 return RegisterSecurity2Handler (
1010 DxeTpmMeasureBootHandler
,
1011 EFI_AUTH_OPERATION_MEASURE_IMAGE
| EFI_AUTH_OPERATION_IMAGE_REQUIRED