Home | History | Annotate | Download | only in DxeTpmMeasureBootLib
      1 /** @file
      2   The library instance provides security service of TPM 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   DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content
     10   read is within the image buffer.
     11 
     12   TcgMeasurePeImage() function will accept untrusted PE/COFF image and validate its
     13   data structure within this image buffer before use.
     14 
     15   TcgMeasureGptTable() function will receive untrusted GPT partition table, and parse
     16   partition data carefully.
     17 
     18 Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
     19 This program and the accompanying materials
     20 are licensed and made available under the terms and conditions of the BSD License
     21 which accompanies this distribution.  The full text of the license may be found at
     22 http://opensource.org/licenses/bsd-license.php
     23 
     24 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     25 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     26 
     27 **/
     28 
     29 #include <PiDxe.h>
     30 
     31 #include <Protocol/TcgService.h>
     32 #include <Protocol/BlockIo.h>
     33 #include <Protocol/DiskIo.h>
     34 #include <Protocol/FirmwareVolumeBlock.h>
     35 
     36 #include <Guid/MeasuredFvHob.h>
     37 #include <Guid/ZeroGuid.h>
     38 
     39 #include <Library/BaseLib.h>
     40 #include <Library/DebugLib.h>
     41 #include <Library/BaseMemoryLib.h>
     42 #include <Library/MemoryAllocationLib.h>
     43 #include <Library/DevicePathLib.h>
     44 #include <Library/UefiBootServicesTableLib.h>
     45 #include <Library/BaseCryptLib.h>
     46 #include <Library/PeCoffLib.h>
     47 #include <Library/SecurityManagementLib.h>
     48 #include <Library/HobLib.h>
     49 
     50 //
     51 // Flag to check GPT partition. It only need be measured once.
     52 //
     53 BOOLEAN                           mMeasureGptTableFlag = FALSE;
     54 UINTN                             mMeasureGptCount = 0;
     55 VOID                              *mFileBuffer;
     56 UINTN                             mTpmImageSize;
     57 //
     58 // Measured FV handle cache
     59 //
     60 EFI_HANDLE                        mCacheMeasuredHandle  = NULL;
     61 MEASURED_HOB_DATA                 *mMeasuredHobData     = NULL;
     62 
     63 /**
     64   Reads contents of a PE/COFF image in memory buffer.
     65 
     66   Caution: This function may receive untrusted input.
     67   PE/COFF image is external input, so this function will make sure the PE/COFF image content
     68   read is within the image buffer.
     69 
     70   @param  FileHandle      Pointer to the file handle to read the PE/COFF image.
     71   @param  FileOffset      Offset into the PE/COFF image to begin the read operation.
     72   @param  ReadSize        On input, the size in bytes of the requested read operation.
     73                           On output, the number of bytes actually read.
     74   @param  Buffer          Output buffer that contains the data read from the PE/COFF image.
     75 
     76   @retval EFI_SUCCESS     The specified portion of the PE/COFF image was read and the size
     77 **/
     78 EFI_STATUS
     79 EFIAPI
     80 DxeTpmMeasureBootLibImageRead (
     81   IN     VOID    *FileHandle,
     82   IN     UINTN   FileOffset,
     83   IN OUT UINTN   *ReadSize,
     84   OUT    VOID    *Buffer
     85   )
     86 {
     87   UINTN               EndPosition;
     88 
     89   if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {
     90     return EFI_INVALID_PARAMETER;
     91   }
     92 
     93   if (MAX_ADDRESS - FileOffset < *ReadSize) {
     94     return EFI_INVALID_PARAMETER;
     95   }
     96 
     97   EndPosition = FileOffset + *ReadSize;
     98   if (EndPosition > mTpmImageSize) {
     99     *ReadSize = (UINT32)(mTpmImageSize - FileOffset);
    100   }
    101 
    102   if (FileOffset >= mTpmImageSize) {
    103     *ReadSize = 0;
    104   }
    105 
    106   CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);
    107 
    108   return EFI_SUCCESS;
    109 }
    110 
    111 /**
    112   Measure GPT table data into TPM log.
    113 
    114   Caution: This function may receive untrusted input.
    115   The GPT partition table is external input, so this function should parse partition data carefully.
    116 
    117   @param TcgProtocol             Pointer to the located TCG protocol instance.
    118   @param GptHandle               Handle that GPT partition was installed.
    119 
    120   @retval EFI_SUCCESS            Successfully measure GPT table.
    121   @retval EFI_UNSUPPORTED        Not support GPT table on the given handle.
    122   @retval EFI_DEVICE_ERROR       Can't get GPT table because device error.
    123   @retval EFI_OUT_OF_RESOURCES   No enough resource to measure GPT table.
    124   @retval other error value
    125 **/
    126 EFI_STATUS
    127 EFIAPI
    128 TcgMeasureGptTable (
    129   IN  EFI_TCG_PROTOCOL   *TcgProtocol,
    130   IN  EFI_HANDLE         GptHandle
    131   )
    132 {
    133   EFI_STATUS                        Status;
    134   EFI_BLOCK_IO_PROTOCOL             *BlockIo;
    135   EFI_DISK_IO_PROTOCOL              *DiskIo;
    136   EFI_PARTITION_TABLE_HEADER        *PrimaryHeader;
    137   EFI_PARTITION_ENTRY               *PartitionEntry;
    138   UINT8                             *EntryPtr;
    139   UINTN                             NumberOfPartition;
    140   UINT32                            Index;
    141   TCG_PCR_EVENT                     *TcgEvent;
    142   EFI_GPT_DATA                      *GptData;
    143   UINT32                            EventSize;
    144   UINT32                            EventNumber;
    145   EFI_PHYSICAL_ADDRESS              EventLogLastEntry;
    146 
    147   if (mMeasureGptCount > 0) {
    148     return EFI_SUCCESS;
    149   }
    150 
    151   Status = gBS->HandleProtocol (GptHandle, &gEfiBlockIoProtocolGuid, (VOID**)&BlockIo);
    152   if (EFI_ERROR (Status)) {
    153     return EFI_UNSUPPORTED;
    154   }
    155   Status = gBS->HandleProtocol (GptHandle, &gEfiDiskIoProtocolGuid, (VOID**)&DiskIo);
    156   if (EFI_ERROR (Status)) {
    157     return EFI_UNSUPPORTED;
    158   }
    159   //
    160   // Read the EFI Partition Table Header
    161   //
    162   PrimaryHeader = (EFI_PARTITION_TABLE_HEADER *) AllocatePool (BlockIo->Media->BlockSize);
    163   if (PrimaryHeader == NULL) {
    164     return EFI_OUT_OF_RESOURCES;
    165   }
    166   Status = DiskIo->ReadDisk (
    167                      DiskIo,
    168                      BlockIo->Media->MediaId,
    169                      1 * BlockIo->Media->BlockSize,
    170                      BlockIo->Media->BlockSize,
    171                      (UINT8 *)PrimaryHeader
    172                      );
    173   if (EFI_ERROR (Status)) {
    174     DEBUG ((EFI_D_ERROR, "Failed to Read Partition Table Header!\n"));
    175     FreePool (PrimaryHeader);
    176     return EFI_DEVICE_ERROR;
    177   }
    178   //
    179   // Read the partition entry.
    180   //
    181   EntryPtr = (UINT8 *)AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);
    182   if (EntryPtr == NULL) {
    183     FreePool (PrimaryHeader);
    184     return EFI_OUT_OF_RESOURCES;
    185   }
    186   Status = DiskIo->ReadDisk (
    187                      DiskIo,
    188                      BlockIo->Media->MediaId,
    189                      MultU64x32(PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),
    190                      PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry,
    191                      EntryPtr
    192                      );
    193   if (EFI_ERROR (Status)) {
    194     FreePool (PrimaryHeader);
    195     FreePool (EntryPtr);
    196     return EFI_DEVICE_ERROR;
    197   }
    198 
    199   //
    200   // Count the valid partition
    201   //
    202   PartitionEntry    = (EFI_PARTITION_ENTRY *)EntryPtr;
    203   NumberOfPartition = 0;
    204   for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {
    205     if (!CompareGuid (&PartitionEntry->PartitionTypeGUID, &gZeroGuid)) {
    206       NumberOfPartition++;
    207     }
    208     PartitionEntry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry);
    209   }
    210 
    211   //
    212   // Prepare Data for Measurement
    213   //
    214   EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions)
    215                         + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry);
    216   TcgEvent = (TCG_PCR_EVENT *) AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT_HDR));
    217   if (TcgEvent == NULL) {
    218     FreePool (PrimaryHeader);
    219     FreePool (EntryPtr);
    220     return EFI_OUT_OF_RESOURCES;
    221   }
    222 
    223   TcgEvent->PCRIndex   = 5;
    224   TcgEvent->EventType  = EV_EFI_GPT_EVENT;
    225   TcgEvent->EventSize  = EventSize;
    226   GptData = (EFI_GPT_DATA *) TcgEvent->Event;
    227 
    228   //
    229   // Copy the EFI_PARTITION_TABLE_HEADER and NumberOfPartition
    230   //
    231   CopyMem ((UINT8 *)GptData, (UINT8*)PrimaryHeader, sizeof (EFI_PARTITION_TABLE_HEADER));
    232   GptData->NumberOfPartitions = NumberOfPartition;
    233   //
    234   // Copy the valid partition entry
    235   //
    236   PartitionEntry    = (EFI_PARTITION_ENTRY*)EntryPtr;
    237   NumberOfPartition = 0;
    238   for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {
    239     if (!CompareGuid (&PartitionEntry->PartitionTypeGUID, &gZeroGuid)) {
    240       CopyMem (
    241         (UINT8 *)&GptData->Partitions + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry,
    242         (UINT8 *)PartitionEntry,
    243         PrimaryHeader->SizeOfPartitionEntry
    244         );
    245       NumberOfPartition++;
    246     }
    247     PartitionEntry =(EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry);
    248   }
    249 
    250   //
    251   // Measure the GPT data
    252   //
    253   EventNumber = 1;
    254   Status = TcgProtocol->HashLogExtendEvent (
    255              TcgProtocol,
    256              (EFI_PHYSICAL_ADDRESS) (UINTN) (VOID *) GptData,
    257              (UINT64) TcgEvent->EventSize,
    258              TPM_ALG_SHA,
    259              TcgEvent,
    260              &EventNumber,
    261              &EventLogLastEntry
    262              );
    263   if (!EFI_ERROR (Status)) {
    264     mMeasureGptCount++;
    265   }
    266 
    267   FreePool (PrimaryHeader);
    268   FreePool (EntryPtr);
    269   FreePool (TcgEvent);
    270 
    271   return Status;
    272 }
    273 
    274 /**
    275   Measure PE image into TPM log based on the authenticode image hashing in
    276   PE/COFF Specification 8.0 Appendix A.
    277 
    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.
    281 
    282   @param[in] TcgProtocol    Pointer to the located TCG protocol instance.
    283   @param[in] ImageAddress   Start address of image buffer.
    284   @param[in] ImageSize      Image size
    285   @param[in] LinkTimeBase   Address that the image is loaded into memory.
    286   @param[in] ImageType      Image subsystem type.
    287   @param[in] FilePath       File path is corresponding to the input image.
    288 
    289   @retval EFI_SUCCESS            Successfully measure image.
    290   @retval EFI_OUT_OF_RESOURCES   No enough resource to measure image.
    291   @retval EFI_UNSUPPORTED        ImageType is unsupported or PE image is mal-format.
    292   @retval other error value
    293 
    294 **/
    295 EFI_STATUS
    296 EFIAPI
    297 TcgMeasurePeImage (
    298   IN  EFI_TCG_PROTOCOL          *TcgProtocol,
    299   IN  EFI_PHYSICAL_ADDRESS      ImageAddress,
    300   IN  UINTN                     ImageSize,
    301   IN  UINTN                     LinkTimeBase,
    302   IN  UINT16                    ImageType,
    303   IN  EFI_DEVICE_PATH_PROTOCOL  *FilePath
    304   )
    305 {
    306   EFI_STATUS                           Status;
    307   TCG_PCR_EVENT                        *TcgEvent;
    308   EFI_IMAGE_LOAD_EVENT                 *ImageLoad;
    309   UINT32                               FilePathSize;
    310   VOID                                 *Sha1Ctx;
    311   UINTN                                CtxSize;
    312   EFI_IMAGE_DOS_HEADER                 *DosHdr;
    313   UINT32                               PeCoffHeaderOffset;
    314   EFI_IMAGE_SECTION_HEADER             *Section;
    315   UINT8                                *HashBase;
    316   UINTN                                HashSize;
    317   UINTN                                SumOfBytesHashed;
    318   EFI_IMAGE_SECTION_HEADER             *SectionHeader;
    319   UINTN                                Index;
    320   UINTN                                Pos;
    321   UINT16                               Magic;
    322   UINT32                               EventSize;
    323   UINT32                               EventNumber;
    324   EFI_PHYSICAL_ADDRESS                 EventLogLastEntry;
    325   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr;
    326   UINT32                               NumberOfRvaAndSizes;
    327   BOOLEAN                              HashStatus;
    328   UINT32                               CertSize;
    329 
    330   Status        = EFI_UNSUPPORTED;
    331   ImageLoad     = NULL;
    332   SectionHeader = NULL;
    333   Sha1Ctx       = NULL;
    334   FilePathSize  = (UINT32) GetDevicePathSize (FilePath);
    335 
    336   //
    337   // Determine destination PCR by BootPolicy
    338   //
    339   EventSize = sizeof (*ImageLoad) - sizeof (ImageLoad->DevicePath) + FilePathSize;
    340   TcgEvent = AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT));
    341   if (TcgEvent == NULL) {
    342     return EFI_OUT_OF_RESOURCES;
    343   }
    344 
    345   TcgEvent->EventSize = EventSize;
    346   ImageLoad           = (EFI_IMAGE_LOAD_EVENT *) TcgEvent->Event;
    347 
    348   switch (ImageType) {
    349     case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:
    350       TcgEvent->EventType = EV_EFI_BOOT_SERVICES_APPLICATION;
    351       TcgEvent->PCRIndex  = 4;
    352       break;
    353     case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
    354       TcgEvent->EventType = EV_EFI_BOOT_SERVICES_DRIVER;
    355       TcgEvent->PCRIndex  = 2;
    356       break;
    357     case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
    358       TcgEvent->EventType = EV_EFI_RUNTIME_SERVICES_DRIVER;
    359       TcgEvent->PCRIndex  = 2;
    360       break;
    361     default:
    362       DEBUG ((
    363         EFI_D_ERROR,
    364         "TcgMeasurePeImage: Unknown subsystem type %d",
    365         ImageType
    366         ));
    367       goto Finish;
    368   }
    369 
    370   ImageLoad->ImageLocationInMemory = ImageAddress;
    371   ImageLoad->ImageLengthInMemory   = ImageSize;
    372   ImageLoad->ImageLinkTimeAddress  = LinkTimeBase;
    373   ImageLoad->LengthOfDevicePath    = FilePathSize;
    374   if ((FilePath != NULL) && (FilePathSize != 0)) {
    375     CopyMem (ImageLoad->DevicePath, FilePath, FilePathSize);
    376   }
    377 
    378   //
    379   // Check PE/COFF image
    380   //
    381   DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;
    382   PeCoffHeaderOffset = 0;
    383   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
    384     PeCoffHeaderOffset = DosHdr->e_lfanew;
    385   }
    386 
    387   Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);
    388   if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
    389     goto Finish;
    390   }
    391 
    392   //
    393   // PE/COFF Image Measurement
    394   //
    395   //    NOTE: The following codes/steps are based upon the authenticode image hashing in
    396   //      PE/COFF Specification 8.0 Appendix A.
    397   //
    398   //
    399 
    400   // 1.  Load the image header into memory.
    401 
    402   // 2.  Initialize a SHA hash context.
    403   CtxSize = Sha1GetContextSize ();
    404   Sha1Ctx = AllocatePool (CtxSize);
    405   if (Sha1Ctx == NULL) {
    406     Status = EFI_OUT_OF_RESOURCES;
    407     goto Finish;
    408   }
    409 
    410   HashStatus = Sha1Init (Sha1Ctx);
    411   if (!HashStatus) {
    412     goto Finish;
    413   }
    414 
    415   //
    416   // Measuring PE/COFF Image Header;
    417   // But CheckSum field and SECURITY data directory (certificate) are excluded
    418   //
    419   if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    420     //
    421     // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
    422     //       in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
    423     //       Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
    424     //       then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
    425     //
    426     Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
    427   } else {
    428     //
    429     // Get the magic value from the PE/COFF Optional Header
    430     //
    431     Magic = Hdr.Pe32->OptionalHeader.Magic;
    432   }
    433 
    434   //
    435   // 3.  Calculate the distance from the base of the image header to the image checksum address.
    436   // 4.  Hash the image header from its base to beginning of the image checksum.
    437   //
    438   HashBase = (UINT8 *) (UINTN) ImageAddress;
    439   if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    440     //
    441     // Use PE32 offset
    442     //
    443     NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
    444     HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.CheckSum) - HashBase);
    445   } else {
    446     //
    447     // Use PE32+ offset
    448     //
    449     NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
    450     HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.CheckSum) - HashBase);
    451   }
    452 
    453   HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);
    454   if (!HashStatus) {
    455     goto Finish;
    456   }
    457 
    458   //
    459   // 5.  Skip over the image checksum (it occupies a single ULONG).
    460   //
    461   if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
    462     //
    463     // 6.  Since there is no Cert Directory in optional header, hash everything
    464     //     from the end of the checksum to the end of image header.
    465     //
    466     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    467       //
    468       // Use PE32 offset.
    469       //
    470       HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
    471       HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
    472     } else {
    473       //
    474       // Use PE32+ offset.
    475       //
    476       HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
    477       HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
    478     }
    479 
    480     if (HashSize != 0) {
    481       HashStatus  = Sha1Update (Sha1Ctx, HashBase, HashSize);
    482       if (!HashStatus) {
    483         goto Finish;
    484       }
    485     }
    486   } else {
    487     //
    488     // 7.  Hash everything from the end of the checksum to the start of the Cert Directory.
    489     //
    490     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    491       //
    492       // Use PE32 offset
    493       //
    494       HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
    495       HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
    496     } else {
    497       //
    498       // Use PE32+ offset
    499       //
    500       HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
    501       HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
    502     }
    503 
    504     if (HashSize != 0) {
    505       HashStatus  = Sha1Update (Sha1Ctx, HashBase, HashSize);
    506       if (!HashStatus) {
    507         goto Finish;
    508       }
    509     }
    510 
    511     //
    512     // 8.  Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)
    513     // 9.  Hash everything from the end of the Cert Directory to the end of image header.
    514     //
    515     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    516       //
    517       // Use PE32 offset
    518       //
    519       HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
    520       HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
    521     } else {
    522       //
    523       // Use PE32+ offset
    524       //
    525       HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
    526       HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
    527     }
    528 
    529     if (HashSize != 0) {
    530       HashStatus  = Sha1Update (Sha1Ctx, HashBase, HashSize);
    531       if (!HashStatus) {
    532         goto Finish;
    533       }
    534     }
    535   }
    536 
    537   //
    538   // 10. Set the SUM_OF_BYTES_HASHED to the size of the header
    539   //
    540   if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    541     //
    542     // Use PE32 offset
    543     //
    544     SumOfBytesHashed = Hdr.Pe32->OptionalHeader.SizeOfHeaders;
    545   } else {
    546     //
    547     // Use PE32+ offset
    548     //
    549     SumOfBytesHashed = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;
    550   }
    551 
    552   //
    553   // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER
    554   //     structures in the image. The 'NumberOfSections' field of the image
    555   //     header indicates how big the table should be. Do not include any
    556   //     IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.
    557   //
    558   SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections);
    559   if (SectionHeader == NULL) {
    560     Status = EFI_OUT_OF_RESOURCES;
    561     goto Finish;
    562   }
    563 
    564   //
    565   // 12.  Using the 'PointerToRawData' in the referenced section headers as
    566   //      a key, arrange the elements in the table in ascending order. In other
    567   //      words, sort the section headers according to the disk-file offset of
    568   //      the section.
    569   //
    570   Section = (EFI_IMAGE_SECTION_HEADER *) (
    571                (UINT8 *) (UINTN) ImageAddress +
    572                PeCoffHeaderOffset +
    573                sizeof(UINT32) +
    574                sizeof(EFI_IMAGE_FILE_HEADER) +
    575                Hdr.Pe32->FileHeader.SizeOfOptionalHeader
    576                );
    577   for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
    578     Pos = Index;
    579     while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {
    580       CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof(EFI_IMAGE_SECTION_HEADER));
    581       Pos--;
    582     }
    583     CopyMem (&SectionHeader[Pos], Section, sizeof(EFI_IMAGE_SECTION_HEADER));
    584     Section += 1;
    585   }
    586 
    587   //
    588   // 13.  Walk through the sorted table, bring the corresponding section
    589   //      into memory, and hash the entire section (using the 'SizeOfRawData'
    590   //      field in the section header to determine the amount of data to hash).
    591   // 14.  Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .
    592   // 15.  Repeat steps 13 and 14 for all the sections in the sorted table.
    593   //
    594   for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
    595     Section  = (EFI_IMAGE_SECTION_HEADER *) &SectionHeader[Index];
    596     if (Section->SizeOfRawData == 0) {
    597       continue;
    598     }
    599     HashBase = (UINT8 *) (UINTN) ImageAddress + Section->PointerToRawData;
    600     HashSize = (UINTN) Section->SizeOfRawData;
    601 
    602     HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);
    603     if (!HashStatus) {
    604       goto Finish;
    605     }
    606 
    607     SumOfBytesHashed += HashSize;
    608   }
    609 
    610   //
    611   // 16.  If the file size is greater than SUM_OF_BYTES_HASHED, there is extra
    612   //      data in the file that needs to be added to the hash. This data begins
    613   //      at file offset SUM_OF_BYTES_HASHED and its length is:
    614   //             FileSize  -  (CertDirectory->Size)
    615   //
    616   if (ImageSize > SumOfBytesHashed) {
    617     HashBase = (UINT8 *) (UINTN) ImageAddress + SumOfBytesHashed;
    618 
    619     if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
    620       CertSize = 0;
    621     } else {
    622       if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    623         //
    624         // Use PE32 offset.
    625         //
    626         CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
    627       } else {
    628         //
    629         // Use PE32+ offset.
    630         //
    631         CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
    632       }
    633     }
    634 
    635     if (ImageSize > CertSize + SumOfBytesHashed) {
    636       HashSize = (UINTN) (ImageSize - CertSize - SumOfBytesHashed);
    637 
    638       HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);
    639       if (!HashStatus) {
    640         goto Finish;
    641       }
    642     } else if (ImageSize < CertSize + SumOfBytesHashed) {
    643       goto Finish;
    644     }
    645   }
    646 
    647   //
    648   // 17.  Finalize the SHA hash.
    649   //
    650   HashStatus = Sha1Final (Sha1Ctx, (UINT8 *) &TcgEvent->Digest);
    651   if (!HashStatus) {
    652     goto Finish;
    653   }
    654 
    655   //
    656   // Log the PE data
    657   //
    658   EventNumber = 1;
    659   Status = TcgProtocol->HashLogExtendEvent (
    660              TcgProtocol,
    661              (EFI_PHYSICAL_ADDRESS) (UINTN) (VOID *) NULL,
    662              0,
    663              TPM_ALG_SHA,
    664              TcgEvent,
    665              &EventNumber,
    666              &EventLogLastEntry
    667              );
    668   if (Status == EFI_OUT_OF_RESOURCES) {
    669     //
    670     // Out of resource here means the image is hashed and its result is extended to PCR.
    671     // But the event log cann't be saved since log area is full.
    672     // Just return EFI_SUCCESS in order not to block the image load.
    673     //
    674     Status = EFI_SUCCESS;
    675   }
    676 
    677 Finish:
    678   FreePool (TcgEvent);
    679 
    680   if (SectionHeader != NULL) {
    681     FreePool (SectionHeader);
    682   }
    683 
    684   if (Sha1Ctx != NULL ) {
    685     FreePool (Sha1Ctx);
    686   }
    687   return Status;
    688 }
    689 
    690 /**
    691   The security handler is used to abstract platform-specific policy
    692   from the DXE core response to an attempt to use a file that returns a
    693   given status for the authentication check from the section extraction protocol.
    694 
    695   The possible responses in a given SAP implementation may include locking
    696   flash upon failure to authenticate, attestation logging for all signed drivers,
    697   and other exception operations.  The File parameter allows for possible logging
    698   within the SAP of the driver.
    699 
    700   If File is NULL, then EFI_INVALID_PARAMETER is returned.
    701 
    702   If the file specified by File with an authentication status specified by
    703   AuthenticationStatus is safe for the DXE Core to use, then EFI_SUCCESS is returned.
    704 
    705   If the file specified by File with an authentication status specified by
    706   AuthenticationStatus is not safe for the DXE Core to use under any circumstances,
    707   then EFI_ACCESS_DENIED is returned.
    708 
    709   If the file specified by File with an authentication status specified by
    710   AuthenticationStatus is not safe for the DXE Core to use right now, but it
    711   might be possible to use it at a future time, then EFI_SECURITY_VIOLATION is
    712   returned.
    713 
    714   @param[in]      AuthenticationStatus  This is the authentication status returned
    715                                         from the securitymeasurement services for the
    716                                         input file.
    717   @param[in]      File       This is a pointer to the device path of the file that is
    718                              being dispatched. This will optionally be used for logging.
    719   @param[in]      FileBuffer File buffer matches the input file device path.
    720   @param[in]      FileSize   Size of File buffer matches the input file device path.
    721   @param[in]      BootPolicy A boot policy that was used to call LoadImage() UEFI service.
    722 
    723   @retval EFI_SUCCESS             The file specified by DevicePath and non-NULL
    724                                   FileBuffer did authenticate, and the platform policy dictates
    725                                   that the DXE Foundation may use the file.
    726   @retval other error value
    727 **/
    728 EFI_STATUS
    729 EFIAPI
    730 DxeTpmMeasureBootHandler (
    731   IN  UINT32                           AuthenticationStatus,
    732   IN  CONST EFI_DEVICE_PATH_PROTOCOL   *File,
    733   IN  VOID                             *FileBuffer,
    734   IN  UINTN                            FileSize,
    735   IN  BOOLEAN                          BootPolicy
    736   )
    737 {
    738   EFI_TCG_PROTOCOL                    *TcgProtocol;
    739   EFI_STATUS                          Status;
    740   TCG_EFI_BOOT_SERVICE_CAPABILITY     ProtocolCapability;
    741   UINT32                              TCGFeatureFlags;
    742   EFI_PHYSICAL_ADDRESS                EventLogLocation;
    743   EFI_PHYSICAL_ADDRESS                EventLogLastEntry;
    744   EFI_DEVICE_PATH_PROTOCOL            *DevicePathNode;
    745   EFI_DEVICE_PATH_PROTOCOL            *OrigDevicePathNode;
    746   EFI_HANDLE                          Handle;
    747   EFI_HANDLE                          TempHandle;
    748   BOOLEAN                             ApplicationRequired;
    749   PE_COFF_LOADER_IMAGE_CONTEXT        ImageContext;
    750   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *FvbProtocol;
    751   EFI_PHYSICAL_ADDRESS                FvAddress;
    752   UINT32                              Index;
    753 
    754   Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **) &TcgProtocol);
    755   if (EFI_ERROR (Status)) {
    756     //
    757     // TCG protocol is not installed. So, TPM is not present.
    758     // Don't do any measurement, and directly return EFI_SUCCESS.
    759     //
    760     return EFI_SUCCESS;
    761   }
    762 
    763   ProtocolCapability.Size = (UINT8) sizeof (ProtocolCapability);
    764   Status = TcgProtocol->StatusCheck (
    765              TcgProtocol,
    766              &ProtocolCapability,
    767              &TCGFeatureFlags,
    768              &EventLogLocation,
    769              &EventLogLastEntry
    770            );
    771   if (EFI_ERROR (Status) || ProtocolCapability.TPMDeactivatedFlag || (!ProtocolCapability.TPMPresentFlag)) {
    772     //
    773     // TPM device doesn't work or activate.
    774     //
    775     return EFI_SUCCESS;
    776   }
    777 
    778   //
    779   // Copy File Device Path
    780   //
    781   OrigDevicePathNode = DuplicateDevicePath (File);
    782 
    783   //
    784   // 1. Check whether this device path support BlockIo protocol.
    785   // Is so, this device path may be a GPT device path.
    786   //
    787   DevicePathNode = OrigDevicePathNode;
    788   Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevicePathNode, &Handle);
    789   if (!EFI_ERROR (Status) && !mMeasureGptTableFlag) {
    790     //
    791     // Find the gpt partion on the given devicepath
    792     //
    793     DevicePathNode = OrigDevicePathNode;
    794     ASSERT (DevicePathNode != NULL);
    795     while (!IsDevicePathEnd (DevicePathNode)) {
    796       //
    797       // Find the Gpt partition
    798       //
    799       if (DevicePathType (DevicePathNode) == MEDIA_DEVICE_PATH &&
    800             DevicePathSubType (DevicePathNode) == MEDIA_HARDDRIVE_DP) {
    801         //
    802         // Check whether it is a gpt partition or not
    803         //
    804         if (((HARDDRIVE_DEVICE_PATH *) DevicePathNode)->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER &&
    805             ((HARDDRIVE_DEVICE_PATH *) DevicePathNode)->SignatureType == SIGNATURE_TYPE_GUID) {
    806 
    807           //
    808           // Change the partition device path to its parent device path (disk) and get the handle.
    809           //
    810           DevicePathNode->Type    = END_DEVICE_PATH_TYPE;
    811           DevicePathNode->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
    812           DevicePathNode          = OrigDevicePathNode;
    813           Status = gBS->LocateDevicePath (
    814                          &gEfiDiskIoProtocolGuid,
    815                          &DevicePathNode,
    816                          &Handle
    817                          );
    818           if (!EFI_ERROR (Status)) {
    819             //
    820             // Measure GPT disk.
    821             //
    822             Status = TcgMeasureGptTable (TcgProtocol, Handle);
    823             if (!EFI_ERROR (Status)) {
    824               //
    825               // GPT disk check done.
    826               //
    827               mMeasureGptTableFlag = TRUE;
    828             }
    829           }
    830           FreePool (OrigDevicePathNode);
    831           OrigDevicePathNode = DuplicateDevicePath (File);
    832           ASSERT (OrigDevicePathNode != NULL);
    833           break;
    834         }
    835       }
    836       DevicePathNode    = NextDevicePathNode (DevicePathNode);
    837     }
    838   }
    839 
    840   //
    841   // 2. Measure PE image.
    842   //
    843   ApplicationRequired = FALSE;
    844 
    845   //
    846   // Check whether this device path support FVB protocol.
    847   //
    848   DevicePathNode = OrigDevicePathNode;
    849   Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &DevicePathNode, &Handle);
    850   if (!EFI_ERROR (Status)) {
    851     //
    852     // Don't check FV image, and directly return EFI_SUCCESS.
    853     // It can be extended to the specific FV authentication according to the different requirement.
    854     //
    855     if (IsDevicePathEnd (DevicePathNode)) {
    856       return EFI_SUCCESS;
    857     }
    858     //
    859     // The PE image from unmeasured Firmware volume need be measured
    860     // The PE image from measured Firmware volume will be mearsured according to policy below.
    861     //   If it is driver, do not measure
    862     //   If it is application, still measure.
    863     //
    864     ApplicationRequired = TRUE;
    865 
    866     if (mCacheMeasuredHandle != Handle && mMeasuredHobData != NULL) {
    867       //
    868       // Search for Root FV of this PE image
    869       //
    870       TempHandle = Handle;
    871       do {
    872         Status = gBS->HandleProtocol(
    873                         TempHandle,
    874                         &gEfiFirmwareVolumeBlockProtocolGuid,
    875                         (VOID**)&FvbProtocol
    876                         );
    877         TempHandle = FvbProtocol->ParentHandle;
    878       } while (!EFI_ERROR(Status) && FvbProtocol->ParentHandle != NULL);
    879 
    880       //
    881       // Search in measured FV Hob
    882       //
    883       Status = FvbProtocol->GetPhysicalAddress(FvbProtocol, &FvAddress);
    884       if (EFI_ERROR(Status)){
    885         return Status;
    886       }
    887 
    888       ApplicationRequired = FALSE;
    889 
    890       for (Index = 0; Index < mMeasuredHobData->Num; Index++) {
    891         if(mMeasuredHobData->MeasuredFvBuf[Index].BlobBase == FvAddress) {
    892           //
    893           // Cache measured FV for next measurement
    894           //
    895           mCacheMeasuredHandle = Handle;
    896           ApplicationRequired  = TRUE;
    897           break;
    898         }
    899       }
    900     }
    901   }
    902 
    903   //
    904   // File is not found.
    905   //
    906   if (FileBuffer == NULL) {
    907     Status = EFI_SECURITY_VIOLATION;
    908     goto Finish;
    909   }
    910 
    911   mTpmImageSize  = FileSize;
    912   mFileBuffer = FileBuffer;
    913 
    914   //
    915   // Measure PE Image
    916   //
    917   DevicePathNode = OrigDevicePathNode;
    918   ZeroMem (&ImageContext, sizeof (ImageContext));
    919   ImageContext.Handle    = (VOID *) FileBuffer;
    920   ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeTpmMeasureBootLibImageRead;
    921 
    922   //
    923   // Get information about the image being loaded
    924   //
    925   Status = PeCoffLoaderGetImageInfo (&ImageContext);
    926   if (EFI_ERROR (Status)) {
    927     //
    928     // The information can't be got from the invalid PeImage
    929     //
    930     goto Finish;
    931   }
    932 
    933   //
    934   // Measure only application if Application flag is set
    935   // Measure drivers and applications if Application flag is not set
    936   //
    937   if ((!ApplicationRequired) ||
    938         (ApplicationRequired && ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)) {
    939     //
    940     // Print the image path to be measured.
    941     //
    942     DEBUG_CODE_BEGIN ();
    943       CHAR16                            *ToText;
    944       ToText = ConvertDevicePathToText (
    945                  DevicePathNode,
    946                  FALSE,
    947                  TRUE
    948                  );
    949       if (ToText != NULL) {
    950         DEBUG ((DEBUG_INFO, "The measured image path is %s.\n", ToText));
    951         FreePool (ToText);
    952       }
    953     DEBUG_CODE_END ();
    954 
    955     //
    956     // Measure PE image into TPM log.
    957     //
    958     Status = TcgMeasurePeImage (
    959                TcgProtocol,
    960                (EFI_PHYSICAL_ADDRESS) (UINTN) FileBuffer,
    961                FileSize,
    962                (UINTN) ImageContext.ImageAddress,
    963                ImageContext.ImageType,
    964                DevicePathNode
    965                );
    966   }
    967 
    968   //
    969   // Done, free the allocated resource.
    970   //
    971 Finish:
    972   if (OrigDevicePathNode != NULL) {
    973     FreePool (OrigDevicePathNode);
    974   }
    975 
    976   return Status;
    977 }
    978 
    979 /**
    980   Register the security handler to provide TPM measure boot service.
    981 
    982   @param  ImageHandle  ImageHandle of the loaded driver.
    983   @param  SystemTable  Pointer to the EFI System Table.
    984 
    985   @retval  EFI_SUCCESS            Register successfully.
    986   @retval  EFI_OUT_OF_RESOURCES   No enough memory to register this handler.
    987 **/
    988 EFI_STATUS
    989 EFIAPI
    990 DxeTpmMeasureBootLibConstructor (
    991   IN EFI_HANDLE        ImageHandle,
    992   IN EFI_SYSTEM_TABLE  *SystemTable
    993   )
    994 {
    995   EFI_HOB_GUID_TYPE  *GuidHob;
    996 
    997   GuidHob = NULL;
    998 
    999   GuidHob = GetFirstGuidHob (&gMeasuredFvHobGuid);
   1000 
   1001   if (GuidHob != NULL) {
   1002     mMeasuredHobData = GET_GUID_HOB_DATA (GuidHob);
   1003   }
   1004 
   1005   return RegisterSecurity2Handler (
   1006           DxeTpmMeasureBootHandler,
   1007           EFI_AUTH_OPERATION_MEASURE_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED
   1008           );
   1009 }
   1010