Savva Mitrofanov 344a2080b2 User: Adds UserUnicodeCollation library
Dedicates unicode collation protocol functions into separate user
library to prevent code duplication across several user utilities
2023-03-07 21:28:51 +06:00

505 lines
11 KiB
C

/** @file
Copyright (c) 2023, Savva Mitrofanov. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
**/
#include <Fat.h>
#include <UserFile.h>
#include <UserGlobalVar.h>
#include <UserMemory.h>
#include <UserUnicodeCollation.h>
#include <string.h>
extern EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollationInterface;
STATIC EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *mEfiSfsInterface;
UINTN mFuzzOffset;
UINTN mFuzzSize;
CONST UINT8 *mFuzzPointer;
EFI_STATUS
EFIAPI
FuzzBlockIoFlushBlocks (
IN EFI_BLOCK_IO_PROTOCOL *This
)
{
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
FuzzReadDisk (
IN EFI_DISK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN UINT64 Offset,
IN UINTN BufferSize,
OUT VOID *Buffer
)
{
if (Buffer == NULL) {
return EFI_INVALID_PARAMETER;
}
if ((mFuzzSize - mFuzzOffset) < BufferSize) {
return EFI_DEVICE_ERROR;
}
CopyMem (Buffer, mFuzzPointer, BufferSize);
mFuzzPointer += BufferSize;
mFuzzOffset += BufferSize;
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
WrapInstallMultipleProtocolInterfaces (
IN OUT EFI_HANDLE *Handle,
...
)
{
VA_LIST Args;
EFI_STATUS Status;
EFI_GUID *Protocol;
VOID *Interface;
if (Handle == NULL) {
return EFI_INVALID_PARAMETER;
}
VA_START (Args, Handle);
for (Status = EFI_SUCCESS; !EFI_ERROR (Status);) {
//
// If protocol is NULL, then it's the end of the list
//
Protocol = VA_ARG (Args, EFI_GUID *);
if (Protocol == NULL) {
break;
}
Interface = VA_ARG (Args, VOID *);
//
// If this is Sfs protocol then save interface into global state
//
if (CompareGuid (Protocol, &gEfiSimpleFileSystemProtocolGuid)) {
mEfiSfsInterface = Interface;
}
}
VA_END (Args);
return Status;
}
VOID
FreeAll (
IN CHAR16 *FileName,
IN FAT_VOLUME *Volume,
IN EFI_FILE_PROTOCOL *RootDirInstance
)
{
FreePool (FileName);
//
// Closes root directory
//
if (RootDirInstance != NULL) {
FatClose (RootDirInstance);
}
//
// Abandon volume structure
//
if (Volume != NULL) {
if (Volume->DiskIo != NULL) {
FreePool (Volume->DiskIo);
}
if (Volume->BlockIo != NULL) {
if (Volume->BlockIo->Media != NULL) {
FreePool (Volume->BlockIo->Media);
}
FreePool (Volume->BlockIo);
}
if (Volume->Root != NULL) {
FatSetVolumeError (
Volume->Root,
EFI_NO_MEDIA
);
}
Volume->Valid = FALSE;
FatCleanupVolume (Volume, NULL, EFI_SUCCESS, NULL);
}
}
#ifdef MEMORY_MUTATIONS
STATIC
VOID
ConfigureMemoryAllocations (
IN CONST UINT8 *Data,
IN UINTN Size
)
{
UINT32 Off;
mPoolAllocationIndex = 0;
mPageAllocationIndex = 0;
//
// Limit single pool allocation size to 3GB
//
SetPoolAllocationSizeLimit (BASE_1GB | BASE_2GB);
Off = sizeof (UINT64);
if (Size >= Off) {
CopyMem (&mPoolAllocationMask, &Data[Size - Off], sizeof (UINT64));
} else {
mPoolAllocationMask = MAX_UINT64;
}
Off += sizeof (UINT64);
if (Size >= Off) {
CopyMem (&mPageAllocationMask, &Data[Size - Off], sizeof (UINT64));
} else {
mPageAllocationMask = MAX_UINT64;
}
}
#endif
STATIC
INT32
TestFatDxe (
CONST UINT8 *FuzzData,
UINTN FuzzSize
)
{
EFI_STATUS Status;
EFI_FILE_PROTOCOL *VolumeRootDir;
UINTN BufferSize;
VOID *Buffer;
EFI_FILE_PROTOCOL *NewHandle;
CHAR16 *FileName;
VOID *Info;
UINTN Len;
UINT64 Position;
EFI_DISK_IO_PROTOCOL *DiskIo;
EFI_BLOCK_IO_PROTOCOL *BlockIo;
FAT_VOLUME *Volume;
FAT_IFILE *FileInstance;
UINT64 FileSize;
EFI_HANDLE DeviceHandle;
BufferSize = 100;
mFuzzOffset = 0;
mFuzzSize = FuzzSize;
mFuzzPointer = FuzzData;
mEfiSfsInterface = NULL;
Volume = NULL;
VolumeRootDir = NULL;
Position = 0;
DeviceHandle = (EFI_HANDLE)0xDEADDEADULL;
//
// Construct File Name
//
FileName = AllocateZeroPool (BufferSize);
if (FileName == NULL) {
return 0;
}
ASAN_CHECK_MEMORY_REGION (FileName, BufferSize);
if ((mFuzzSize - mFuzzOffset) < BufferSize) {
FreeAll (FileName, Volume, VolumeRootDir);
return 0;
}
CopyMem (FileName, mFuzzPointer, BufferSize - 2);
mFuzzPointer += BufferSize - 2;
mFuzzOffset += BufferSize - 2;
//
// Construct BlockIo and DiskIo interfaces
//
DiskIo = AllocateZeroPool (sizeof (EFI_DISK_IO_PROTOCOL));
if (DiskIo == NULL) {
FreeAll (FileName, Volume, VolumeRootDir);
return 0;
}
ASAN_CHECK_MEMORY_REGION (DiskIo, sizeof (EFI_DISK_IO_PROTOCOL));
DiskIo->ReadDisk = FuzzReadDisk;
BlockIo = AllocateZeroPool (sizeof (EFI_BLOCK_IO_PROTOCOL));
if (BlockIo == NULL) {
FreePool (DiskIo);
FreeAll (FileName, Volume, VolumeRootDir);
return 0;
}
ASAN_CHECK_MEMORY_REGION (BlockIo, sizeof (EFI_BLOCK_IO_PROTOCOL));
BlockIo->Media = AllocateZeroPool (sizeof (EFI_BLOCK_IO_MEDIA));
if (BlockIo->Media == NULL) {
FreePool (DiskIo);
FreePool (BlockIo);
FreeAll (FileName, Volume, VolumeRootDir);
return 0;
}
ASAN_CHECK_MEMORY_REGION (BlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));
BlockIo->FlushBlocks = FuzzBlockIoFlushBlocks;
//
// Allocate volume
//
Status = FatAllocateVolume (DeviceHandle, DiskIo, NULL, BlockIo);
if (EFI_ERROR (Status)) {
FreePool (BlockIo->Media);
FreePool (BlockIo);
FreePool (DiskIo);
FreeAll (FileName, Volume, VolumeRootDir);
return 0;
}
//
// Open volume root dir
//
Status = FatOpenVolume (mEfiSfsInterface, &VolumeRootDir);
if (EFI_ERROR (Status)) {
FreeAll (FileName, Volume, VolumeRootDir);
return 0;
}
Volume = VOLUME_FROM_VOL_INTERFACE (mEfiSfsInterface);
//
// Open File
//
Status = FatOpen (VolumeRootDir, &NewHandle, FileName, EFI_FILE_MODE_READ, 0);
if (Status == EFI_SUCCESS) {
Buffer = NULL;
BufferSize = 0;
Status = FatRead (NewHandle, &BufferSize, Buffer);
if (Status == EFI_BUFFER_TOO_SMALL) {
Buffer = AllocateZeroPool (BufferSize);
if (Buffer == NULL) {
FatClose (NewHandle);
FreeAll (FileName, Volume, VolumeRootDir);
return 0;
}
ASAN_CHECK_MEMORY_REGION (Buffer, BufferSize);
FatRead (NewHandle, &BufferSize, Buffer);
FatWrite (NewHandle, &BufferSize, Buffer);
FatFlush (NewHandle);
FreePool (Buffer);
}
//
// Set/Get file info
//
Len = 0;
Info = NULL;
Status = FatGetInfo (NewHandle, &gEfiFileInfoGuid, &Len, Info);
if (Status == EFI_BUFFER_TOO_SMALL) {
Info = AllocateZeroPool (Len);
if (Info == NULL) {
FatClose (NewHandle);
FreeAll (FileName, Volume, VolumeRootDir);
return 0;
}
Status = FatGetInfo (NewHandle, &gEfiFileInfoGuid, &Len, Info);
if (!EFI_ERROR (Status)) {
//
// Try to set this info back
//
FatSetInfo (NewHandle, &gEfiFileInfoGuid, Len, Info);
FreePool (Info);
}
}
Len = 0;
Info = NULL;
Status = FatGetInfo (NewHandle, &gEfiFileSystemInfoGuid, &Len, Info);
if (Status == EFI_BUFFER_TOO_SMALL) {
Info = AllocateZeroPool (Len);
if (Info == NULL) {
FatClose (NewHandle);
FreeAll (FileName, Volume, VolumeRootDir);
return 0;
}
Status = FatGetInfo (NewHandle, &gEfiFileSystemInfoGuid, &Len, Info);
if (!EFI_ERROR (Status)) {
//
// Try to set this info back
//
FatSetInfo (NewHandle, &gEfiFileSystemInfoGuid, Len, Info);
FreePool (Info);
}
}
Len = 0;
Info = NULL;
Status = FatGetInfo (NewHandle, &gEfiFileSystemVolumeLabelInfoIdGuid, &Len, Info);
if (Status == EFI_BUFFER_TOO_SMALL) {
Info = AllocateZeroPool (Len);
if (Info == NULL) {
FatClose (NewHandle);
FreeAll (FileName, Volume, VolumeRootDir);
return 0;
}
Status = FatGetInfo (NewHandle, &gEfiFileSystemVolumeLabelInfoIdGuid, &Len, Info);
if (!EFI_ERROR (Status)) {
//
// Try to set this info back
//
FatSetInfo (NewHandle, &gEfiFileSystemVolumeLabelInfoIdGuid, Len, Info);
FreePool (Info);
}
}
//
// Test position functions
//
FatGetPosition (NewHandle, &Position);
FatSetPosition (NewHandle, Position);
//
// Trying to reach the end of file and read/write it
//
Position = (UINT64)-1;
Status = FatSetPosition (NewHandle, Position);
if (!EFI_ERROR (Status)) {
Buffer = NULL;
BufferSize = 0;
Status = FatRead (NewHandle, &BufferSize, Buffer);
if (Status == EFI_BUFFER_TOO_SMALL) {
Buffer = AllocateZeroPool (BufferSize);
if (Buffer == NULL) {
FatClose (NewHandle);
FreeAll (FileName, Volume, VolumeRootDir);
return 0;
}
ASAN_CHECK_MEMORY_REGION (Buffer, BufferSize);
FatRead (NewHandle, &BufferSize, Buffer);
FatWrite (NewHandle, &BufferSize, Buffer);
FatFlush (NewHandle);
FreePool (Buffer);
}
}
//
// Trying to reach out of bound of FileSize
//
FileInstance = IFILE_FROM_FHAND (NewHandle);
FileSize = FileInstance->OFile->FileSize;
if (FileSize < (UINT64)-1 - 1) {
Position = FileSize + 1;
Status = FatSetPosition (NewHandle, Position);
if (!EFI_ERROR (Status)) {
Buffer = NULL;
BufferSize = 0;
Status = FatRead (NewHandle, &BufferSize, Buffer);
ASSERT (Status == EFI_DEVICE_ERROR);
}
}
FatDelete (NewHandle);
}
FreeAll (FileName, Volume, VolumeRootDir);
return 0;
}
INT32
LLVMFuzzerTestOneInput (
CONST UINT8 *FuzzData,
UINTN FuzzSize
)
{
VOID *NewData;
if (FuzzSize == 0) {
return 0;
}
// Set up unicode collation protocol
UserUnicodeCollationInstallProtocol (&mUnicodeCollationInterface);
//
// Override InstallMultipleProtocolInterfaces with custom wrapper
//
gBS->InstallMultipleProtocolInterfaces = WrapInstallMultipleProtocolInterfaces;
#ifdef MEMORY_MUTATIONS
ConfigureMemoryAllocations (FuzzData, FuzzSize);
#else
SetPoolAllocationSizeLimit (BASE_1GB | BASE_2GB);
#endif
NewData = AllocatePool (FuzzSize);
if (NewData != NULL) {
CopyMem (NewData, FuzzData, FuzzSize);
TestFatDxe (NewData, FuzzSize);
FreePool (NewData);
}
DEBUG ((
DEBUG_POOL | DEBUG_PAGE,
"UMEM: Allocated %u pools %u pages\n",
(UINT32)mPoolAllocations,
(UINT32)mPageAllocations
));
return 0;
}
int
ENTRY_POINT (
int argc,
char **argv
)
{
uint32_t f;
uint8_t *b;
if ((b = UserReadFile ((argc > 1) ? argv[1] : "in.bin", &f)) == NULL) {
DEBUG ((DEBUG_ERROR, "Read fail\n"));
return -1;
}
LLVMFuzzerTestOneInput (b, f);
FreePool (b);
return 0;
}