mirror of https://github.com/acidanthera/audk.git
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:
parent
035da677c8
commit
28186d4566
|
@ -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);
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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) {
|
||||
//
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
|
Loading…
Reference in New Issue