mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2025-12-08 19:25:01 +00:00
Dedicates unicode collation protocol functions into separate user library to prevent code duplication across several user utilities
516 lines
12 KiB
C
516 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 <UserUnicodeCollation.h>
|
|
#include <string.h>
|
|
|
|
#define OPEN_FILE_MODES_COUNT 3
|
|
|
|
STATIC UINTN mFuzzOffset;
|
|
STATIC UINTN mFuzzSize;
|
|
STATIC CONST UINT8 *mFuzzPointer;
|
|
|
|
STATIC EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *mEfiSfsInterface;
|
|
|
|
STATIC UINT64 mOpenFileModes[OPEN_FILE_MODES_COUNT] = { EFI_FILE_MODE_READ, EFI_FILE_MODE_WRITE, EFI_FILE_MODE_CREATE };
|
|
|
|
/**
|
|
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
|
|
)
|
|
{
|
|
OcUnicodeCollationInitializeMappingTables ();
|
|
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 EngStriColl (NULL, 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;
|
|
}
|
|
|
|
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 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;
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
STATIC
|
|
INT32
|
|
TestExt4Dxe (
|
|
CONST UINT8 *FuzzData,
|
|
UINTN FuzzSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EXT4_PARTITION *Part;
|
|
EXT4_FILE *File;
|
|
EFI_FILE_PROTOCOL *This;
|
|
EFI_DISK_IO_PROTOCOL *DiskIo;
|
|
EFI_BLOCK_IO_PROTOCOL *BlockIo;
|
|
EFI_HANDLE DeviceHandle;
|
|
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;
|
|
mEfiSfsInterface = NULL;
|
|
|
|
DeviceHandle = (EFI_HANDLE)0xDEADBEAFULL;
|
|
|
|
//
|
|
// Construct file name
|
|
//
|
|
FileName = AllocateZeroPool (BufferSize);
|
|
if (FileName == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
ASAN_CHECK_MEMORY_REGION (FileName, BufferSize);
|
|
|
|
if ((mFuzzSize - mFuzzOffset) < BufferSize) {
|
|
FreePool (FileName);
|
|
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) {
|
|
FreePool (FileName);
|
|
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 (FileName);
|
|
FreePool (DiskIo);
|
|
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 (FileName);
|
|
FreePool (DiskIo);
|
|
FreePool (BlockIo);
|
|
return 0;
|
|
}
|
|
|
|
ASAN_CHECK_MEMORY_REGION (BlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));
|
|
|
|
//
|
|
// Check Ext4 SuperBlock magic like it done
|
|
// in Ext4IsBindingSupported routine
|
|
//
|
|
if (!Ext4SuperblockCheckMagic (DiskIo, BlockIo)) {
|
|
// Don't halt on bad magic, just keep going
|
|
DEBUG ((DEBUG_WARN, "[ext4] Superblock contains bad magic \n"));
|
|
}
|
|
|
|
//
|
|
// Open partition
|
|
//
|
|
Status = Ext4OpenPartition (DeviceHandle, DiskIo, NULL, BlockIo);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "[ext4] Error mounting: %r\n", Status));
|
|
FreePool (FileName);
|
|
FreePool (BlockIo->Media);
|
|
FreePool (BlockIo);
|
|
FreePool (DiskIo);
|
|
return 0;
|
|
}
|
|
|
|
Part = (EXT4_PARTITION *)mEfiSfsInterface;
|
|
|
|
ASAN_CHECK_MEMORY_REGION (Part, sizeof (EXT4_PARTITION));
|
|
|
|
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;
|
|
Status = Ext4SetPosition (NewHandle, Position);
|
|
if (!EFI_ERROR (Status)) {
|
|
Buffer = NULL;
|
|
BufferSize = 0;
|
|
Status = Ext4ReadFile (NewHandle, &BufferSize, Buffer);
|
|
|
|
ASSERT (Status == EFI_DEVICE_ERROR);
|
|
}
|
|
}
|
|
|
|
Ext4Delete (NewHandle);
|
|
}
|
|
}
|
|
|
|
FreeAll (FileName, Part);
|
|
|
|
return 0;
|
|
}
|
|
|
|
INT32
|
|
LLVMFuzzerTestOneInput (
|
|
CONST UINT8 *FuzzData,
|
|
UINTN FuzzSize
|
|
)
|
|
{
|
|
VOID *NewData;
|
|
|
|
if (FuzzSize == 0) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Override InstallMultipleProtocolInterfaces with custom wrapper
|
|
//
|
|
gBS->InstallMultipleProtocolInterfaces = WrapInstallMultipleProtocolInterfaces;
|
|
|
|
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;
|
|
}
|