]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
OvmfPkg: Add custom SecureBootConfigDxe that doesn't reset
[mirror_edk2.git] / SecurityPkg / Library / DxeImageVerificationLib / DxeImageVerificationLib.c
index 3e0bbe1ee4c771092fc4c9afc898ab0ffa629128..f83e530c5c52f6d0b82774fae8eaa28c038ae3ad 100644 (file)
@@ -1,6 +1,17 @@
 /** @file\r
   Implement image verification services for secure boot service in UEFI2.3.1.\r
 \r
+  Caution: This file requires additional review when modified.\r
+  This library will have external input - PE/COFF image.\r
+  This external input must be validated carefully to avoid security issue like\r
+  buffer overflow, integer overflow.\r
+\r
+  DxeImageVerificationLibImageRead() function will make sure the PE/COFF image content\r
+  read is within the image buffer.\r
+\r
+  DxeImageVerificationHandler(), HashPeImageByType(), HashPeImage() function will accept\r
+  untrusted PE/COFF image and validate its data structure within this image buffer before use.\r
+\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
@@ -14,15 +25,23 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 #include "DxeImageVerificationLib.h"\r
 \r
+//\r
+// Caution: This is used by a function which may receive untrusted input.\r
+// These global variables hold PE/COFF image data, and they should be validated before use.\r
+//\r
 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader;\r
-UINTN                               mImageSize;\r
 UINT32                              mPeCoffHeaderOffset;\r
-UINT8                               mImageDigest[MAX_DIGEST_SIZE];\r
-UINTN                               mImageDigestSize;\r
 EFI_IMAGE_DATA_DIRECTORY            *mSecDataDir      = NULL;\r
-UINT8                               *mImageBase       = NULL;\r
 EFI_GUID                            mCertType;\r
 \r
+//\r
+// Information on current PE/COFF image\r
+//\r
+UINTN                               mImageSize;\r
+UINT8                               *mImageBase       = NULL;\r
+UINT8                               mImageDigest[MAX_DIGEST_SIZE];\r
+UINTN                               mImageDigestSize;\r
+\r
 //\r
 // Notify string for authorization UI.\r
 //\r
@@ -57,6 +76,10 @@ HASH_TABLE mHash[] = {
 /**\r
   Reads contents of a PE/COFF image in memory buffer.\r
 \r
+  Caution: This function may receive untrusted input.\r
+  PE/COFF image is external input, so this function will make sure the PE/COFF image content\r
+  read is within the image buffer.\r
+\r
   @param  FileHandle      Pointer to the file handle to read the PE/COFF image.\r
   @param  FileOffset      Offset into the PE/COFF image to begin the read operation.\r
   @param  ReadSize        On input, the size in bytes of the requested read operation.  \r
@@ -229,6 +252,10 @@ GetImageType (
   Caculate hash of Pe/Coff image based on the authenticode image hashing in\r
   PE/COFF Specification 8.0 Appendix A\r
 \r
+  Caution: This function may receive untrusted input.\r
+  PE/COFF image is external input, so this function will validate its data structure\r
+  within this image buffer before use.\r
+\r
   @param[in]    HashAlg   Hash algorithm type.\r
 \r
   @retval TRUE            Successfully hash image.\r
@@ -297,7 +324,21 @@ HashPeImage (
   // Measuring PE/COFF Image Header;\r
   // But CheckSum field and SECURITY data directory (certificate) are excluded\r
   //\r
-  Magic = mNtHeader.Pe32->OptionalHeader.Magic;\r
+  if (mNtHeader.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+    //\r
+    // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value \r
+    //       in the PE/COFF Header. If the MachineType is Itanium(IA64) and the \r
+    //       Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
+    //       then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
+    //\r
+    Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
+  } else {\r
+    //\r
+    // Get the magic value from the PE/COFF Optional Header\r
+    //\r
+    Magic =  mNtHeader.Pe32->OptionalHeader.Magic;\r
+  }\r
+  \r
   //\r
   // 3.  Calculate the distance from the base of the image header to the image checksum address.\r
   // 4.  Hash the image header from its base to beginning of the image checksum.\r
@@ -536,6 +577,10 @@ Done:
   Pe/Coff image based on the authenticode image hashing in PE/COFF Specification\r
   8.0 Appendix A\r
 \r
+  Caution: This function may receive untrusted input.\r
+  PE/COFF image is external input, so this function will validate its data structure\r
+  within this image buffer before use.\r
+\r
   @retval EFI_UNSUPPORTED             Hash algorithm is not supported.\r
   @retval EFI_SUCCESS                 Hash successfully.\r
 \r
@@ -939,14 +984,14 @@ IsPkcsSignedDataVerifiedBySignatureList (
           // Iterate each Signature Data Node within this CertList for verify.\r
           //\r
           RootCert      = Cert->SignatureData;\r
-          RootCertSize  = CertList->SignatureSize;\r
+          RootCertSize  = CertList->SignatureSize - sizeof (EFI_GUID);\r
 \r
           //\r
           // Call AuthenticodeVerify library to Verify Authenticode struct.\r
           //\r
           VerifyStatus = AuthenticodeVerify (\r
                            PkcsCertData->CertData,\r
-                           mSecDataDir->Size - sizeof(PkcsCertData->Hdr),\r
+                           PkcsCertData->Hdr.dwLength - sizeof(PkcsCertData->Hdr),\r
                            RootCert,\r
                            RootCertSize,\r
                            mImageDigest,\r
@@ -1065,7 +1110,7 @@ VerifyCertUefiGuid (
   //\r
   // Get KEK database variable.\r
   //\r
-  KekList = GetEfiGlobalVariable (EFI_KEY_EXCHANGE_KEY_NAME);\r
+  GetEfiGlobalVariable2 (EFI_KEY_EXCHANGE_KEY_NAME, (VOID**)&KekList, NULL);\r
   if (KekList == NULL) {\r
     return EFI_SECURITY_VIOLATION;\r
   }\r
@@ -1170,6 +1215,10 @@ Done:
           If no,\r
             Error out\r
 \r
+  Caution: This function may receive untrusted input.\r
+  PE/COFF image is external input, so this function will validate its data structure\r
+  within this image buffer before use.\r
+\r
   @param[in]    AuthenticationStatus\r
                            This is the authentication status returned from the security\r
                            measurement services for the input file.\r
@@ -1205,14 +1254,13 @@ DxeImageVerificationHandler (
   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
+  UINT8                                *SecureBoot;\r
   PE_COFF_LOADER_IMAGE_CONTEXT         ImageContext;\r
   UINT32                               NumberOfRvaAndSizes;\r
   UINT32                               CertSize;\r
@@ -1260,43 +1308,22 @@ DxeImageVerificationHandler (
     return EFI_ACCESS_DENIED;\r
   }\r
 \r
-  SecureBootEnable = GetVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid);\r
-  //\r
-  // Skip verification if SecureBootEnable variable doesn't exist.\r
-  //\r
-  if (SecureBootEnable == NULL) {\r
-    return EFI_SUCCESS;\r
-  }\r
-\r
+  GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&SecureBoot, NULL);\r
   //\r
-  // Skip verification if SecureBootEnable is disabled.\r
+  // Skip verification if SecureBoot variable doesn't exist.\r
   //\r
-  if (*SecureBootEnable == SECURE_BOOT_DISABLE) {\r
-    FreePool (SecureBootEnable);\r
+  if (SecureBoot == NULL) {\r
     return EFI_SUCCESS;\r
   }\r
 \r
-  FreePool (SecureBootEnable);\r
-\r
-  SetupMode = GetEfiGlobalVariable (EFI_SETUP_MODE_NAME);\r
-\r
   //\r
-  // SetupMode doesn't exist means no AuthVar driver is dispatched,\r
-  // skip verification.\r
+  // Skip verification if SecureBoot is disabled.\r
   //\r
-  if (SetupMode == NULL) {\r
+  if (*SecureBoot == SECURE_BOOT_MODE_DISABLE) {\r
+    FreePool (SecureBoot);\r
     return EFI_SUCCESS;\r
   }\r
-\r
-  //\r
-  // If platform is in SETUP MODE, skip verification.\r
-  //\r
-  if (*SetupMode == SETUP_MODE) {\r
-    FreePool (SetupMode);\r
-    return EFI_SUCCESS;\r
-  }\r
-\r
-  FreePool (SetupMode);\r
+  FreePool (SecureBoot);\r
 \r
   //\r
   // Read the Dos header.\r
@@ -1346,7 +1373,21 @@ DxeImageVerificationHandler (
     goto Done;\r
   }\r
 \r
-  Magic = mNtHeader.Pe32->OptionalHeader.Magic;\r
+  if (mNtHeader.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+    //\r
+    // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value \r
+    //       in the PE/COFF Header. If the MachineType is Itanium(IA64) and the \r
+    //       Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
+    //       then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
+    //\r
+    Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
+  } else {\r
+    //\r
+    // Get the magic value from the PE/COFF Optional Header\r
+    //\r
+    Magic = mNtHeader.Pe32->OptionalHeader.Magic;\r
+  }\r
+  \r
   if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
     //\r
     // Use PE32 offset.\r
@@ -1544,7 +1585,7 @@ VariableWriteCallBack (
   // If this library is built-in, it means firmware has capability to perform\r
   // driver signing verification.\r
   //\r
-  SecureBootModePtr = GetEfiGlobalVariable (EFI_SECURE_BOOT_MODE_NAME);\r
+  GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&SecureBootModePtr, NULL);\r
   if (SecureBootModePtr == NULL) {\r
     SecureBootMode   = SECURE_BOOT_MODE_DISABLE;\r
     //\r