mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2025-12-08 19:25:01 +00:00
Trying to open file with different modes in loop (read, write, create). Adds memory allocation mutations based on given allocation mask to imitate allocation errors. This change should increase code coverage by reaching branches with memory allocation error
545 lines
12 KiB
C
545 lines
12 KiB
C
/** @file
|
|
Copyright (c) 2022, Mikhail Krichanov. All rights reserved.
|
|
SPDX-License-Identifier: BSD-3-Clause
|
|
**/
|
|
#include <Ext4Dxe.h>
|
|
|
|
#include <UserFile.h>
|
|
#include <UserGlobalVar.h>
|
|
#include <UserMemory.h>
|
|
#include <string.h>
|
|
|
|
#define OPEN_FILE_MODES_COUNT 3
|
|
#define MAP_TABLE_SIZE 0x100
|
|
#define CHAR_FAT_VALID 0x01
|
|
|
|
#define TO_UPPER(a) (CHAR16) ((a) <= 0xFF ? mEngUpperMap[a] : (a))
|
|
|
|
UINT8 _gPcd_FixedAtBuild_PcdUefiVariableDefaultLang[4] = { 101, 110, 103, 0 };
|
|
UINT8 _gPcd_FixedAtBuild_PcdUefiVariableDefaultPlatformLang[6] = { 101, 110, 45, 85, 83, 0 };
|
|
|
|
STATIC UINTN mFuzzOffset;
|
|
STATIC UINTN mFuzzSize;
|
|
STATIC CONST UINT8 *mFuzzPointer;
|
|
|
|
STATIC UINT64 mOpenFileModes[OPEN_FILE_MODES_COUNT] = { EFI_FILE_MODE_READ, EFI_FILE_MODE_WRITE, EFI_FILE_MODE_CREATE };
|
|
|
|
CHAR8 mEngUpperMap[MAP_TABLE_SIZE];
|
|
CHAR8 mEngLowerMap[MAP_TABLE_SIZE];
|
|
CHAR8 mEngInfoMap[MAP_TABLE_SIZE];
|
|
|
|
CHAR8 mOtherChars[] = {
|
|
'0',
|
|
'1',
|
|
'2',
|
|
'3',
|
|
'4',
|
|
'5',
|
|
'6',
|
|
'7',
|
|
'8',
|
|
'9',
|
|
'\\',
|
|
'.',
|
|
'_',
|
|
'^',
|
|
'$',
|
|
'~',
|
|
'!',
|
|
'#',
|
|
'%',
|
|
'&',
|
|
'-',
|
|
'{',
|
|
'}',
|
|
'(',
|
|
')',
|
|
'@',
|
|
'`',
|
|
'\'',
|
|
'\0'
|
|
};
|
|
|
|
VOID
|
|
UnicodeCollationInitializeMappingTables (
|
|
VOID
|
|
)
|
|
{
|
|
UINTN Index;
|
|
UINTN Index2;
|
|
|
|
//
|
|
// Initialize mapping tables for the supported languages
|
|
//
|
|
for (Index = 0; Index < MAP_TABLE_SIZE; Index++) {
|
|
mEngUpperMap[Index] = (CHAR8)Index;
|
|
mEngLowerMap[Index] = (CHAR8)Index;
|
|
mEngInfoMap[Index] = 0;
|
|
|
|
if (((Index >= 'a') && (Index <= 'z')) || ((Index >= 0xe0) && (Index <= 0xf6)) || ((Index >= 0xf8) && (Index <= 0xfe))) {
|
|
Index2 = Index - 0x20;
|
|
mEngUpperMap[Index] = (CHAR8)Index2;
|
|
mEngLowerMap[Index2] = (CHAR8)Index;
|
|
|
|
mEngInfoMap[Index] |= CHAR_FAT_VALID;
|
|
mEngInfoMap[Index2] |= CHAR_FAT_VALID;
|
|
}
|
|
}
|
|
|
|
for (Index = 0; mOtherChars[Index] != 0; Index++) {
|
|
Index2 = mOtherChars[Index];
|
|
mEngInfoMap[Index2] |= CHAR_FAT_VALID;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Performs a case-insensitive comparison of two Null-terminated strings.
|
|
|
|
@param This Protocol instance pointer.
|
|
@param Str1 A pointer to a Null-terminated string.
|
|
@param Str2 A pointer to a Null-terminated string.
|
|
|
|
@retval 0 Str1 is equivalent to Str2
|
|
@retval > 0 Str1 is lexically greater than Str2
|
|
@retval < 0 Str1 is lexically less than Str2
|
|
|
|
**/
|
|
INTN
|
|
StriColl (
|
|
IN CHAR16 *Str1,
|
|
IN CHAR16 *Str2
|
|
)
|
|
{
|
|
while (*Str1 != 0) {
|
|
if (TO_UPPER (*Str1) != TO_UPPER (*Str2)) {
|
|
break;
|
|
}
|
|
|
|
Str1 += 1;
|
|
Str2 += 1;
|
|
}
|
|
|
|
return TO_UPPER (*Str1) - TO_UPPER (*Str2);
|
|
}
|
|
|
|
/**
|
|
Initialises Unicode collation, which is needed for case-insensitive string comparisons
|
|
within the driver (a good example of an application of this is filename comparison).
|
|
|
|
@param[in] DriverHandle Handle to the driver image.
|
|
|
|
@retval EFI_SUCCESS Unicode collation was successfully initialised.
|
|
@retval !EFI_SUCCESS Failure.
|
|
**/
|
|
EFI_STATUS
|
|
Ext4InitialiseUnicodeCollation (
|
|
EFI_HANDLE DriverHandle
|
|
)
|
|
{
|
|
UnicodeCollationInitializeMappingTables ();
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Does a case-insensitive string comparison. Refer to EFI_UNICODE_COLLATION_PROTOCOL's StriColl
|
|
for more details.
|
|
|
|
@param[in] Str1 Pointer to a null terminated string.
|
|
@param[in] Str2 Pointer to a null terminated string.
|
|
|
|
@retval 0 Str1 is equivalent to Str2.
|
|
@retval >0 Str1 is lexically greater than Str2.
|
|
@retval <0 Str1 is lexically less than Str2.
|
|
**/
|
|
INTN
|
|
Ext4StrCmpInsensitive (
|
|
IN CHAR16 *Str1,
|
|
IN CHAR16 *Str2
|
|
)
|
|
{
|
|
return StriColl (Str1, Str2);
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
EfiLibInstallAllDriverProtocols2 (
|
|
IN CONST EFI_HANDLE ImageHandle,
|
|
IN CONST EFI_SYSTEM_TABLE *SystemTable,
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
|
|
IN EFI_HANDLE DriverBindingHandle,
|
|
IN CONST EFI_COMPONENT_NAME_PROTOCOL *ComponentName, OPTIONAL
|
|
IN CONST EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2, OPTIONAL
|
|
IN CONST EFI_DRIVER_CONFIGURATION_PROTOCOL *DriverConfiguration, OPTIONAL
|
|
IN CONST EFI_DRIVER_CONFIGURATION2_PROTOCOL *DriverConfiguration2, OPTIONAL
|
|
IN CONST EFI_DRIVER_DIAGNOSTICS_PROTOCOL *DriverDiagnostics, OPTIONAL
|
|
IN CONST EFI_DRIVER_DIAGNOSTICS2_PROTOCOL *DriverDiagnostics2 OPTIONAL
|
|
)
|
|
{
|
|
abort ();
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
EfiLibUninstallAllDriverProtocols2 (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
|
|
IN CONST EFI_COMPONENT_NAME_PROTOCOL *ComponentName, OPTIONAL
|
|
IN CONST EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2, OPTIONAL
|
|
IN CONST EFI_DRIVER_CONFIGURATION_PROTOCOL *DriverConfiguration, OPTIONAL
|
|
IN CONST EFI_DRIVER_CONFIGURATION2_PROTOCOL *DriverConfiguration2, OPTIONAL
|
|
IN CONST EFI_DRIVER_DIAGNOSTICS_PROTOCOL *DriverDiagnostics, OPTIONAL
|
|
IN CONST EFI_DRIVER_DIAGNOSTICS2_PROTOCOL *DriverDiagnostics2 OPTIONAL
|
|
)
|
|
{
|
|
abort ();
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
VOID
|
|
FreeAll (
|
|
IN CHAR16 *FileName,
|
|
IN EXT4_PARTITION *Part
|
|
)
|
|
{
|
|
FreePool (FileName);
|
|
|
|
if (Part != NULL) {
|
|
if (Part->DiskIo != NULL) {
|
|
FreePool (Part->DiskIo);
|
|
}
|
|
|
|
if (Part->BlockIo != NULL) {
|
|
if (Part->BlockIo->Media != NULL) {
|
|
FreePool (Part->BlockIo->Media);
|
|
}
|
|
|
|
FreePool (Part->BlockIo);
|
|
}
|
|
|
|
if (Part->Root != NULL) {
|
|
Ext4UnmountAndFreePartition (Part);
|
|
} else if (Part != NULL) {
|
|
FreePool (Part);
|
|
}
|
|
}
|
|
}
|
|
|
|
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_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
CopyMem (Buffer, mFuzzPointer, BufferSize);
|
|
mFuzzPointer += BufferSize;
|
|
mFuzzOffset += BufferSize;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
ConfigureMemoryAllocations (
|
|
IN CONST UINT8 *Data,
|
|
IN UINTN Size
|
|
)
|
|
{
|
|
UINT32 Off;
|
|
|
|
mPoolAllocationIndex = 0;
|
|
mPageAllocationIndex = 0;
|
|
|
|
SetPoolAllocationSizeLimit (BASE_4GB);
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
STATIC
|
|
INT32
|
|
TestExt4Dxe (
|
|
CONST UINT8 *FuzzData,
|
|
UINTN FuzzSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EXT4_PARTITION *Part;
|
|
EXT4_FILE *File;
|
|
EFI_FILE_PROTOCOL *This;
|
|
UINTN BufferSize;
|
|
VOID *Buffer;
|
|
EFI_FILE_PROTOCOL *NewHandle;
|
|
CHAR16 *FileName;
|
|
VOID *Info;
|
|
UINTN Len;
|
|
UINT64 Position;
|
|
UINT64 FileSize;
|
|
UINTN Index;
|
|
|
|
Part = NULL;
|
|
BufferSize = 100;
|
|
|
|
mFuzzOffset = 0;
|
|
mFuzzSize = FuzzSize;
|
|
mFuzzPointer = FuzzData;
|
|
|
|
//
|
|
// Construct file name
|
|
//
|
|
FileName = AllocateZeroPool (BufferSize);
|
|
if (FileName == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
ASAN_CHECK_MEMORY_REGION (FileName, BufferSize);
|
|
|
|
if ((mFuzzSize - mFuzzOffset) < BufferSize) {
|
|
FreeAll (FileName, Part);
|
|
return 0;
|
|
}
|
|
|
|
CopyMem (FileName, mFuzzPointer, BufferSize - 2);
|
|
mFuzzPointer += BufferSize - 2;
|
|
mFuzzOffset += BufferSize - 2;
|
|
|
|
//
|
|
// Construct File System
|
|
//
|
|
Part = AllocateZeroPool (sizeof (EXT4_PARTITION));
|
|
if (Part == NULL) {
|
|
FreeAll (FileName, Part);
|
|
return 0;
|
|
}
|
|
|
|
ASAN_CHECK_MEMORY_REGION (Part, sizeof (EXT4_PARTITION));
|
|
|
|
InitializeListHead (&Part->OpenFiles);
|
|
|
|
Part->DiskIo = AllocateZeroPool (sizeof (EFI_DISK_IO_PROTOCOL));
|
|
if (Part->DiskIo == NULL) {
|
|
FreeAll (FileName, Part);
|
|
return 0;
|
|
}
|
|
|
|
ASAN_CHECK_MEMORY_REGION (Part->DiskIo, sizeof (EFI_DISK_IO_PROTOCOL));
|
|
|
|
Part->DiskIo->ReadDisk = FuzzReadDisk;
|
|
|
|
Part->BlockIo = AllocateZeroPool (sizeof (EFI_BLOCK_IO_PROTOCOL));
|
|
if (Part->BlockIo == NULL) {
|
|
FreeAll (FileName, Part);
|
|
return 0;
|
|
}
|
|
|
|
ASAN_CHECK_MEMORY_REGION (Part->BlockIo, sizeof (EFI_BLOCK_IO_PROTOCOL));
|
|
|
|
Part->BlockIo->Media = AllocateZeroPool (sizeof (EFI_BLOCK_IO_MEDIA));
|
|
if (Part->BlockIo->Media == NULL) {
|
|
FreeAll (FileName, Part);
|
|
return 0;
|
|
}
|
|
|
|
ASAN_CHECK_MEMORY_REGION (Part->BlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));
|
|
|
|
Status = Ext4OpenSuperblock (Part);
|
|
if (EFI_ERROR (Status)) {
|
|
FreeAll (FileName, Part);
|
|
return 0;
|
|
}
|
|
|
|
Part->Interface.Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;
|
|
Part->Interface.OpenVolume = Ext4OpenVolume;
|
|
|
|
This = (EFI_FILE_PROTOCOL *)Part->Root;
|
|
|
|
//
|
|
// Test Ext4Dxe driver
|
|
//
|
|
for (Index = 0; Index < OPEN_FILE_MODES_COUNT; Index++) {
|
|
Status = Ext4Open (This, &NewHandle, FileName, mOpenFileModes[Index], 0);
|
|
if (Status == EFI_SUCCESS) {
|
|
Buffer = NULL;
|
|
BufferSize = 0;
|
|
Status = Ext4ReadFile (NewHandle, &BufferSize, Buffer);
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
Buffer = AllocateZeroPool (BufferSize);
|
|
if (Buffer == NULL) {
|
|
FreeAll (FileName, Part);
|
|
return 0;
|
|
}
|
|
|
|
ASAN_CHECK_MEMORY_REGION (Buffer, BufferSize);
|
|
|
|
Ext4ReadFile (NewHandle, &BufferSize, Buffer);
|
|
|
|
Ext4WriteFile (NewHandle, &BufferSize, Buffer);
|
|
|
|
FreePool (Buffer);
|
|
}
|
|
|
|
Len = 0;
|
|
Info = NULL;
|
|
Status = Ext4GetInfo (NewHandle, &gEfiFileInfoGuid, &Len, Info);
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
Info = AllocateZeroPool (Len);
|
|
if (Info == NULL) {
|
|
FreeAll (FileName, Part);
|
|
return 0;
|
|
}
|
|
|
|
Ext4GetInfo (NewHandle, &gEfiFileInfoGuid, &Len, Info);
|
|
FreePool (Info);
|
|
}
|
|
|
|
Len = 0;
|
|
Status = Ext4GetInfo (NewHandle, &gEfiFileSystemInfoGuid, &Len, Info);
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
Info = AllocateZeroPool (Len);
|
|
if (Info == NULL) {
|
|
FreeAll (FileName, Part);
|
|
return 0;
|
|
}
|
|
|
|
Ext4GetInfo (NewHandle, &gEfiFileSystemInfoGuid, &Len, Info);
|
|
FreePool (Info);
|
|
}
|
|
|
|
Len = 0;
|
|
Status = Ext4GetInfo (NewHandle, &gEfiFileSystemVolumeLabelInfoIdGuid, &Len, Info);
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
Info = AllocateZeroPool (Len);
|
|
if (Info == NULL) {
|
|
FreeAll (FileName, Part);
|
|
return 0;
|
|
}
|
|
|
|
Ext4GetInfo (NewHandle, &gEfiFileSystemVolumeLabelInfoIdGuid, &Len, Info);
|
|
FreePool (Info);
|
|
}
|
|
|
|
Ext4SetInfo (NewHandle, &gEfiFileSystemVolumeLabelInfoIdGuid, Len, Info);
|
|
|
|
//
|
|
// Test position functions
|
|
//
|
|
Ext4GetPosition (NewHandle, &Position);
|
|
Ext4SetPosition (NewHandle, Position);
|
|
|
|
//
|
|
// Trying to reach the end of file and read/write it
|
|
//
|
|
Position = (UINT64)-1;
|
|
Status = Ext4SetPosition (NewHandle, Position);
|
|
if (!EFI_ERROR (Status)) {
|
|
Buffer = NULL;
|
|
BufferSize = 0;
|
|
Status = Ext4ReadFile (NewHandle, &BufferSize, Buffer);
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
Buffer = AllocateZeroPool (BufferSize);
|
|
if (Buffer == NULL) {
|
|
FreeAll (FileName, Part);
|
|
return 0;
|
|
}
|
|
|
|
ASAN_CHECK_MEMORY_REGION (Buffer, BufferSize);
|
|
|
|
Ext4ReadFile (NewHandle, &BufferSize, Buffer);
|
|
|
|
Ext4WriteFile (NewHandle, &BufferSize, Buffer);
|
|
|
|
FreePool (Buffer);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Trying to reach out of bound of FileSize
|
|
//
|
|
File = EXT4_FILE_FROM_THIS (NewHandle);
|
|
FileSize = EXT4_INODE_SIZE (File->Inode);
|
|
if (FileSize < (UINT64)-1 - 1) {
|
|
Position = FileSize + 1;
|
|
Ext4SetPosition (NewHandle, Position);
|
|
}
|
|
|
|
Ext4Delete (NewHandle);
|
|
}
|
|
}
|
|
|
|
FreeAll (FileName, Part);
|
|
|
|
return 0;
|
|
}
|
|
|
|
INT32
|
|
LLVMFuzzerTestOneInput (
|
|
CONST UINT8 *FuzzData,
|
|
UINTN FuzzSize
|
|
)
|
|
{
|
|
VOID *NewData;
|
|
|
|
if (FuzzSize == 0) {
|
|
return 0;
|
|
}
|
|
|
|
ConfigureMemoryAllocations (FuzzData, FuzzSize);
|
|
|
|
NewData = AllocatePool (FuzzSize);
|
|
if (NewData != NULL) {
|
|
CopyMem (NewData, FuzzData, FuzzSize);
|
|
TestExt4Dxe (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;
|
|
}
|