Base PE/COFF loader supports loading any PE32/PE32+ or TE image, but\r
only supports relocating IA32, x64, IPF, and EBC images.\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
+ The basic guideline is that caller need provide ImageContext->ImageRead () with the\r
+ necessary data range check, to make sure when this library reads PE/COFF image, the\r
+ PE image buffer is always in valid range.\r
+ This library will also do some additional check for PE header fields.\r
+\r
+ PeCoffLoaderGetPeHeader() routine will do basic check for PE/COFF header.\r
+ PeCoffLoaderGetImageInfo() routine will do basic check for whole PE/COFF image.\r
+\r
Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>\r
Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
This program and the accompanying materials\r
\r
/**\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
+\r
+ Caution: This function may receive untrusted input.\r
+ PE/COFF image is external input, so this routine will \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
RETURN_STATUS Status;\r
EFI_IMAGE_DOS_HEADER DosHdr;\r
UINTN Size;\r
+ UINTN ReadSize;\r
UINT16 Magic;\r
UINT32 SectionHeaderOffset;\r
UINT32 Index;\r
+ UINT32 HeaderWithoutDataDir;\r
CHAR8 BufferData;\r
+ UINTN NumberOfSections;\r
EFI_IMAGE_SECTION_HEADER SectionHeader;\r
\r
//\r
// Read the DOS image header to check for its existence\r
//\r
Size = sizeof (EFI_IMAGE_DOS_HEADER);\r
+ ReadSize = Size;\r
Status = ImageContext->ImageRead (\r
ImageContext->Handle,\r
0,\r
&Size,\r
&DosHdr\r
);\r
- if (RETURN_ERROR (Status)) {\r
+ if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+ if (Size != ReadSize) {\r
+ Status = RETURN_UNSUPPORTED;\r
+ }\r
return Status;\r
}\r
\r
// location in both images.\r
//\r
Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);\r
+ ReadSize = Size;\r
Status = ImageContext->ImageRead (\r
ImageContext->Handle,\r
ImageContext->PeCoffHeaderOffset,\r
&Size,\r
Hdr.Pe32\r
);\r
- if (RETURN_ERROR (Status)) {\r
+ if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+ if (Size != ReadSize) {\r
+ Status = RETURN_UNSUPPORTED;\r
+ }\r
return Status;\r
}\r
\r
\r
if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
//\r
- // 1. Check FileHeader.SizeOfOptionalHeader filed.\r
+ // 1. Check OptionalHeader.NumberOfRvaAndSizes filed.\r
//\r
if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes) {\r
+ ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\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
+ // 2. Check the FileHeader.SizeOfOptionalHeader field.\r
+ // OptionalHeader.NumberOfRvaAndSizes is not bigger than 16, so \r
+ // OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY) will not overflow.\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
+ HeaderWithoutDataDir = sizeof (EFI_IMAGE_OPTIONAL_HEADER32) - sizeof (EFI_IMAGE_DATA_DIRECTORY) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;\r
+ if (((UINT32)Hdr.Pe32->FileHeader.SizeOfOptionalHeader - HeaderWithoutDataDir) !=\r
+ Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY)) {\r
+ ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+\r
+ SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + Hdr.Pe32->FileHeader.SizeOfOptionalHeader;\r
+ //\r
+ // 3. Check the FileHeader.NumberOfSections field.\r
+ //\r
+ if ((Hdr.Pe32->OptionalHeader.SizeOfImage - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER <= Hdr.Pe32->FileHeader.NumberOfSections) {\r
+ ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+ return RETURN_UNSUPPORTED;\r
}\r
\r
//\r
- // Read Hdr.Pe32.OptionalHeader.SizeOfHeaders data from file\r
+ // 4. Check the OptionalHeader.SizeOfHeaders field.\r
+ //\r
+ if ((Hdr.Pe32->OptionalHeader.SizeOfHeaders - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER < (UINT32)Hdr.Pe32->FileHeader.NumberOfSections) {\r
+ ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // 4.2 Read last byte of Hdr.Pe32.OptionalHeader.SizeOfHeaders from the file.\r
//\r
Size = 1;\r
+ ReadSize = Size;\r
Status = ImageContext->ImageRead (\r
ImageContext->Handle,\r
Hdr.Pe32->OptionalHeader.SizeOfHeaders - 1,\r
&Size,\r
&BufferData\r
);\r
- if (RETURN_ERROR (Status)) {\r
+ if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
+ ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+ if (Size != ReadSize) {\r
+ Status = RETURN_UNSUPPORTED;\r
+ }\r
return Status;\r
}\r
\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
+ ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+ return RETURN_UNSUPPORTED;\r
}\r
\r
//\r
- // Read section header from file\r
+ // Read last byte of section header from file\r
//\r
Size = 1;\r
+ ReadSize = Size;\r
Status = ImageContext->ImageRead (\r
ImageContext->Handle,\r
Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress +\r
&Size,\r
&BufferData\r
);\r
- if (RETURN_ERROR (Status)) {\r
+ if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
+ ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+ if (Size != ReadSize) {\r
+ Status = RETURN_UNSUPPORTED;\r
+ }\r
return Status;\r
}\r
}\r
\r
} else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
//\r
- // 1. Check FileHeader.SizeOfOptionalHeader filed.\r
+ // 1. Check FileHeader.NumberOfRvaAndSizes filed.\r
//\r
if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes) {\r
+ ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+ //\r
+ // 2. Check the FileHeader.SizeOfOptionalHeader field.\r
+ // OptionalHeader.NumberOfRvaAndSizes is not bigger than 16, so \r
+ // OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY) will not overflow.\r
+ //\r
+ HeaderWithoutDataDir = sizeof (EFI_IMAGE_OPTIONAL_HEADER64) - sizeof (EFI_IMAGE_DATA_DIRECTORY) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;\r
+ if (((UINT32)Hdr.Pe32Plus->FileHeader.SizeOfOptionalHeader - HeaderWithoutDataDir) !=\r
+ Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY)) {\r
+ ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
return RETURN_UNSUPPORTED;\r
}\r
\r
+ SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + Hdr.Pe32Plus->FileHeader.SizeOfOptionalHeader;\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
+ // 3. Check the FileHeader.NumberOfSections field.\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
+ if ((Hdr.Pe32Plus->OptionalHeader.SizeOfImage - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER <= Hdr.Pe32Plus->FileHeader.NumberOfSections) {\r
+ ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+ return RETURN_UNSUPPORTED;\r
}\r
\r
//\r
- // Read Hdr.Pe32.OptionalHeader.SizeOfHeaders data from file\r
+ // 4. Check the OptionalHeader.SizeOfHeaders field.\r
+ //\r
+ if ((Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER < (UINT32)Hdr.Pe32Plus->FileHeader.NumberOfSections) {\r
+ ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // 4.2 Read last byte of Hdr.Pe32Plus.OptionalHeader.SizeOfHeaders from the file.\r
//\r
Size = 1;\r
+ ReadSize = Size;\r
Status = ImageContext->ImageRead (\r
ImageContext->Handle,\r
Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - 1,\r
&Size,\r
&BufferData\r
);\r
- if (RETURN_ERROR (Status)) {\r
+ if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
+ ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+ if (Size != ReadSize) {\r
+ Status = RETURN_UNSUPPORTED;\r
+ }\r
return Status;\r
}\r
\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
+ ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+ return RETURN_UNSUPPORTED;\r
}\r
\r
//\r
- // Read section header from file\r
+ // Read last byte of section header from file\r
//\r
Size = 1;\r
+ ReadSize = Size;\r
Status = ImageContext->ImageRead (\r
ImageContext->Handle,\r
Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress +\r
&Size,\r
&BufferData\r
);\r
- if (RETURN_ERROR (Status)) {\r
+ if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
+ ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+ if (Size != ReadSize) {\r
+ Status = RETURN_UNSUPPORTED;\r
+ }\r
return Status;\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
+ if (ImageContext->IsTeImage) {\r
+ SectionHeaderOffset = sizeof(EFI_TE_IMAGE_HEADER);\r
+ NumberOfSections = (UINTN) (Hdr.Te->NumberOfSections);\r
+ } else {\r
+ SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + Hdr.Pe32->FileHeader.SizeOfOptionalHeader;\r
+ NumberOfSections = (UINTN) (Hdr.Pe32->FileHeader.NumberOfSections);\r
+ }\r
+\r
+ for (Index = 0; Index < NumberOfSections; Index++) {\r
//\r
// Read section header from file\r
//\r
Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
+ ReadSize = Size;\r
Status = ImageContext->ImageRead (\r
ImageContext->Handle,\r
SectionHeaderOffset,\r
&Size,\r
&SectionHeader\r
);\r
- if (RETURN_ERROR (Status)) {\r
+ if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
+ ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+ if (Size != ReadSize) {\r
+ Status = RETURN_UNSUPPORTED;\r
+ }\r
return Status;\r
}\r
\r
if (SectionHeader.SizeOfRawData > 0) {\r
+ //\r
+ // Section data should bigger than the Pe header.\r
+ //\r
+ if (SectionHeader.VirtualAddress < ImageContext->SizeOfHeaders || \r
+ SectionHeader.PointerToRawData < ImageContext->SizeOfHeaders) {\r
+ ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+\r
//\r
// Check the member data to avoid overflow.\r
//\r
if ((UINT32) (~0) - SectionHeader.PointerToRawData < SectionHeader.SizeOfRawData) {\r
- return RETURN_INVALID_PARAMETER;\r
+ ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+ return RETURN_UNSUPPORTED;\r
}\r
\r
//\r
// Read the last byte to make sure the data is in the image region.\r
//\r
Size = 1;\r
+ ReadSize = Size;\r
Status = ImageContext->ImageRead (\r
ImageContext->Handle,\r
SectionHeader.PointerToRawData + SectionHeader.SizeOfRawData - 1,\r
&Size,\r
&BufferData\r
);\r
- if (RETURN_ERROR (Status)) {\r
+ if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
+ ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+ if (Size != ReadSize) {\r
+ Status = RETURN_UNSUPPORTED;\r
+ }\r
return Status;\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
+ Caution: This function may receive untrusted input.\r
+ PE/COFF image is external input, so this routine will \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
EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry;\r
UINTN Size;\r
+ UINTN ReadSize;\r
UINTN Index;\r
UINTN DebugDirectoryEntryRva;\r
UINTN DebugDirectoryEntryFileOffset;\r
// This case is not a valid TE image. \r
//\r
if ((ImageContext->IsTeImage) && (Hdr.Te->DataDirectory[0].Size != 0) && (Hdr.Te->DataDirectory[0].VirtualAddress == 0)) {\r
- return RETURN_INVALID_PARAMETER;\r
+ ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+ return RETURN_UNSUPPORTED;\r
}\r
\r
if (!(ImageContext->IsTeImage)) {\r
// Read section header from file\r
//\r
Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
+ ReadSize = Size;\r
Status = ImageContext->ImageRead (\r
ImageContext->Handle,\r
SectionHeaderOffset,\r
&Size,\r
&SectionHeader\r
);\r
- if (RETURN_ERROR (Status)) {\r
+ if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+ if (Size != ReadSize) {\r
+ Status = RETURN_UNSUPPORTED;\r
+ }\r
return Status;\r
}\r
\r
// Read next debug directory entry\r
//\r
Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
+ ReadSize = Size;\r
Status = ImageContext->ImageRead (\r
ImageContext->Handle,\r
DebugDirectoryEntryFileOffset + Index,\r
&Size,\r
&DebugEntry\r
);\r
- if (RETURN_ERROR (Status)) {\r
+ if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+ if (Size != ReadSize) {\r
+ Status = RETURN_UNSUPPORTED;\r
+ }\r
return Status;\r
}\r
+\r
+ //\r
+ // From PeCoff spec, when DebugEntry.RVA == 0 means this debug info will not load into memory.\r
+ // Here we will always load EFI_IMAGE_DEBUG_TYPE_CODEVIEW type debug info. so need adjust the\r
+ // ImageContext->ImageSize when DebugEntry.RVA == 0.\r
+ //\r
if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r
ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);\r
if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {\r
// Read section header from file\r
//\r
Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
+ ReadSize = Size;\r
Status = ImageContext->ImageRead (\r
ImageContext->Handle,\r
SectionHeaderOffset,\r
&Size,\r
&SectionHeader\r
);\r
- if (RETURN_ERROR (Status)) {\r
+ if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+ if (Size != ReadSize) {\r
+ Status = RETURN_UNSUPPORTED;\r
+ }\r
return Status;\r
}\r
\r
// Read next debug directory entry\r
//\r
Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
+ ReadSize = Size;\r
Status = ImageContext->ImageRead (\r
ImageContext->Handle,\r
DebugDirectoryEntryFileOffset + Index,\r
&Size,\r
&DebugEntry\r
);\r
- if (RETURN_ERROR (Status)) {\r
+ if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+ if (Size != ReadSize) {\r
+ Status = RETURN_UNSUPPORTED;\r
+ }\r
return Status;\r
}\r
\r
while (RelocBase < RelocBaseEnd) {\r
\r
Reloc = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));\r
- RelocEnd = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);\r
- \r
//\r
- // Make sure RelocEnd is in the Image range.\r
+ // Add check for RelocBase->SizeOfBlock field.\r
//\r
- if ((CHAR8 *) RelocEnd < (CHAR8 *)((UINTN) ImageContext->ImageAddress) ||\r
- (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress + (UINTN)ImageContext->ImageSize)) {\r
+ if ((RelocBase->SizeOfBlock == 0) || (RelocBase->SizeOfBlock > RelocDir->Size)) {\r
ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
return RETURN_LOAD_ERROR;\r
}\r
\r
+ RelocEnd = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);\r
+\r
if (!(ImageContext->IsTeImage)) {\r
FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress);\r
if (FixupBase == NULL) {\r
UINTN Index;\r
CHAR8 *Base;\r
CHAR8 *End;\r
- CHAR8 *MaxEnd;\r
EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;\r
EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;\r
UINTN Size;\r
EFI_IMAGE_RESOURCE_DIRECTORY_STRING *ResourceDirectoryString;\r
EFI_IMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry;\r
CHAR16 *String;\r
+ UINT32 Offset;\r
\r
\r
ASSERT (ImageContext != NULL);\r
// Load each section of the image\r
//\r
Section = FirstSection;\r
- for (Index = 0, MaxEnd = NULL; Index < NumberOfSections; Index++) {\r
+ for (Index = 0; Index < NumberOfSections; Index++) {\r
//\r
// Read the section\r
//\r
End = (CHAR8 *)((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize);\r
}\r
\r
- if (End > MaxEnd) {\r
- MaxEnd = End;\r
- }\r
-\r
if (Section->SizeOfRawData > 0) {\r
if (!(ImageContext->IsTeImage)) {\r
Status = ImageContext->ImageRead (\r
\r
switch (*(UINT32 *) ImageContext->CodeView) {\r
case CODEVIEW_SIGNATURE_NB10:\r
+ if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)) {\r
+ ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);\r
break;\r
\r
case CODEVIEW_SIGNATURE_RSDS:\r
+ if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY)) {\r
+ ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);\r
break;\r
\r
case CODEVIEW_SIGNATURE_MTOC:\r
+ if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY)) {\r
+ ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY);\r
break;\r
\r
//\r
// Use PE32 offset\r
//\r
+ NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];\r
} else {\r
//\r
// Use PE32+ offset\r
//\r
+ NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];\r
}\r
\r
- if (DirectoryEntry->Size != 0) {\r
+ if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE && DirectoryEntry->Size != 0) {\r
Base = PeCoffLoaderImageAddress (ImageContext, DirectoryEntry->VirtualAddress);\r
if (Base != NULL) {\r
ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) Base;\r
+ Offset = sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) * \r
+ (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);\r
+ if (Offset > DirectoryEntry->Size) {\r
+ ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);\r
\r
for (Index = 0; Index < ResourceDirectory->NumberOfNamedEntries; Index++) {\r
if (ResourceDirectoryEntry->u1.s.NameIsString) {\r
+ //\r
+ // Check the ResourceDirectoryEntry->u1.s.NameOffset before use it.\r
+ //\r
+ if (ResourceDirectoryEntry->u1.s.NameOffset >= DirectoryEntry->Size) {\r
+ ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
ResourceDirectoryString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *) (Base + ResourceDirectoryEntry->u1.s.NameOffset);\r
String = &ResourceDirectoryString->String[0];\r
\r
//\r
// Move to next level - resource Name\r
//\r
+ if (ResourceDirectoryEntry->u2.s.OffsetToDirectory >= DirectoryEntry->Size) {\r
+ ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);\r
+ Offset = ResourceDirectoryEntry->u2.s.OffsetToDirectory + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) + \r
+ sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) * (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);\r
+ if (Offset > DirectoryEntry->Size) {\r
+ ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);\r
\r
if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {\r
//\r
// Move to next level - resource Language\r
//\r
+ if (ResourceDirectoryEntry->u2.s.OffsetToDirectory >= DirectoryEntry->Size) {\r
+ ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);\r
+ Offset = ResourceDirectoryEntry->u2.s.OffsetToDirectory + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) + \r
+ sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) * (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);\r
+ if (Offset > DirectoryEntry->Size) {\r
+ ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);\r
}\r
}\r
// Now it ought to be resource Data\r
//\r
if (!ResourceDirectoryEntry->u2.s.DataIsDirectory) {\r
+ if (ResourceDirectoryEntry->u2.OffsetToData >= DirectoryEntry->Size) {\r
+ ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
ResourceDataEntry = (EFI_IMAGE_RESOURCE_DATA_ENTRY *) (Base + ResourceDirectoryEntry->u2.OffsetToData);\r
ImageContext->HiiResourceData = (PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress (ImageContext, ResourceDataEntry->OffsetToData);\r
break;\r
//\r
FixupData = RelocationData;\r
while (RelocBase < RelocBaseEnd) {\r
+ //\r
+ // Add check for RelocBase->SizeOfBlock field.\r
+ //\r
+ if ((RelocBase->SizeOfBlock == 0) || (RelocBase->SizeOfBlock > RelocDir->Size)) {\r
+ //\r
+ // Data invalid, cannot continue to relocate the image, just return.\r
+ //\r
+ return;\r
+ }\r
\r
Reloc = (UINT16 *) ((UINT8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));\r
RelocEnd = (UINT16 *) ((UINT8 *) RelocBase + RelocBase->SizeOfBlock);\r
FixupData = FixupData + sizeof (UINT64);\r
break;\r
\r
- case EFI_IMAGE_REL_BASED_HIGHADJ:\r
- //\r
- // Not valid Relocation type for UEFI image, ASSERT\r
- //\r
- ASSERT (FALSE);\r
- break;\r
-\r
default:\r
//\r
// Only Itanium requires ConvertPeImage_Ex\r
PE/COFF image starting at byte offset FileOffset into the buffer specified by Buffer. \r
The size of the buffer actually read is returned in ReadSize.\r
\r
+ The caller must make sure the FileOffset and ReadSize within the file scope.\r
+\r
If FileHandle is NULL, then ASSERT().\r
If ReadSize is NULL, then ASSERT().\r
If Buffer is NULL, then ASSERT().\r