User: Provide more robust PE example and memory support

This commit is contained in:
vit9696 2022-02-03 22:18:26 +03:00
parent a3a48b1933
commit e0701fbdae
4 changed files with 236 additions and 87 deletions

12
User/Include/UserMemory.h Normal file
View File

@ -0,0 +1,12 @@
/** @file
Copyright (c) 2022, vit9696. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
**/
#ifndef USER_MEMORY_H
#define USER_MEMORY_H
extern UINTN mPoolAllocations;
extern UINTN mPageAllocations;
#endif // USER_MEMORY_H

View File

@ -5,6 +5,7 @@
#include <Uefi.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/DebugLib.h>
#include <Library/UefiLib.h>
#include <Library/UefiApplicationEntryPoint.h>
@ -16,6 +17,9 @@
#include <malloc.h>
#endif // WIN32
UINTN mPoolAllocations;
UINTN mPageAllocations;
VOID *
EFIAPI
CopyMem (
@ -87,7 +91,19 @@ AllocatePool (
IN UINTN AllocationSize
)
{
return malloc (AllocationSize);
// UEFI guarantees 8-byte alignment.
void *p = malloc ((AllocationSize + 7U) & ~7U);
DEBUG ((
DEBUG_POOL,
"UMEM: Allocating pool %u at %p\n",
(UINT32) AllocationSize,
p
));
ASSERT (((UINTN)p & 7U) == 0);
if (p != NULL) {
++mPoolAllocations;
}
return p;
}
VOID *
@ -140,7 +156,7 @@ ReallocatePool (
if (NewBuffer != NULL && OldBuffer != NULL) {
memcpy (NewBuffer, OldBuffer, MIN (OldSize, NewSize));
free (OldBuffer);
FreePool (OldBuffer);
}
return NewBuffer;
@ -152,10 +168,11 @@ AllocatePages (
IN UINTN Pages
)
{
#ifdef WIN32
return _aligned_malloc (Pages * EFI_PAGE_SIZE, EFI_PAGE_SIZE);
#else // !WIN32
VOID *Memory;
#ifdef WIN32
Memory = _aligned_malloc (Pages * EFI_PAGE_SIZE, EFI_PAGE_SIZE);
#else // !WIN32
INTN RetVal;
Memory = NULL;
@ -164,11 +181,22 @@ AllocatePages (
if (RetVal != 0) {
DEBUG ((DEBUG_ERROR, "posix_memalign returns error %d\n", RetVal));
return NULL;
Memory = NULL;
}
return Memory;
#endif // WIN32
DEBUG ((
DEBUG_PAGE,
"UMEM: Allocating %u pages at %p\n",
(UINT32) Pages,
Memory
));
if (Memory != NULL) {
mPageAllocations += Pages;
}
return Memory;
}
VOID
@ -178,6 +206,13 @@ FreePool (
)
{
ASSERT (Buffer != NULL);
DEBUG ((
DEBUG_POOL,
"UMEM: Deallocating pool %p\n",
Buffer
));
--mPoolAllocations;
free (Buffer);
}
@ -191,6 +226,15 @@ FreePages (
{
ASSERT (Buffer != NULL);
DEBUG ((
DEBUG_PAGE,
"UMEM: Deallocating %u pages at %p\n",
(UINT32) Pages,
Buffer
));
mPageAllocations -= Pages;
free (Buffer);
}

View File

@ -4,6 +4,7 @@
**/
#include <UserFile.h>
#include <Library/MemoryAllocationLib.h>
uint8_t *UserReadFile(const char *str, uint32_t *size) {
FILE *f = fopen(str, "rb");
@ -14,7 +15,7 @@ uint8_t *UserReadFile(const char *str, uint32_t *size) {
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
uint8_t *string = malloc(fsize + 1);
uint8_t *string = AllocatePool(fsize + 1);
if (fsize > 0 && fread(string, fsize, 1, f) != 1)
abort();
fclose(f);

View File

@ -9,106 +9,195 @@
#include <Library/MemoryAllocationLib.h>
#include <Library/DebugLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/BaseMemoryLib.h>
#include <stdio.h>
#include <string.h>
#include <UserFile.h>
#include <UserMemory.h>
EFI_STATUS
TestImageLoad (
IN VOID *SourceBuffer,
IN UINTN SourceSize
STATIC UINT64 PcdValidAllocMask = MAX_UINT64;
STATIC UINT8 PcdValidHashes = MAX_UINT8;
UINTN HashDependency;
BOOLEAN
HashUpdate (
IN OUT VOID *HashContext,
IN CONST VOID *Data,
IN UINTN DataLength
)
{
EFI_STATUS Status;
EFI_STATUS ImageStatus;
PE_COFF_IMAGE_CONTEXT ImageContext;
EFI_PHYSICAL_ADDRESS DestinationArea;
VOID *DestinationBuffer;
CONST UINT8 *D = (CONST UINT8 *)Data;
//
// Initialize the image context.
//
ImageStatus = PeCoffInitializeContext (
&ImageContext,
SourceBuffer,
SourceSize
);
if (EFI_ERROR (ImageStatus)) {
DEBUG ((DEBUG_INFO, "OCB: PeCoff init failure - %r\n", ImageStatus));
return EFI_UNSUPPORTED;
(VOID) HashContext;
for (UINTN i = 0; i < DataLength; i++)
HashDependency += D[i];
if (PcdValidHashes > 0) {
PcdValidHashes--;
return TRUE;
}
//
// Reject images that are not meant for the platform's architecture.
//
if (ImageContext.Machine != IMAGE_FILE_MACHINE_X64) {
DEBUG ((DEBUG_INFO, "OCB: PeCoff wrong machine - %x\n", ImageContext.Machine));
return EFI_UNSUPPORTED;
return FALSE;
}
STATIC
RETURN_STATUS
PeCoffTestRtReloc (
PE_COFF_IMAGE_CONTEXT *Context
)
{
RETURN_STATUS Status;
PE_COFF_RUNTIME_CONTEXT *RtCtx;
UINT32 RtCtxSize;
Status = PeCoffRelocationDataSize (Context, &RtCtxSize);
if (Status != RETURN_SUCCESS) {
return RETURN_UNSUPPORTED;
}
//
// Reject RT drivers for the moment.
//
if (ImageContext.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
DEBUG ((DEBUG_INFO, "OCB: PeCoff no support for RT drivers\n"));
return EFI_UNSUPPORTED;
RtCtx = AllocatePool (RtCtxSize);
if (RtCtx == NULL) {
return RETURN_UNSUPPORTED;
}
//
// Allocate the image destination memory.
// FIXME: RT drivers require EfiRuntimeServicesCode.
//
Status = gBS->AllocatePages (
AllocateAnyPages,
EfiBootServicesCode,
EFI_SIZE_TO_PAGES (ImageContext.SizeOfImage),
&DestinationArea
);
if (EFI_ERROR (Status)) {
Status = PeCoffRelocateImage (Context, 0x69696969, RtCtx, RtCtxSize);
if (Status != RETURN_SUCCESS) {
FreePool (RtCtx);
return Status;
}
DestinationBuffer = (VOID *)(UINTN) DestinationArea;
Status = PeCoffRelocateImageForRuntime (Context->ImageBuffer, Context->SizeOfImage, 0x96969696, RtCtx);
FreePool (RtCtx);
//
// Load SourceBuffer into DestinationBuffer.
//
ImageStatus = PeCoffLoadImage (
&ImageContext,
DestinationBuffer,
ImageContext.SizeOfImage
);
if (EFI_ERROR (ImageStatus)) {
DEBUG ((DEBUG_INFO, "OCB: PeCoff load image error - %r\n", ImageStatus));
FreePages (DestinationBuffer, EFI_SIZE_TO_PAGES (ImageContext.SizeOfImage));
return EFI_UNSUPPORTED;
}
//
// Relocate the loaded image to the destination address.
//
ImageStatus = PeCoffRelocateImage (
&ImageContext,
(UINTN) DestinationBuffer,
NULL,
0
);
return Status;
}
FreePages (DestinationBuffer, EFI_SIZE_TO_PAGES (ImageContext.SizeOfImage));
STATIC
RETURN_STATUS
PeCoffTestLoad (
PE_COFF_IMAGE_CONTEXT *Context,
VOID *Destination,
UINT32 DestinationSize
)
{
RETURN_STATUS Status;
CHAR8 *PdbPath;
UINT32 PdbPathSize;
if (EFI_ERROR (ImageStatus)) {
DEBUG ((DEBUG_INFO, "OCB: PeCoff relocate image error - %d\n", ImageStatus));
return EFI_UNSUPPORTED;
(VOID) PeCoffLoadImage (Context, Destination, DestinationSize);
Status = PeCoffGetPdbPath (Context, &PdbPath, &PdbPathSize);
if (Status == RETURN_SUCCESS) {
ZeroMem (PdbPath, PdbPathSize);
}
return EFI_SUCCESS;
if (!Context->RelocsStripped) {
if (Context->Subsystem != EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
Status = PeCoffRelocateImage (Context, (UINTN) (Context->ImageBuffer), NULL, 0);
} else {
Status = PeCoffTestRtReloc (Context);
}
}
if (Status != RETURN_SUCCESS) {
return Status;
}
PeCoffDiscardSections (Context);
return RETURN_SUCCESS;
}
static void loadConfig(const uint8_t *data, size_t size) {
HashDependency = 0;
PcdGetBool(PcdImageLoaderRtRelocAllowTargetMismatch) = (data[size - 1] & 1U) != 0;
PcdGetBool(PcdImageLoaderHashProhibitOverlap) = (data[size - 1] & 2U) != 0;
PcdGetBool(PcdImageLoaderLoadHeader) = (data[size - 1] & 4U) != 0;
PcdGetBool(PcdImageLoaderSupportArmThumb) = (data[size - 1] & 8U) != 0;
PcdGetBool(PcdImageLoaderForceLoadDebug) = (data[size - 1] & 16U) != 0;
PcdGetBool(PcdImageLoaderTolerantLoad) = (data[size - 1] & 32U) != 0;
PcdGetBool(PcdImageLoaderSupportDebug) = (data[size - 1] & 64U) != 0;
memcpy(&PcdValidAllocMask, &data[size - MIN(size, sizeof(UINT64))], MIN(size, sizeof(UINT64)));
PcdValidHashes = data[size - MIN(size, sizeof(UINT64) + sizeof(UINT8))];
}
RETURN_STATUS
PeCoffTestLoadFull (
IN VOID *FileBuffer,
IN UINT32 FileSize
)
{
RETURN_STATUS Status;
BOOLEAN Result;
PE_COFF_IMAGE_CONTEXT Context;
VOID *Destination;
UINT32 DestinationSize;
Status = PeCoffInitializeContext (&Context, FileBuffer, FileSize);
if (Status != RETURN_SUCCESS) {
return RETURN_UNSUPPORTED;
}
UINT8 HashContext;
Result = PeCoffHashImage (
&Context,
HashUpdate,
&HashContext
);
if (!Result) {
return RETURN_UNSUPPORTED;
}
DestinationSize = Context.SizeOfImage + Context.SizeOfImageDebugAdd;
if (OcOverflowAddU32 (DestinationSize, Context.SectionAlignment, &DestinationSize)) {
return RETURN_UNSUPPORTED;
}
Destination = AllocatePages (EFI_SIZE_TO_PAGES (DestinationSize));
if (Destination == NULL) {
return RETURN_UNSUPPORTED;
}
Status = PeCoffTestLoad (&Context, Destination, DestinationSize);
FreePages (Destination, EFI_SIZE_TO_PAGES (DestinationSize));
return Status;
}
INT32 LLVMFuzzerTestOneInput(CONST UINT8 *Data, UINTN Size) {
if (Data != NULL) {
void *DataCopy = AllocateCopyPool(Size, Data);
TestImageLoad (DataCopy, Size);
FreePool(DataCopy);
if (Size == 0)
return 0;
//PcdGet32 (PcdFixedDebugPrintErrorLevel) |= DEBUG_POOL | DEBUG_PAGE;
//PcdGet32 (PcdDebugPrintErrorLevel) |= DEBUG_POOL | DEBUG_PAGE;
void *p = AllocatePool(Size);
if (p != NULL) {
loadConfig(Data, Size);
memcpy(p, Data, Size);
PeCoffTestLoadFull(p, Size);
FreePool(p);
}
DEBUG ((
DEBUG_POOL | DEBUG_PAGE,
"UMEM: Allocated %u pools %u pages\n",
(UINT32) mPoolAllocations,
(UINT32) mPageAllocations
));
return 0;
}
@ -121,6 +210,9 @@ int ENTRY_POINT (int argc, char *argv[]) {
PcdGet32 (PcdFixedDebugPrintErrorLevel) |= DEBUG_INFO;
PcdGet32 (PcdDebugPrintErrorLevel) |= DEBUG_INFO;
//PcdGet32 (PcdFixedDebugPrintErrorLevel) |= DEBUG_POOL | DEBUG_PAGE;
//PcdGet32 (PcdDebugPrintErrorLevel) |= DEBUG_POOL | DEBUG_PAGE;
uint8_t *Image;
uint32_t ImageSize;
@ -129,8 +221,8 @@ int ENTRY_POINT (int argc, char *argv[]) {
return 1;
}
EFI_STATUS Status = TestImageLoad (Image, ImageSize);
free(Image);
EFI_STATUS Status = LLVMFuzzerTestOneInput (Image, ImageSize);
FreePool(Image);
if (EFI_ERROR (Status)) {
return 1;
}