]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c
Enhance GPT measurement to be able to handle different partition entry size.
[mirror_edk2.git] / SecurityPkg / Library / DxeTpmMeasureBootLib / DxeTpmMeasureBootLib.c
index c012f130d98d0e0d860b09948f0209a10b1c9080..803c7876a5777889b5afc5326d3bacb98d4f9c4c 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   The library instance provides security service of TPM measure boot.  \r
 \r
-Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials \r
 are licensed and made available under the terms and conditions of the BSD License \r
 which accompanies this distribution.  The full text of the license may be found at \r
@@ -36,6 +36,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 BOOLEAN                           mMeasureGptTableFlag = FALSE;\r
 EFI_GUID                          mZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};\r
 UINTN                             mMeasureGptCount = 0;\r
+VOID                              *mFileBuffer;\r
+UINTN                             mImageSize;\r
 \r
 /**\r
   Reads contents of a PE/COFF image in memory buffer.\r
@@ -50,14 +52,34 @@ UINTN                             mMeasureGptCount = 0;
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-ImageRead (\r
+DxeTpmMeasureBootLibImageRead (\r
   IN     VOID    *FileHandle,\r
   IN     UINTN   FileOffset,\r
   IN OUT UINTN   *ReadSize,\r
   OUT    VOID    *Buffer\r
   )\r
 {\r
+  UINTN               EndPosition;\r
+\r
+  if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (MAX_ADDRESS - FileOffset < *ReadSize) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  EndPosition = FileOffset + *ReadSize;\r
+  if (EndPosition > mImageSize) {\r
+    *ReadSize = (UINT32)(mImageSize - FileOffset);\r
+  }\r
+\r
+  if (FileOffset >= mImageSize) {\r
+    *ReadSize = 0;\r
+  }\r
+\r
   CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);\r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -155,15 +177,15 @@ TcgMeasureGptTable (
     if (!CompareGuid (&PartitionEntry->PartitionTypeGUID, &mZeroGuid)) {\r
       NumberOfPartition++;  \r
     }\r
-    PartitionEntry++;\r
+    PartitionEntry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry);\r
   }\r
 \r
   //\r
-  // Parepare Data for Measurement\r
+  // Prepare Data for Measurement\r
   // \r
   EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) \r
                         + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry);\r
-  TcgEvent = (TCG_PCR_EVENT *) AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT));\r
+  TcgEvent = (TCG_PCR_EVENT *) AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT_HDR));\r
   if (TcgEvent == NULL) {\r
     FreePool (PrimaryHeader);\r
     FreePool (EntryPtr);\r
@@ -188,13 +210,13 @@ TcgMeasureGptTable (
   for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {\r
     if (!CompareGuid (&PartitionEntry->PartitionTypeGUID, &mZeroGuid)) {\r
       CopyMem (\r
-        (UINT8 *)&GptData->Partitions + NumberOfPartition * sizeof (EFI_PARTITION_ENTRY),\r
+        (UINT8 *)&GptData->Partitions + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry,\r
         (UINT8 *)PartitionEntry,\r
-        sizeof (EFI_PARTITION_ENTRY)\r
+        PrimaryHeader->SizeOfPartitionEntry\r
         );\r
       NumberOfPartition++;\r
     }\r
-    PartitionEntry++;\r
+    PartitionEntry =(EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry);\r
   }\r
 \r
   //\r
@@ -234,7 +256,9 @@ TcgMeasureGptTable (
 \r
   @retval EFI_SUCCESS            Successfully measure image.\r
   @retval EFI_OUT_OF_RESOURCES   No enough resource to measure image.\r
+  @retval EFI_UNSUPPORTED        ImageType is unsupported or PE image is mal-format.  \r
   @retval other error value\r
+\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
@@ -247,27 +271,31 @@ TcgMeasurePeImage (
   IN  EFI_DEVICE_PATH_PROTOCOL  *FilePath\r
   )\r
 {\r
-  EFI_STATUS                        Status;\r
-  TCG_PCR_EVENT                     *TcgEvent;\r
-  EFI_IMAGE_LOAD_EVENT              *ImageLoad;\r
-  UINT32                            FilePathSize;\r
-  VOID                              *Sha1Ctx;\r
-  UINTN                             CtxSize;\r
-  EFI_IMAGE_DOS_HEADER              *DosHdr;\r
-  UINT32                            PeCoffHeaderOffset;\r
-  EFI_IMAGE_SECTION_HEADER          *Section;\r
-  UINT8                             *HashBase;\r
-  UINTN                             HashSize;\r
-  UINTN                             SumOfBytesHashed;\r
-  EFI_IMAGE_SECTION_HEADER          *SectionHeader;\r
-  UINTN                             Index, Pos;\r
-  UINT16                            Magic;\r
-  UINT32                            EventSize;\r
-  UINT32                            EventNumber;\r
-  EFI_PHYSICAL_ADDRESS              EventLogLastEntry;\r
+  EFI_STATUS                           Status;\r
+  TCG_PCR_EVENT                        *TcgEvent;\r
+  EFI_IMAGE_LOAD_EVENT                 *ImageLoad;\r
+  UINT32                               FilePathSize;\r
+  VOID                                 *Sha1Ctx;\r
+  UINTN                                CtxSize;\r
+  EFI_IMAGE_DOS_HEADER                 *DosHdr;\r
+  UINT32                               PeCoffHeaderOffset;\r
+  EFI_IMAGE_SECTION_HEADER             *Section;\r
+  UINT8                                *HashBase;\r
+  UINTN                                HashSize;\r
+  UINTN                                SumOfBytesHashed;\r
+  EFI_IMAGE_SECTION_HEADER             *SectionHeader;\r
+  UINTN                                Index;\r
+  UINTN                                Pos;\r
+  UINT16                               Magic;\r
+  UINT32                               EventSize;\r
+  UINT32                               EventNumber;\r
+  EFI_PHYSICAL_ADDRESS                 EventLogLastEntry;\r
   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr;\r
+  UINT32                               NumberOfRvaAndSizes;\r
+  BOOLEAN                              HashStatus;\r
+  UINT32                               CertSize;\r
 \r
-  Status        = EFI_SUCCESS;\r
+  Status        = EFI_UNSUPPORTED;\r
   ImageLoad     = NULL;\r
   SectionHeader = NULL;\r
   Sha1Ctx       = NULL;\r
@@ -304,9 +332,6 @@ TcgMeasurePeImage (
         "TcgMeasurePeImage: Unknown subsystem type %d",\r
         ImageType\r
         ));\r
-      ASSERT (FALSE);\r
-      TcgEvent->EventType = ImageType;\r
-      Status = EFI_UNSUPPORTED;\r
       goto Finish;\r
   }\r
 \r
@@ -324,8 +349,9 @@ TcgMeasurePeImage (
   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
     PeCoffHeaderOffset = DosHdr->e_lfanew;\r
   }\r
-  if (((EFI_TE_IMAGE_HEADER *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset))->Signature\r
-       == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
+\r
+  Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);\r
+  if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
     goto Finish;\r
   }\r
 \r
@@ -347,14 +373,16 @@ TcgMeasurePeImage (
     goto Finish;\r
   }\r
 \r
-  Sha1Init (Sha1Ctx);\r
+  HashStatus = Sha1Init (Sha1Ctx);\r
+  if (!HashStatus) {\r
+    goto Finish;\r
+  }\r
 \r
   //\r
   // Measuring PE/COFF Image Header;\r
   // But CheckSum field and SECURITY data directory (certificate) are excluded\r
   //\r
-  Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);\r
-  Magic    = Hdr.Pe32->OptionalHeader.Magic;\r
+  Magic = Hdr.Pe32->OptionalHeader.Magic;\r
   \r
   //\r
   // 3.  Calculate the distance from the base of the image header to the image checksum address.\r
@@ -365,58 +393,99 @@ TcgMeasurePeImage (
     //\r
     // Use PE32 offset\r
     //\r
+    NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
     HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.CheckSum) - HashBase);\r
   } else {\r
     //\r
     // Use PE32+ offset\r
     //\r
+    NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
     HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.CheckSum) - HashBase);\r
   }\r
 \r
-  Sha1Update (Sha1Ctx, HashBase, HashSize);\r
+  HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);\r
+  if (!HashStatus) {\r
+    goto Finish;\r
+  }  \r
 \r
   //\r
   // 5.  Skip over the image checksum (it occupies a single ULONG).\r
-  // 6.  Get the address of the beginning of the Cert Directory.\r
-  // 7.  Hash everything from the end of the checksum to the start of the Cert Directory.\r
   //\r
-  if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+  if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
     //\r
-    // Use PE32 offset\r
+    // 6.  Since there is no Cert Directory in optional header, hash everything\r
+    //     from the end of the checksum to the end of image header.\r
     //\r
-    HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
-    HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
+    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+      //\r
+      // Use PE32 offset.\r
+      //\r
+      HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
+      HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);\r
+    } else {\r
+      //\r
+      // Use PE32+ offset.\r
+      //\r
+      HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
+      HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);\r
+    }\r
+\r
+    if (HashSize != 0) {\r
+      HashStatus  = Sha1Update (Sha1Ctx, HashBase, HashSize);\r
+      if (!HashStatus) {\r
+        goto Finish;\r
+      }\r
+    }    \r
   } else {\r
     //\r
-    // Use PE32+ offset\r
-    //    \r
-    HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
-    HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
-  }\r
+    // 7.  Hash everything from the end of the checksum to the start of the Cert Directory.\r
+    //\r
+    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+      //\r
+      // Use PE32 offset\r
+      //\r
+      HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
+      HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
+    } else {\r
+      //\r
+      // Use PE32+ offset\r
+      //    \r
+      HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
+      HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
+    }\r
 \r
-  Sha1Update (Sha1Ctx, HashBase, HashSize);\r
+    if (HashSize != 0) {\r
+      HashStatus  = Sha1Update (Sha1Ctx, HashBase, HashSize);\r
+      if (!HashStatus) {\r
+        goto Finish;\r
+      }\r
+    }\r
 \r
-  //\r
-  // 8.  Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)\r
-  // 9.  Hash everything from the end of the Cert Directory to the end of image header.\r
-  //\r
-  if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
-    //\r
-    // Use PE32 offset\r
     //\r
-    HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
-    HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders -\r
-             (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINT8 *) (UINTN) ImageAddress);\r
-  } else {\r
-    //\r
-    // Use PE32+ offset\r
+    // 8.  Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)\r
+    // 9.  Hash everything from the end of the Cert Directory to the end of image header.\r
     //\r
-    HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
-    HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders -\r
-             (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINT8 *) (UINTN) ImageAddress);\r
+    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+      //\r
+      // Use PE32 offset\r
+      //\r
+      HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
+      HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);\r
+    } else {\r
+      //\r
+      // Use PE32+ offset\r
+      //\r
+      HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
+      HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);\r
+    }\r
+    \r
+    if (HashSize != 0) {\r
+      HashStatus  = Sha1Update (Sha1Ctx, HashBase, HashSize);\r
+      if (!HashStatus) {\r
+        goto Finish;\r
+      }\r
+    }\r
   }\r
-  \r
-  Sha1Update (Sha1Ctx, HashBase, HashSize);\r
 \r
   //\r
   // 10. Set the SUM_OF_BYTES_HASHED to the size of the header\r
@@ -439,7 +508,7 @@ TcgMeasurePeImage (
   //     header indicates how big the table should be. Do not include any\r
   //     IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.\r
   //\r
-  SectionHeader = (EFI_IMAGE_SECTION_HEADER *)AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections);\r
+  SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections);\r
   if (SectionHeader == NULL) {\r
     Status = EFI_OUT_OF_RESOURCES;\r
     goto Finish;\r
@@ -483,7 +552,10 @@ TcgMeasurePeImage (
     HashBase = (UINT8 *) (UINTN) ImageAddress + Section->PointerToRawData;\r
     HashSize = (UINTN) Section->SizeOfRawData;\r
 \r
-    Sha1Update (Sha1Ctx, HashBase, HashSize);\r
+    HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);\r
+    if (!HashStatus) {\r
+      goto Finish;\r
+    }\r
 \r
     SumOfBytesHashed += HashSize;\r
   }\r
@@ -496,29 +568,42 @@ TcgMeasurePeImage (
   //\r
   if (ImageSize > SumOfBytesHashed) {\r
     HashBase = (UINT8 *) (UINTN) ImageAddress + SumOfBytesHashed;\r
-    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
-      //\r
-      // Use PE32 offset\r
-      //\r
-      HashSize = (UINTN)(ImageSize -\r
-                 Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -\r
-                 SumOfBytesHashed);\r
+\r
+    if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
+      CertSize = 0;\r
     } else {\r
-      //\r
-      // Use PE32+ offset\r
-      //\r
-      HashSize = (UINTN)(ImageSize -\r
-                 Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -\r
-                 SumOfBytesHashed);      \r
+      if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+        //\r
+        // Use PE32 offset.\r
+        //\r
+        CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;\r
+      } else {\r
+        //\r
+        // Use PE32+ offset.\r
+        //\r
+        CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;\r
+      }\r
     }\r
 \r
-    Sha1Update (Sha1Ctx, HashBase, HashSize);\r
+    if (ImageSize > CertSize + SumOfBytesHashed) {\r
+      HashSize = (UINTN) (ImageSize - CertSize - SumOfBytesHashed);\r
+\r
+      HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);\r
+      if (!HashStatus) {\r
+        goto Finish;\r
+      }\r
+    } else if (ImageSize < CertSize + SumOfBytesHashed) {\r
+      goto Finish;\r
+    }\r
   }\r
 \r
   //\r
   // 17.  Finalize the SHA hash.\r
   //\r
-  Sha1Final (Sha1Ctx, (UINT8 *)&TcgEvent->Digest);\r
+  HashStatus = Sha1Final (Sha1Ctx, (UINT8 *) &TcgEvent->Digest);\r
+  if (!HashStatus) {\r
+    goto Finish;\r
+  }\r
 \r
   //\r
   // Log the PE data\r
@@ -737,13 +822,16 @@ DxeTpmMeasureBootHandler (
     goto Finish;\r
   }\r
 \r
+  mImageSize  = FileSize;\r
+  mFileBuffer = FileBuffer;\r
+\r
   //\r
   // Measure PE Image\r
   //\r
   DevicePathNode = OrigDevicePathNode;\r
   ZeroMem (&ImageContext, sizeof (ImageContext));\r
   ImageContext.Handle    = (VOID *) FileBuffer;\r
-  ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) ImageRead;\r
+  ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeTpmMeasureBootLibImageRead;\r
 \r
   //\r
   // Get information about the image being loaded\r