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