Validate some fields in PE image to make sure not access violation for later code.
Signed-off-by: Eric Dong <eric.dong@intel.com> Reviewed-by: Liming Gao <liming.gao@intel.com> git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13211 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
@@ -47,7 +47,9 @@ PeCoffLoaderGetPeHeaderMagicValue (
|
||||
|
||||
|
||||
/**
|
||||
Retrieves the PE or TE Header from a PE/COFF or TE image.
|
||||
Retrieves the PE or TE Header from a PE/COFF or TE image.
|
||||
Also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader,
|
||||
SizeOfHeader, Section Data Region and Security Data Region be in PE image range.
|
||||
|
||||
@param ImageContext The context of the image being loaded.
|
||||
@param Hdr The buffer in which to return the PE32, PE32+, or TE header.
|
||||
@@ -66,6 +68,10 @@ PeCoffLoaderGetPeHeader (
|
||||
EFI_IMAGE_DOS_HEADER DosHdr;
|
||||
UINTN Size;
|
||||
UINT16 Magic;
|
||||
UINT32 SectionHeaderOffset;
|
||||
UINT32 Index;
|
||||
CHAR8 BufferData;
|
||||
EFI_IMAGE_SECTION_HEADER SectionHeader;
|
||||
|
||||
//
|
||||
// Read the DOS image header to check for its existence
|
||||
@@ -131,6 +137,74 @@ PeCoffLoaderGetPeHeader (
|
||||
Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
|
||||
|
||||
if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
|
||||
//
|
||||
// 1. Check FileHeader.SizeOfOptionalHeader filed.
|
||||
//
|
||||
if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes) {
|
||||
return RETURN_UNSUPPORTED;
|
||||
}
|
||||
|
||||
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)) {
|
||||
return RETURN_UNSUPPORTED;
|
||||
}
|
||||
|
||||
//
|
||||
// 2. Check the OptionalHeader.SizeOfHeaders field.
|
||||
// This field will be use like the following mode, so just compare the result.
|
||||
// The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
|
||||
//
|
||||
if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1 < Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes) {
|
||||
if (Hdr.Pe32->OptionalHeader.SizeOfHeaders < (UINT32)((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINT8 *) &Hdr)) {
|
||||
return RETURN_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Read Hdr.Pe32.OptionalHeader.SizeOfHeaders data from file
|
||||
//
|
||||
Size = 1;
|
||||
Status = ImageContext->ImageRead (
|
||||
ImageContext->Handle,
|
||||
Hdr.Pe32->OptionalHeader.SizeOfHeaders - 1,
|
||||
&Size,
|
||||
&BufferData
|
||||
);
|
||||
if (RETURN_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.
|
||||
// Read the last byte to make sure the data is in the image region.
|
||||
// The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
|
||||
//
|
||||
if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY < Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes) {
|
||||
if (Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size != 0) {
|
||||
//
|
||||
// Check the member data to avoid overflow.
|
||||
//
|
||||
if ((UINT32) (~0) - Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress <
|
||||
Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {
|
||||
return RETURN_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// Read section header from file
|
||||
//
|
||||
Size = 1;
|
||||
Status = ImageContext->ImageRead (
|
||||
ImageContext->Handle,
|
||||
Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress +
|
||||
Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - 1,
|
||||
&Size,
|
||||
&BufferData
|
||||
);
|
||||
if (RETURN_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Use PE32 offset
|
||||
//
|
||||
@@ -140,6 +214,74 @@ PeCoffLoaderGetPeHeader (
|
||||
ImageContext->SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders;
|
||||
|
||||
} else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
|
||||
//
|
||||
// 1. Check FileHeader.SizeOfOptionalHeader filed.
|
||||
//
|
||||
if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes) {
|
||||
return RETURN_UNSUPPORTED;
|
||||
}
|
||||
|
||||
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)) {
|
||||
return RETURN_UNSUPPORTED;
|
||||
}
|
||||
|
||||
//
|
||||
// 2. Check the OptionalHeader.SizeOfHeaders field.
|
||||
// This field will be use like the following mode, so just compare the result.
|
||||
// The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
|
||||
//
|
||||
if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1 < Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes) {
|
||||
if (Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders < (UINT32)((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINT8 *) &Hdr)) {
|
||||
return RETURN_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Read Hdr.Pe32.OptionalHeader.SizeOfHeaders data from file
|
||||
//
|
||||
Size = 1;
|
||||
Status = ImageContext->ImageRead (
|
||||
ImageContext->Handle,
|
||||
Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - 1,
|
||||
&Size,
|
||||
&BufferData
|
||||
);
|
||||
if (RETURN_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.
|
||||
// Read the last byte to make sure the data is in the image region.
|
||||
// The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
|
||||
//
|
||||
if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY < Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes) {
|
||||
if (Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size != 0) {
|
||||
//
|
||||
// Check the member data to avoid overflow.
|
||||
//
|
||||
if ((UINT32) (~0) - Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress <
|
||||
Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {
|
||||
return RETURN_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// Read section header from file
|
||||
//
|
||||
Size = 1;
|
||||
Status = ImageContext->ImageRead (
|
||||
ImageContext->Handle,
|
||||
Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress +
|
||||
Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - 1,
|
||||
&Size,
|
||||
&BufferData
|
||||
);
|
||||
if (RETURN_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Use PE32+ offset
|
||||
//
|
||||
@@ -166,6 +308,55 @@ PeCoffLoaderGetPeHeader (
|
||||
return RETURN_UNSUPPORTED;
|
||||
}
|
||||
|
||||
//
|
||||
// Check each section field.
|
||||
//
|
||||
SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + Hdr.Pe32->FileHeader.SizeOfOptionalHeader;
|
||||
for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
|
||||
//
|
||||
// Read section header from file
|
||||
//
|
||||
Size = sizeof (EFI_IMAGE_SECTION_HEADER);
|
||||
Status = ImageContext->ImageRead (
|
||||
ImageContext->Handle,
|
||||
SectionHeaderOffset,
|
||||
&Size,
|
||||
&SectionHeader
|
||||
);
|
||||
if (RETURN_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (SectionHeader.SizeOfRawData > 0) {
|
||||
//
|
||||
// Check the member data to avoid overflow.
|
||||
//
|
||||
if ((UINT32) (~0) - SectionHeader.PointerToRawData < SectionHeader.SizeOfRawData) {
|
||||
return RETURN_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// Base on the ImageRead function to check the section data field.
|
||||
// Read the last byte to make sure the data is in the image region.
|
||||
//
|
||||
Size = 1;
|
||||
Status = ImageContext->ImageRead (
|
||||
ImageContext->Handle,
|
||||
SectionHeader.PointerToRawData + SectionHeader.SizeOfRawData - 1,
|
||||
&Size,
|
||||
&BufferData
|
||||
);
|
||||
if (RETURN_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Check next section.
|
||||
//
|
||||
SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
|
||||
}
|
||||
|
||||
return RETURN_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -185,6 +376,9 @@ PeCoffLoaderGetPeHeader (
|
||||
The ImageRead and Handle fields of ImageContext structure must be valid prior
|
||||
to invoking this service.
|
||||
|
||||
Also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader,
|
||||
SizeOfHeader, Section Data Region and Security Data Region be in PE image range.
|
||||
|
||||
@param ImageContext The pointer to the image context structure that describes the PE/COFF
|
||||
image that needs to be examined by this function.
|
||||
|
||||
|
Reference in New Issue
Block a user