]> 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 d3c7bfec627cc9a970e55b40e6dd7e8bbd9ae835..803c7876a5777889b5afc5326d3bacb98d4f9c4c 100644 (file)
@@ -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,7 +332,6 @@ TcgMeasurePeImage (
         "TcgMeasurePeImage: Unknown subsystem type %d",\r
         ImageType\r
         ));\r
-      Status = EFI_UNSUPPORTED;\r
       goto Finish;\r
   }\r
 \r
@@ -322,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
@@ -345,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
@@ -363,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
@@ -437,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
@@ -481,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
@@ -494,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
@@ -735,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