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:
ydong10 2012-04-24 03:00:32 +00:00
parent 035da677c8
commit 28186d4566
6 changed files with 309 additions and 3 deletions

View File

@ -1,7 +1,7 @@
/** @file
Core image handling services to load and unload PeImage.
Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
@ -232,6 +232,14 @@ CoreReadImageFile (
UINTN EndPosition;
IMAGE_FILE_HANDLE *FHand;
if (UserHandle == NULL || ReadSize == NULL || Buffer == NULL) {
return EFI_INVALID_PARAMETER;
}
if (MAX_ADDRESS - Offset < *ReadSize) {
return EFI_INVALID_PARAMETER;
}
FHand = (IMAGE_FILE_HANDLE *)UserHandle;
ASSERT (FHand->Signature == IMAGE_FILE_HANDLE_SIGNATURE);

View File

@ -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.

View File

@ -54,6 +54,50 @@ HASH_TABLE mHash[] = {
{ L"SHA512", 64, &mHashOidValue[40], 9, NULL, NULL, NULL, NULL }
};
/**
Reads contents of a PE/COFF image in memory buffer.
@param FileHandle Pointer to the file handle to read the PE/COFF image.
@param FileOffset Offset into the PE/COFF image to begin the read operation.
@param ReadSize On input, the size in bytes of the requested read operation.
On output, the number of bytes actually read.
@param Buffer Output buffer that contains the data read from the PE/COFF image.
@retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size
**/
EFI_STATUS
EFIAPI
ImageRead (
IN VOID *FileHandle,
IN UINTN FileOffset,
IN OUT UINTN *ReadSize,
OUT VOID *Buffer
)
{
UINTN EndPosition;
if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {
return EFI_INVALID_PARAMETER;
}
if (MAX_ADDRESS - FileOffset < *ReadSize) {
return EFI_INVALID_PARAMETER;
}
EndPosition = FileOffset + *ReadSize;
if (EndPosition > mImageSize) {
*ReadSize = (UINT32)(mImageSize - FileOffset);
}
if (FileOffset >= mImageSize) {
*ReadSize = 0;
}
CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);
return EFI_SUCCESS;
}
/**
Get the image type.
@ -422,6 +466,10 @@ HashPeImage (
if (mImageSize > SumOfBytesHashed) {
HashBase = mImageBase + SumOfBytesHashed;
if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
if (mImageSize - SumOfBytesHashed < mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {
Status = FALSE;
goto Done;
}
//
// Use PE32 offset.
//
@ -430,6 +478,10 @@ HashPeImage (
mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -
SumOfBytesHashed);
} else {
if (mImageSize - SumOfBytesHashed < mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {
Status = FALSE;
goto Done;
}
//
// Use PE32+ offset.
//
@ -1130,6 +1182,7 @@ DxeImageVerificationHandler (
WIN_CERTIFICATE *WinCertificate;
UINT32 Policy;
UINT8 *SecureBootEnable;
PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
if (File == NULL) {
return EFI_INVALID_PARAMETER;
@ -1216,6 +1269,22 @@ DxeImageVerificationHandler (
}
mImageBase = (UINT8 *) FileBuffer;
mImageSize = FileSize;
ZeroMem (&ImageContext, sizeof (ImageContext));
ImageContext.Handle = (VOID *) FileBuffer;
ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) ImageRead;
//
// Get information about the image being loaded
//
Status = PeCoffLoaderGetImageInfo (&ImageContext);
if (EFI_ERROR (Status)) {
//
// The information can't be got from the invalid PeImage
//
goto Done;
}
DosHdr = (EFI_IMAGE_DOS_HEADER *) mImageBase;
if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
//

View File

@ -28,6 +28,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Library/PcdLib.h>
#include <Library/DevicePathLib.h>
#include <Library/SecurityManagementLib.h>
#include <Library/PeCoffLib.h>
#include <Protocol/FirmwareVolume2.h>
#include <Protocol/DevicePath.h>
#include <Protocol/BlockIo.h>

View File

@ -2,7 +2,7 @@
# The library instance provides security service of image verification.
# Image verification Library module supports UEFI2.3.1
#
# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
# Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
@ -48,6 +48,7 @@
DevicePathLib
BaseCryptLib
SecurityManagementLib
PeCoffLib
[Protocols]
gEfiFirmwareVolume2ProtocolGuid

View File

@ -36,6 +36,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
BOOLEAN mMeasureGptTableFlag = FALSE;
EFI_GUID mZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
UINTN mMeasureGptCount = 0;
VOID *mFileBuffer;
UINTN mImageSize;
/**
Reads contents of a PE/COFF image in memory buffer.
@ -57,7 +59,27 @@ ImageRead (
OUT VOID *Buffer
)
{
UINTN EndPosition;
if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {
return EFI_INVALID_PARAMETER;
}
if (MAX_ADDRESS - FileOffset < *ReadSize) {
return EFI_INVALID_PARAMETER;
}
EndPosition = FileOffset + *ReadSize;
if (EndPosition > mImageSize) {
*ReadSize = (UINT32)(mImageSize - FileOffset);
}
if (FileOffset >= mImageSize) {
*ReadSize = 0;
}
CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);
return EFI_SUCCESS;
}
@ -495,6 +517,10 @@ TcgMeasurePeImage (
if (ImageSize > SumOfBytesHashed) {
HashBase = (UINT8 *) (UINTN) ImageAddress + SumOfBytesHashed;
if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
if (ImageSize - SumOfBytesHashed < Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {
Status = EFI_INVALID_PARAMETER;
goto Finish;
}
//
// Use PE32 offset
//
@ -502,6 +528,10 @@ TcgMeasurePeImage (
Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -
SumOfBytesHashed);
} else {
if (ImageSize - SumOfBytesHashed < Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {
Status = EFI_INVALID_PARAMETER;
goto Finish;
}
//
// Use PE32+ offset
//
@ -735,6 +765,9 @@ DxeTpmMeasureBootHandler (
goto Finish;
}
mImageSize = FileSize;
mFileBuffer = FileBuffer;
//
// Measure PE Image
//