]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
Enhances PE image hash algorithm in DxeImageVerificationLib and DxeTpmMeasureBootLib.
[mirror_edk2.git] / SecurityPkg / Library / DxeImageVerificationLib / DxeImageVerificationLib.c
index 14cd2d73b4c1600a09813b497154f7ab44908c33..a591970e45cceefeac06dfb6b75e942f601f47e9 100644 (file)
@@ -253,6 +253,8 @@ HashPeImage (
   UINTN                     Pos;\r
   UINTN                     SumOfSectionBytes;\r
   EFI_IMAGE_SECTION_HEADER  *SectionCache;\r
+  UINT32                    CertSize;\r
+  UINT32                    NumberOfRvaAndSizes;\r
 \r
   HashCtx       = NULL;\r
   SectionHeader = NULL;\r
@@ -292,6 +294,7 @@ HashPeImage (
   if (!Status) {\r
     goto Done;\r
   }\r
+\r
   //\r
   // Measuring PE/COFF Image Header;\r
   // But CheckSum field and SECURITY data directory (certificate) are excluded\r
@@ -307,11 +310,13 @@ HashPeImage (
     // Use PE32 offset.\r
     //\r
     HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.CheckSum) - HashBase);\r
+    NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
   } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
     //\r
     // Use PE32+ offset.\r
     //\r
     HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - HashBase);\r
+    NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
   } else {\r
     //\r
     // Invalid header magic number.\r
@@ -324,51 +329,86 @@ HashPeImage (
   if (!Status) {\r
     goto Done;\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 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
-    HashSize = (UINTN) ((UINT8 *) (&mNtHeader.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 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
+      HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - mImageBase);\r
+    } else {\r
+      //\r
+      // Use PE32+ offset.\r
+      //\r
+      HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
+      HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - mImageBase);\r
+    }\r
+\r
+    if (HashSize != 0) {\r
+      Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
+      if (!Status) {\r
+        goto Done;\r
+      }\r
+    }\r
   } else {\r
     //\r
-    // Use PE32+ offset.\r
+    // 7.  Hash everything from the end of the checksum to the start of the Cert Directory.\r
     //\r
-    HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
-    HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
-  }\r
+    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+      //\r
+      // Use PE32 offset.\r
+      //\r
+      HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
+      HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
+    } else {\r
+      //\r
+      // Use PE32+ offset.\r
+      //\r
+      HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
+      HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
+    }\r
+\r
+    if (HashSize != 0) {\r
+      Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
+      if (!Status) {\r
+        goto Done;\r
+      }\r
+    }\r
 \r
-  Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
-  if (!Status) {\r
-    goto Done;\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 *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
-    HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - mImageBase);\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 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
-    HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - mImageBase);\r
-  }\r
+    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+      //\r
+      // Use PE32 offset\r
+      //\r
+      HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
+      HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - mImageBase);\r
+    } else {\r
+      //\r
+      // Use PE32+ offset.\r
+      //\r
+      HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
+      HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - mImageBase);\r
+    }\r
 \r
-  Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
-  if (!Status) {\r
-    goto Done;\r
+    if (HashSize != 0) {\r
+      Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
+      if (!Status) {\r
+        goto Done;\r
+      }\r
+    }    \r
   }\r
+\r
   //\r
   // 10. Set the SUM_OF_BYTES_HASHED to the size of the header.\r
   //\r
@@ -398,15 +438,6 @@ HashPeImage (
     SumOfSectionBytes += SectionCache->SizeOfRawData;\r
   }\r
 \r
-  //\r
-  // Sanity check for file corruption. Sections raw data size should be smaller\r
-  // than Image Size.\r
-  //\r
-  if (SumOfSectionBytes >= mImageSize) {\r
-    Status = FALSE;\r
-    goto Done;\r
-  }\r
-\r
   //\r
   // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER\r
   //     structures in the image. The 'NumberOfSections' field of the image\r
