From e0701fbdae4e5f9fd2d0aebb8e4169bc6d98b907 Mon Sep 17 00:00:00 2001 From: vit9696 Date: Thu, 3 Feb 2022 22:18:26 +0300 Subject: [PATCH] User: Provide more robust PE example and memory support --- User/Include/UserMemory.h | 12 ++ User/Library/UserBaseMemoryLib.c | 60 +++++++- User/Library/UserFile.c | 3 +- Utilities/TestPeCoff/PeCoff.c | 248 +++++++++++++++++++++---------- 4 files changed, 236 insertions(+), 87 deletions(-) create mode 100644 User/Include/UserMemory.h diff --git a/User/Include/UserMemory.h b/User/Include/UserMemory.h new file mode 100644 index 00000000..3840251c --- /dev/null +++ b/User/Include/UserMemory.h @@ -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 diff --git a/User/Library/UserBaseMemoryLib.c b/User/Library/UserBaseMemoryLib.c index c74a2d82..0c8b4a2f 100644 --- a/User/Library/UserBaseMemoryLib.c +++ b/User/Library/UserBaseMemoryLib.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -16,6 +17,9 @@ #include #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); } diff --git a/User/Library/UserFile.c b/User/Library/UserFile.c index 2206f0dd..a49fbc41 100644 --- a/User/Library/UserFile.c +++ b/User/Library/UserFile.c @@ -4,6 +4,7 @@ **/ #include +#include 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); diff --git a/Utilities/TestPeCoff/PeCoff.c b/Utilities/TestPeCoff/PeCoff.c index 7af4ba87..a1592f19 100644 --- a/Utilities/TestPeCoff/PeCoff.c +++ b/Utilities/TestPeCoff/PeCoff.c @@ -9,106 +9,195 @@ #include #include #include +#include #include #include #include +#include -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; }