Home | History | Annotate | Download | only in Tcg2Dxe
      1 /** @file
      2   This module implements measuring PeCoff image for Tcg2 Protocol.
      3 
      4   Caution: This file requires additional review when modified.
      5   This driver will have external input - PE/COFF image.
      6   This external input must be validated carefully to avoid security issue like
      7   buffer overflow, integer overflow.
      8 
      9 Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
     10 This program and the accompanying materials
     11 are licensed and made available under the terms and conditions of the BSD License
     12 which accompanies this distribution.  The full text of the license may be found at
     13 http://opensource.org/licenses/bsd-license.php
     14 
     15 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     16 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     17 
     18 **/
     19 
     20 #include <PiDxe.h>
     21 
     22 #include <Library/BaseLib.h>
     23 #include <Library/DebugLib.h>
     24 #include <Library/BaseMemoryLib.h>
     25 #include <Library/MemoryAllocationLib.h>
     26 #include <Library/DevicePathLib.h>
     27 #include <Library/UefiBootServicesTableLib.h>
     28 #include <Library/PeCoffLib.h>
     29 #include <Library/Tpm2CommandLib.h>
     30 #include <Library/HashLib.h>
     31 
     32 UINTN  mTcg2DxeImageSize = 0;
     33 
     34 /**
     35   Reads contents of a PE/COFF image in memory buffer.
     36 
     37   Caution: This function may receive untrusted input.
     38   PE/COFF image is external input, so this function will make sure the PE/COFF image content
     39   read is within the image buffer.
     40 
     41   @param  FileHandle      Pointer to the file handle to read the PE/COFF image.
     42   @param  FileOffset      Offset into the PE/COFF image to begin the read operation.
     43   @param  ReadSize        On input, the size in bytes of the requested read operation.
     44                           On output, the number of bytes actually read.
     45   @param  Buffer          Output buffer that contains the data read from the PE/COFF image.
     46 
     47   @retval EFI_SUCCESS     The specified portion of the PE/COFF image was read and the size
     48 **/
     49 EFI_STATUS
     50 EFIAPI
     51 Tcg2DxeImageRead (
     52   IN     VOID    *FileHandle,
     53   IN     UINTN   FileOffset,
     54   IN OUT UINTN   *ReadSize,
     55   OUT    VOID    *Buffer
     56   )
     57 {
     58   UINTN               EndPosition;
     59 
     60   if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {
     61     return EFI_INVALID_PARAMETER;
     62   }
     63 
     64   if (MAX_ADDRESS - FileOffset < *ReadSize) {
     65     return EFI_INVALID_PARAMETER;
     66   }
     67 
     68   EndPosition = FileOffset + *ReadSize;
     69   if (EndPosition > mTcg2DxeImageSize) {
     70     *ReadSize = (UINT32)(mTcg2DxeImageSize - FileOffset);
     71   }
     72 
     73   if (FileOffset >= mTcg2DxeImageSize) {
     74     *ReadSize = 0;
     75   }
     76 
     77   CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);
     78 
     79   return EFI_SUCCESS;
     80 }
     81 
     82 /**
     83   Measure PE image into TPM log based on the authenticode image hashing in
     84   PE/COFF Specification 8.0 Appendix A.
     85 
     86   Caution: This function may receive untrusted input.
     87   PE/COFF image is external input, so this function will validate its data structure
     88   within this image buffer before use.
     89 
     90   Notes: PE/COFF image is checked by BasePeCoffLib PeCoffLoaderGetImageInfo().
     91 
     92   @param[in]  PCRIndex       TPM PCR index
     93   @param[in]  ImageAddress   Start address of image buffer.
     94   @param[in]  ImageSize      Image size
     95   @param[out] DigestList     Digeest list of this image.
     96 
     97   @retval EFI_SUCCESS            Successfully measure image.
     98   @retval EFI_OUT_OF_RESOURCES   No enough resource to measure image.
     99   @retval other error value
    100 **/
    101 EFI_STATUS
    102 MeasurePeImageAndExtend (
    103   IN  UINT32                    PCRIndex,
    104   IN  EFI_PHYSICAL_ADDRESS      ImageAddress,
    105   IN  UINTN                     ImageSize,
    106   OUT TPML_DIGEST_VALUES        *DigestList
    107   )
    108 {
    109   EFI_STATUS                           Status;
    110   EFI_IMAGE_DOS_HEADER                 *DosHdr;
    111   UINT32                               PeCoffHeaderOffset;
    112   EFI_IMAGE_SECTION_HEADER             *Section;
    113   UINT8                                *HashBase;
    114   UINTN                                HashSize;
    115   UINTN                                SumOfBytesHashed;
    116   EFI_IMAGE_SECTION_HEADER             *SectionHeader;
    117   UINTN                                Index;
    118   UINTN                                Pos;
    119   UINT16                               Magic;
    120   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr;
    121   UINT32                               NumberOfRvaAndSizes;
    122   UINT32                               CertSize;
    123   HASH_HANDLE                          HashHandle;
    124   PE_COFF_LOADER_IMAGE_CONTEXT         ImageContext;
    125 
    126   HashHandle = 0xFFFFFFFF; // Know bad value
    127 
    128   Status        = EFI_UNSUPPORTED;
    129   SectionHeader = NULL;
    130 
    131   //
    132   // Check PE/COFF image
    133   //
    134   ZeroMem (&ImageContext, sizeof (ImageContext));
    135   ImageContext.Handle    = (VOID *) (UINTN) ImageAddress;
    136   mTcg2DxeImageSize      = ImageSize;
    137   ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) Tcg2DxeImageRead;
    138 
    139   //
    140   // Get information about the image being loaded
    141   //
    142   Status = PeCoffLoaderGetImageInfo (&ImageContext);
    143   if (EFI_ERROR (Status)) {
    144     //
    145     // The information can't be got from the invalid PeImage
    146     //
    147     DEBUG ((DEBUG_INFO, "Tcg2Dxe: PeImage invalid. Cannot retrieve image information.\n"));
    148     goto Finish;
    149   }
    150 
    151   DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;
    152   PeCoffHeaderOffset = 0;
    153   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
    154     PeCoffHeaderOffset = DosHdr->e_lfanew;
    155   }
    156 
    157   Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);
    158   if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
    159     Status = EFI_UNSUPPORTED;
    160     goto Finish;
    161   }
    162 
    163   //
    164   // PE/COFF Image Measurement
    165   //
    166   //    NOTE: The following codes/steps are based upon the authenticode image hashing in
    167   //      PE/COFF Specification 8.0 Appendix A.
    168   //
    169   //
    170 
    171   // 1.  Load the image header into memory.
    172 
    173   // 2.  Initialize a SHA hash context.
    174 
    175   Status = HashStart (&HashHandle);
    176   if (EFI_ERROR (Status)) {
    177     goto Finish;
    178   }
    179 
    180   //
    181   // Measuring PE/COFF Image Header;
    182   // But CheckSum field and SECURITY data directory (certificate) are excluded
    183   //
    184   if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    185     //
    186     // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
    187     //       in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
    188     //       Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
    189     //       then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
    190     //
    191     Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
    192   } else {
    193     //
    194     // Get the magic value from the PE/COFF Optional Header
    195     //
    196     Magic = Hdr.Pe32->OptionalHeader.Magic;
    197   }
    198 
    199   //
    200   // 3.  Calculate the distance from the base of the image header to the image checksum address.
    201   // 4.  Hash the image header from its base to beginning of the image checksum.
    202   //
    203   HashBase = (UINT8 *) (UINTN) ImageAddress;
    204   if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    205     //
    206     // Use PE32 offset
    207     //
    208     NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
    209     HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.CheckSum) - HashBase);
    210   } else {
    211     //
    212     // Use PE32+ offset
    213     //
    214     NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
    215     HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.CheckSum) - HashBase);
    216   }
    217 
    218   Status = HashUpdate (HashHandle, HashBase, HashSize);
    219   if (EFI_ERROR (Status)) {
    220     goto Finish;
    221   }
    222 
    223   //
    224   // 5.  Skip over the image checksum (it occupies a single ULONG).
    225   //
    226   if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
    227     //
    228     // 6.  Since there is no Cert Directory in optional header, hash everything
    229     //     from the end of the checksum to the end of image header.
    230     //
    231     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    232       //
    233       // Use PE32 offset.
    234       //
    235       HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
    236       HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
    237     } else {
    238       //
    239       // Use PE32+ offset.
    240       //
    241       HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
    242       HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
    243     }
    244 
    245     if (HashSize != 0) {
    246       Status  = HashUpdate (HashHandle, HashBase, HashSize);
    247       if (EFI_ERROR (Status)) {
    248         goto Finish;
    249       }
    250     }
    251   } else {
    252     //
    253     // 7.  Hash everything from the end of the checksum to the start of the Cert Directory.
    254     //
    255     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    256       //
    257       // Use PE32 offset
    258       //
    259       HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
    260       HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
    261     } else {
    262       //
    263       // Use PE32+ offset
    264       //
    265       HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
    266       HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
    267     }
    268 
    269     if (HashSize != 0) {
    270       Status  = HashUpdate (HashHandle, HashBase, HashSize);
    271       if (EFI_ERROR (Status)) {
    272         goto Finish;
    273       }
    274     }
    275 
    276     //
    277     // 8.  Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)
    278     // 9.  Hash everything from the end of the Cert Directory to the end of image header.
    279     //
    280     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    281       //
    282       // Use PE32 offset
    283       //
    284       HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
    285       HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
    286     } else {
    287       //
    288       // Use PE32+ offset
    289       //
    290       HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
    291       HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
    292     }
    293 
    294     if (HashSize != 0) {
    295       Status  = HashUpdate (HashHandle, HashBase, HashSize);
    296       if (EFI_ERROR (Status)) {
    297         goto Finish;
    298       }
    299     }
    300   }
    301 
    302   //
    303   // 10. Set the SUM_OF_BYTES_HASHED to the size of the header
    304   //
    305   if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    306     //
    307     // Use PE32 offset
    308     //
    309     SumOfBytesHashed = Hdr.Pe32->OptionalHeader.SizeOfHeaders;
    310   } else {
    311     //
    312     // Use PE32+ offset
    313     //
    314     SumOfBytesHashed = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;
    315   }
    316 
    317   //
    318   // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER
    319   //     structures in the image. The 'NumberOfSections' field of the image
    320   //     header indicates how big the table should be. Do not include any
    321   //     IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.
    322   //
    323   SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections);
    324   if (SectionHeader == NULL) {
    325     Status = EFI_OUT_OF_RESOURCES;
    326     goto Finish;
    327   }
    328 
    329   //
    330   // 12.  Using the 'PointerToRawData' in the referenced section headers as
    331   //      a key, arrange the elements in the table in ascending order. In other
    332   //      words, sort the section headers according to the disk-file offset of
    333   //      the section.
    334   //
    335   Section = (EFI_IMAGE_SECTION_HEADER *) (
    336                (UINT8 *) (UINTN) ImageAddress +
    337                PeCoffHeaderOffset +
    338                sizeof(UINT32) +
    339                sizeof(EFI_IMAGE_FILE_HEADER) +
    340                Hdr.Pe32->FileHeader.SizeOfOptionalHeader
    341                );
    342   for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
    343     Pos = Index;
    344     while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {
    345       CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof(EFI_IMAGE_SECTION_HEADER));
    346       Pos--;
    347     }
    348     CopyMem (&SectionHeader[Pos], Section, sizeof(EFI_IMAGE_SECTION_HEADER));
    349     Section += 1;
    350   }
    351 
    352   //
    353   // 13.  Walk through the sorted table, bring the corresponding section
    354   //      into memory, and hash the entire section (using the 'SizeOfRawData'
    355   //      field in the section header to determine the amount of data to hash).
    356   // 14.  Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .
    357   // 15.  Repeat steps 13 and 14 for all the sections in the sorted table.
    358   //
    359   for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
    360     Section  = (EFI_IMAGE_SECTION_HEADER *) &SectionHeader[Index];
    361     if (Section->SizeOfRawData == 0) {
    362       continue;
    363     }
    364     HashBase = (UINT8 *) (UINTN) ImageAddress + Section->PointerToRawData;
    365     HashSize = (UINTN) Section->SizeOfRawData;
    366 
    367     Status = HashUpdate (HashHandle, HashBase, HashSize);
    368     if (EFI_ERROR (Status)) {
    369       goto Finish;
    370     }
    371 
    372     SumOfBytesHashed += HashSize;
    373   }
    374 
    375   //
    376   // 16.  If the file size is greater than SUM_OF_BYTES_HASHED, there is extra
    377   //      data in the file that needs to be added to the hash. This data begins
    378   //      at file offset SUM_OF_BYTES_HASHED and its length is:
    379   //             FileSize  -  (CertDirectory->Size)
    380   //
    381   if (ImageSize > SumOfBytesHashed) {
    382     HashBase = (UINT8 *) (UINTN) ImageAddress + SumOfBytesHashed;
    383 
    384     if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
    385       CertSize = 0;
    386     } else {
    387       if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    388         //
    389         // Use PE32 offset.
    390         //
    391         CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
    392       } else {
    393         //
    394         // Use PE32+ offset.
    395         //
    396         CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
    397       }
    398     }
    399 
    400     if (ImageSize > CertSize + SumOfBytesHashed) {
    401       HashSize = (UINTN) (ImageSize - CertSize - SumOfBytesHashed);
    402 
    403       Status = HashUpdate (HashHandle, HashBase, HashSize);
    404       if (EFI_ERROR (Status)) {
    405         goto Finish;
    406       }
    407     } else if (ImageSize < CertSize + SumOfBytesHashed) {
    408       Status = EFI_UNSUPPORTED;
    409       goto Finish;
    410     }
    411   }
    412 
    413   //
    414   // 17.  Finalize the SHA hash.
    415   //
    416   Status = HashCompleteAndExtend (HashHandle, PCRIndex, NULL, 0, DigestList);
    417   if (EFI_ERROR (Status)) {
    418     goto Finish;
    419   }
    420 
    421 Finish:
    422   if (SectionHeader != NULL) {
    423     FreePool (SectionHeader);
    424   }
    425 
    426   return Status;
    427 }
    428