@@ -465,37 +496,36 @@ HashPeImage (
   //\r
   if (mImageSize > SumOfBytesHashed) {\r
     HashBase = mImageBase + SumOfBytesHashed;\r
-    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
-      if (mImageSize - SumOfBytesHashed < mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {\r
-        Status = FALSE;\r
-        goto Done;\r
-      }\r
-      //\r
-      // Use PE32 offset.\r
-      //\r
-      HashSize = (UINTN)(\r
-                 mImageSize -\r
-                 mNtHeader.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
-      if (mImageSize - SumOfBytesHashed < mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {\r
-        Status = FALSE;\r
-        goto Done;\r
+      if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+        //\r
+        // Use PE32 offset.\r
+        //\r
+        CertSize = mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;\r
+      } else {\r
+        //\r
+        // Use PE32+ offset.\r
+        //\r
+        CertSize = mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;\r
       }\r
-      //\r
-      // Use PE32+ offset.\r
-      //\r
-      HashSize = (UINTN)(\r
-                 mImageSize -\r
-                 mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -\r
-                 SumOfBytesHashed);\r
     }\r
 \r
-    Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
-    if (!Status) {\r
+    if (mImageSize > CertSize + SumOfBytesHashed) {\r
+      HashSize = (UINTN) (mImageSize - CertSize - SumOfBytesHashed);\r
+\r
+      Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
+      if (!Status) {\r
+        goto Done;\r
+      }\r
+    } else if (mImageSize < CertSize + SumOfBytesHashed) {\r
+      Status = FALSE;\r
       goto Done;\r
     }\r
   }\r
+\r
   Status  = mHash[HashAlg].HashFinal(HashCtx, mImageDigest);\r
 \r
 Done:\r
@@ -1170,19 +1200,20 @@ DxeImageVerificationHandler (
   IN  UINTN                            FileSize\r
   )\r
 {\r
-  EFI_STATUS                  Status;\r
-  UINT16                      Magic;\r
-  EFI_IMAGE_DOS_HEADER        *DosHdr;\r
-  EFI_STATUS                  VerifyStatus;\r
-  UINT8                       *SetupMode;\r
-  EFI_SIGNATURE_LIST          *SignatureList;\r
-  UINTN                       SignatureListSize;\r
-  EFI_SIGNATURE_DATA          *Signature;\r
-  EFI_IMAGE_EXECUTION_ACTION  Action;\r
-  WIN_CERTIFICATE             *WinCertificate;\r
-  UINT32                      Policy;\r
-  UINT8                       *SecureBootEnable;\r
-  PE_COFF_LOADER_IMAGE_CONTEXT      ImageContext;\r
+  EFI_STATUS                           Status;\r
+  UINT16                               Magic;\r
+  EFI_IMAGE_DOS_HEADER                 *DosHdr;\r
+  EFI_STATUS                           VerifyStatus;\r
+  UINT8                                *SetupMode;\r
+  EFI_SIGNATURE_LIST                   *SignatureList;\r
+  UINTN                                SignatureListSize;\r
+  EFI_SIGNATURE_DATA                   *Signature;\r
+  EFI_IMAGE_EXECUTION_ACTION           Action;\r
+  WIN_CERTIFICATE                      *WinCertificate;\r
+  UINT32                               Policy;\r
+  UINT8                                *SecureBootEnable;\r
+  PE_COFF_LOADER_IMAGE_CONTEXT         ImageContext;\r
+  UINT32                               NumberOfRvaAndSizes;\r
 \r
   if (File == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -1243,6 +1274,8 @@ DxeImageVerificationHandler (
     return EFI_SUCCESS;\r
   }\r
 \r
+  FreePool (SecureBootEnable);\r
+\r
   SetupMode = GetEfiGlobalVariable (EFI_SETUP_MODE_NAME);\r
 \r
   //\r
@@ -1260,13 +1293,16 @@ DxeImageVerificationHandler (
     FreePool (SetupMode);\r
     return EFI_SUCCESS;\r
   }\r
+\r
+  FreePool (SetupMode);\r
+\r
   //\r
   // Read the Dos header.\r
   //\r
   if (FileBuffer == NULL) {\r
-    FreePool (SetupMode);\r
     return EFI_INVALID_PARAMETER;\r
   }\r
+\r
   mImageBase  = (UINT8 *) FileBuffer;\r
   mImageSize  = FileSize;\r
 \r
@@ -1303,7 +1339,8 @@ DxeImageVerificationHandler (
     //\r
     // It is not a valid Pe/Coff file.\r
     //\r
-    return EFI_ACCESS_DENIED;\r
+    Status = EFI_ACCESS_DENIED;\r
+    goto Done;\r
   }\r
 \r
   Magic = mNtHeader.Pe32->OptionalHeader.Magic;\r
@@ -1311,29 +1348,21 @@ DxeImageVerificationHandler (
     //\r
     // Use PE32 offset.\r
     //\r
-    mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r
-  } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
-    //\r
-    // Use PE32+ offset.\r
-    //\r
-    mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r
+    NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
+    if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
+      mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r
+    }        \r
   } else {\r
     //\r
-    // Invalid header magic number.\r
-    //\r
-    Status       = EFI_INVALID_PARAMETER;\r
-    goto Done;\r
-  }\r
-\r
-  if (mSecDataDir->VirtualAddress >= mImageSize) {\r
-    //\r
-    // Sanity check to see if this file is corrupted.\r
+    // Use PE32+ offset.\r
     //\r
-    Status       = EFI_INVALID_PARAMETER;\r
-    goto Done;\r
+    NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
+    if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
+      mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r
+    }\r
   }\r
 \r
-  if (mSecDataDir->Size == 0) {\r
+  if ((mSecDataDir == NULL) || ((mSecDataDir != NULL) && (mSecDataDir->Size == 0))) {\r
     //\r
     // This image is not signed.\r
     //\r
@@ -1474,8 +1503,6 @@ Done:
     FreePool (SignatureList);\r
   }\r
 \r
-  FreePool (SetupMode);\r
-\r
   return Status;\r
 }\r
 \r