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, 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 /**
     33   Measure PE image into TPM log based on the authenticode image hashing in
     34   PE/COFF Specification 8.0 Appendix A.
     35 
     36   Caution: This function may receive untrusted input.
     37   PE/COFF image is external input, so this function will validate its data structure
     38   within this image buffer before use.
     39 
     40   @param[in]  PCRIndex       TPM PCR index
     41   @param[in]  ImageAddress   Start address of image buffer.
     42   @param[in]  ImageSize      Image size
     43   @param[out] DigestList     Digeest list of this image.
     44 
     45   @retval EFI_SUCCESS            Successfully measure image.
     46   @retval EFI_OUT_OF_RESOURCES   No enough resource to measure image.
     47   @retval other error value
     48 **/
     49 EFI_STATUS
     50 MeasurePeImageAndExtend (
     51   IN  UINT32                    PCRIndex,
     52   IN  EFI_PHYSICAL_ADDRESS      ImageAddress,
     53   IN  UINTN                     ImageSize,
     54   OUT TPML_DIGEST_VALUES        *DigestList
     55   )
     56 {
     57   EFI_STATUS                           Status;
     58   EFI_IMAGE_DOS_HEADER                 *DosHdr;
     59   UINT32                               PeCoffHeaderOffset;
     60   EFI_IMAGE_SECTION_HEADER             *Section;
     61   UINT8                                *HashBase;
     62   UINTN                                HashSize;
     63   UINTN                                SumOfBytesHashed;
     64   EFI_IMAGE_SECTION_HEADER             *SectionHeader;
     65   UINTN                                Index;
     66   UINTN                                Pos;
     67   UINT16                               Magic;
     68   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr;
     69   UINT32                               NumberOfRvaAndSizes;
     70   UINT32                               CertSize;
     71   HASH_HANDLE                          HashHandle;
     72 
     73   HashHandle = 0xFFFFFFFF; // Know bad value
     74 
     75   Status        = EFI_UNSUPPORTED;
     76   SectionHeader = NULL;
     77 
     78   //
     79   // Check PE/COFF image
     80   //
     81   DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;
     82   PeCoffHeaderOffset = 0;
     83   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
     84     PeCoffHeaderOffset = DosHdr->e_lfanew;
     85   }
     86 
     87   Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);
     88   if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
     89     Status = EFI_UNSUPPORTED;
     90     goto Finish;
     91   }
     92 
     93   //
     94   // PE/COFF Image Measurement
     95   //
     96   //    NOTE: The following codes/steps are based upon the authenticode image hashing in
     97   //      PE/COFF Specification 8.0 Appendix A.
     98   //
     99   //
    100 
    101   // 1.  Load the image header into memory.
    102 
    103   // 2.  Initialize a SHA hash context.
    104 
    105   Status = HashStart (&HashHandle);
    106   if (EFI_ERROR (Status)) {
    107     goto Finish;
    108   }
    109 
    110   //
    111   // Measuring PE/COFF Image Header;
    112   // But CheckSum field and SECURITY data directory (certificate) are excluded
    113   //
    114   if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    115     //
    116     // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
    117     //       in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
    118     //       Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
    119     //       then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
    120     //
    121     Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
    122   } else {
    123     //
    124     // Get the magic value from the PE/COFF Optional Header
    125     //
    126     Magic = Hdr.Pe32->OptionalHeader.Magic;
    127   }
    128 
    129   //
    130   // 3.  Calculate the distance from the base of the image header to the image checksum address.
    131   // 4.  Hash the image header from its base to beginning of the image checksum.
    132   //
    133   HashBase = (UINT8 *) (UINTN) ImageAddress;
    134   if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    135     //
    136     // Use PE32 offset
    137     //
    138     NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
    139     HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.CheckSum) - HashBase);
    140   } else {
    141     //
    142     // Use PE32+ offset
    143     //
    144     NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
    145     HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.CheckSum) - HashBase);
    146   }
    147 
    148   Status = HashUpdate (HashHandle, HashBase, HashSize);
    149   if (EFI_ERROR (Status)) {
    150     goto Finish;
    151   }
    152 
    153   //
    154   // 5.  Skip over the image checksum (it occupies a single ULONG).
    155   //
    156   if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
    157     //
    158     // 6.  Since there is no Cert Directory in optional header, hash everything
    159     //     from the end of the checksum to the end of image header.
    160     //
    161     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    162       //
    163       // Use PE32 offset.
    164       //
    165       HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
    166       HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
    167     } else {
    168       //
    169       // Use PE32+ offset.
    170       //
    171       HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
    172       HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
    173     }
    174 
    175     if (HashSize != 0) {
    176       Status  = HashUpdate (HashHandle, HashBase, HashSize);
    177       if (EFI_ERROR (Status)) {
    178         goto Finish;
    179       }
    180     }
    181   } else {
    182     //
    183     // 7.  Hash everything from the end of the checksum to the start of the Cert Directory.
    184     //
    185     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    186       //
    187       // Use PE32 offset
    188       //
    189       HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
    190       HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
    191     } else {
    192       //
    193       // Use PE32+ offset
    194       //
    195       HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
    196       HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
    197     }
    198 
    199     if (HashSize != 0) {
    200       Status  = HashUpdate (HashHandle, HashBase, HashSize);
    201       if (EFI_ERROR (Status)) {
    202         goto Finish;
    203       }
    204     }
    205 
    206     //
    207     // 8.  Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)
    208     // 9.  Hash everything from the end of the Cert Directory to the end of image header.
    209     //
    210     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    211       //
    212       // Use PE32 offset
    213       //
    214       HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
    215       HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
    216     } else {
    217       //
    218       // Use PE32+ offset
    219       //
    220       HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
    221       HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
    222     }
    223 
    224     if (HashSize != 0) {
    225       Status  = HashUpdate (HashHandle, HashBase, HashSize);
    226       if (EFI_ERROR (Status)) {
    227         goto Finish;
    228       }
    229     }
    230   }
    231 
    232   //
    233   // 10. Set the SUM_OF_BYTES_HASHED to the size of the header
    234   //
    235   if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    236     //
    237     // Use PE32 offset
    238     //
    239     SumOfBytesHashed = Hdr.Pe32->OptionalHeader.SizeOfHeaders;
    240   } else {
    241     //
    242     // Use PE32+ offset
    243     //
    244     SumOfBytesHashed = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;
    245   }
    246 
    247   //
    248   // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER
    249   //     structures in the image. The 'NumberOfSections' field of the image
    250   //     header indicates how big the table should be. Do not include any
    251   //     IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.
    252   //
    253   SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections);
    254   if (SectionHeader == NULL) {
    255     Status = EFI_OUT_OF_RESOURCES;
    256     goto Finish;
    257   }
    258 
    259   //
    260   // 12.  Using the 'PointerToRawData' in the referenced section headers as
    261   //      a key, arrange the elements in the table in ascending order. In other
    262   //      words, sort the section headers according to the disk-file offset of
    263   //      the section.
    264   //
    265   Section = (EFI_IMAGE_SECTION_HEADER *) (
    266                (UINT8 *) (UINTN) ImageAddress +
    267                PeCoffHeaderOffset +
    268                sizeof(UINT32) +
    269                sizeof(EFI_IMAGE_FILE_HEADER) +
    270                Hdr.Pe32->FileHeader.SizeOfOptionalHeader
    271                );
    272   for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
    273     Pos = Index;
    274     while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {
    275       CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof(EFI_IMAGE_SECTION_HEADER));
    276       Pos--;
    277     }
    278     CopyMem (&SectionHeader[Pos], Section, sizeof(EFI_IMAGE_SECTION_HEADER));
    279     Section += 1;
    280   }
    281 
    282   //
    283   // 13.  Walk through the sorted table, bring the corresponding section
    284   //      into memory, and hash the entire section (using the 'SizeOfRawData'
    285   //      field in the section header to determine the amount of data to hash).
    286   // 14.  Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .
    287   // 15.  Repeat steps 13 and 14 for all the sections in the sorted table.
    288   //
    289   for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
    290     Section  = (EFI_IMAGE_SECTION_HEADER *) &SectionHeader[Index];
    291     if (Section->SizeOfRawData == 0) {
    292       continue;
    293     }
    294     HashBase = (UINT8 *) (UINTN) ImageAddress + Section->PointerToRawData;
    295     HashSize = (UINTN) Section->SizeOfRawData;
    296 
    297     Status = HashUpdate (HashHandle, HashBase, HashSize);
    298     if (EFI_ERROR (Status)) {
    299       goto Finish;
    300     }
    301 
    302     SumOfBytesHashed += HashSize;
    303   }
    304 
    305   //
    306   // 16.  If the file size is greater than SUM_OF_BYTES_HASHED, there is extra
    307   //      data in the file that needs to be added to the hash. This data begins
    308   //      at file offset SUM_OF_BYTES_HASHED and its length is:
    309   //             FileSize  -  (CertDirectory->Size)
    310   //
    311   if (ImageSize > SumOfBytesHashed) {
    312     HashBase = (UINT8 *) (UINTN) ImageAddress + SumOfBytesHashed;
    313 
    314     if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
    315       CertSize = 0;
    316     } else {
    317       if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    318         //
    319         // Use PE32 offset.
    320         //
    321         CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
    322       } else {
    323         //
    324         // Use PE32+ offset.
    325         //
    326         CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
    327       }
    328     }
    329 
    330     if (ImageSize > CertSize + SumOfBytesHashed) {
    331       HashSize = (UINTN) (ImageSize - CertSize - SumOfBytesHashed);
    332 
    333       Status = HashUpdate (HashHandle, HashBase, HashSize);
    334       if (EFI_ERROR (Status)) {
    335         goto Finish;
    336       }
    337     } else if (ImageSize < CertSize + SumOfBytesHashed) {
    338       Status = EFI_UNSUPPORTED;
    339       goto Finish;
    340     }
    341   }
    342 
    343   //
    344   // 17.  Finalize the SHA hash.
    345   //
    346   Status = HashCompleteAndExtend (HashHandle, PCRIndex, NULL, 0, DigestList);
    347   if (EFI_ERROR (Status)) {
    348     goto Finish;
    349   }
    350 
    351 Finish:
    352   if (SectionHeader != NULL) {
    353     FreePool (SectionHeader);
    354   }
    355 
    356   return Status;
    357 }
    358