\r
\r
/**\r
- Retrieves the PE or TE Header from a PE/COFF or TE image.\r
+ Retrieves the PE or TE Header from a PE/COFF or TE image. \r
+ Also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader, \r
+ SizeOfHeader, Section Data Region and Security Data Region be in PE image range. \r
\r
@param ImageContext The context of the image being loaded.\r
@param Hdr The buffer in which to return the PE32, PE32+, or TE header.\r
EFI_IMAGE_DOS_HEADER DosHdr;\r
UINTN Size;\r
UINT16 Magic;\r
+ UINT32 SectionHeaderOffset;\r
+ UINT32 Index;\r
+ CHAR8 BufferData;\r
+ EFI_IMAGE_SECTION_HEADER SectionHeader;\r
\r
//\r
// Read the DOS image header to check for its existence\r
Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);\r
\r
if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+ //\r
+ // 1. Check FileHeader.SizeOfOptionalHeader filed.\r
+ //\r
+ if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes) {\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+\r
+ if (Hdr.Pe32->FileHeader.SizeOfOptionalHeader != sizeof (EFI_IMAGE_OPTIONAL_HEADER32) - (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES - Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes) * sizeof (EFI_IMAGE_DATA_DIRECTORY)) {\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // 2. Check the OptionalHeader.SizeOfHeaders field.\r
+ // This field will be use like the following mode, so just compare the result.\r
+ // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.\r
+ //\r
+ if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1 < Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes) {\r
+ if (Hdr.Pe32->OptionalHeader.SizeOfHeaders < (UINT32)((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINT8 *) &Hdr)) {\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Read Hdr.Pe32.OptionalHeader.SizeOfHeaders data from file\r
+ //\r
+ Size = 1;\r
+ Status = ImageContext->ImageRead (\r
+ ImageContext->Handle,\r
+ Hdr.Pe32->OptionalHeader.SizeOfHeaders - 1,\r
+ &Size,\r
+ &BufferData\r
+ );\r
+ if (RETURN_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.\r
+ // Read the last byte to make sure the data is in the image region.\r
+ // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.\r
+ //\r
+ if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY < Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes) {\r
+ if (Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size != 0) {\r
+ //\r
+ // Check the member data to avoid overflow.\r
+ //\r
+ if ((UINT32) (~0) - Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress <\r
+ Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {\r
+ return RETURN_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Read section header from file\r
+ //\r
+ Size = 1;\r
+ Status = ImageContext->ImageRead (\r
+ ImageContext->Handle,\r
+ Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress +\r
+ Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - 1,\r
+ &Size,\r
+ &BufferData\r
+ );\r
+ if (RETURN_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+ }\r
+\r
//\r
// Use PE32 offset\r
//\r
ImageContext->SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders;\r
\r
} else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
+ //\r
+ // 1. Check FileHeader.SizeOfOptionalHeader filed.\r
+ //\r
+ if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes) {\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+\r
+ if (Hdr.Pe32Plus->FileHeader.SizeOfOptionalHeader != sizeof (EFI_IMAGE_OPTIONAL_HEADER32) - (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES - Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes) * sizeof (EFI_IMAGE_DATA_DIRECTORY)) {\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // 2. Check the OptionalHeader.SizeOfHeaders field.\r
+ // This field will be use like the following mode, so just compare the result.\r
+ // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.\r
+ //\r
+ if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1 < Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes) {\r
+ if (Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders < (UINT32)((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINT8 *) &Hdr)) {\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Read Hdr.Pe32.OptionalHeader.SizeOfHeaders data from file\r
+ //\r
+ Size = 1;\r
+ Status = ImageContext->ImageRead (\r
+ ImageContext->Handle,\r
+ Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - 1,\r
+ &Size,\r
+ &BufferData\r
+ );\r
+ if (RETURN_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.\r
+ // Read the last byte to make sure the data is in the image region.\r
+ // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.\r
+ //\r
+ if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY < Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes) {\r
+ if (Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size != 0) {\r
+ //\r
+ // Check the member data to avoid overflow.\r
+ //\r
+ if ((UINT32) (~0) - Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress <\r
+ Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {\r
+ return RETURN_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Read section header from file\r
+ //\r
+ Size = 1;\r
+ Status = ImageContext->ImageRead (\r
+ ImageContext->Handle,\r
+ Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress +\r
+ Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - 1,\r
+ &Size,\r
+ &BufferData\r
+ );\r
+ if (RETURN_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+ }\r
+\r
//\r
// Use PE32+ offset\r
//\r
return RETURN_UNSUPPORTED;\r
}\r
\r
+ //\r
+ // Check each section field.\r
+ //\r
+ SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + Hdr.Pe32->FileHeader.SizeOfOptionalHeader;\r
+ for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {\r
+ //\r
+ // Read section header from file\r
+ //\r
+ Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
+ Status = ImageContext->ImageRead (\r
+ ImageContext->Handle,\r
+ SectionHeaderOffset,\r
+ &Size,\r
+ &SectionHeader\r
+ );\r
+ if (RETURN_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (SectionHeader.SizeOfRawData > 0) {\r
+ //\r
+ // Check the member data to avoid overflow.\r
+ //\r
+ if ((UINT32) (~0) - SectionHeader.PointerToRawData < SectionHeader.SizeOfRawData) {\r
+ return RETURN_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Base on the ImageRead function to check the section data field.\r
+ // Read the last byte to make sure the data is in the image region.\r
+ //\r
+ Size = 1;\r
+ Status = ImageContext->ImageRead (\r
+ ImageContext->Handle,\r
+ SectionHeader.PointerToRawData + SectionHeader.SizeOfRawData - 1,\r
+ &Size,\r
+ &BufferData\r
+ );\r
+ if (RETURN_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Check next section.\r
+ //\r
+ SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
+ }\r
+\r
return RETURN_SUCCESS;\r
}\r
\r
The ImageRead and Handle fields of ImageContext structure must be valid prior \r
to invoking this service.\r
\r
+ Also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader, \r
+ SizeOfHeader, Section Data Region and Security Data Region be in PE image range. \r
+\r
@param ImageContext The pointer to the image context structure that describes the PE/COFF\r
image that needs to be examined by this function.\r
\r
{ L"SHA512", 64, &mHashOidValue[40], 9, NULL, NULL, NULL, NULL }\r
};\r
\r
+/**\r
+ Reads contents of a PE/COFF image in memory 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
+ On output, the number of bytes actually read.\r
+ @param Buffer Output buffer that contains the data read from the PE/COFF image.\r
+ \r
+ @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ImageRead (\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
\r
/**\r
Get the image type.\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
mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -\r
SumOfBytesHashed);\r
} else {\r
+ if (mImageSize - SumOfBytesHashed < mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {\r
+ Status = FALSE;\r
+ goto Done;\r
+ }\r
//\r
// Use PE32+ offset.\r
//\r
WIN_CERTIFICATE *WinCertificate;\r
UINT32 Policy;\r
UINT8 *SecureBootEnable;\r
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
\r
if (File == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
mImageBase = (UINT8 *) FileBuffer;\r
mImageSize = FileSize;\r
+\r
+ ZeroMem (&ImageContext, sizeof (ImageContext));\r
+ ImageContext.Handle = (VOID *) FileBuffer;\r
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) ImageRead;\r
+\r
+ //\r
+ // Get information about the image being loaded\r
+ //\r
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // The information can't be got from the invalid PeImage\r
+ //\r
+ goto Done;\r
+ }\r
+\r
DosHdr = (EFI_IMAGE_DOS_HEADER *) mImageBase;\r
if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
//\r
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
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
if (ImageSize > SumOfBytesHashed) {\r
HashBase = (UINT8 *) (UINTN) ImageAddress + SumOfBytesHashed;\r
if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+ if (ImageSize - SumOfBytesHashed < Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Finish;\r
+ }\r
//\r
// Use PE32 offset\r
//\r
Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -\r
SumOfBytesHashed);\r
} else {\r
+ if (ImageSize - SumOfBytesHashed < Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Finish;\r
+ }\r
//\r
// Use PE32+ offset\r
//\r
goto Finish;\r
}\r
\r
+ mImageSize = FileSize;\r
+ mFileBuffer = FileBuffer;\r
+\r
//\r
// Measure PE Image\r
//\r