[BOOTLIB]:

- Implement BiInitializeAndValidateHive, BiLoadHive. Leveraging our existing cmlib and the previously committed code, we are now able to read the BCD file, parse it as a registry hive, and lookup the BCD Objects subkey! The BCD Data Store is now available to the Boot Manager (which also validates that reading from ETFS works).

svn path=/trunk/; revision=69454
This commit is contained in:
Alex Ionescu 2015-10-05 07:25:27 +00:00
parent 0f6b79b197
commit 1a9d2da6dc
2 changed files with 384 additions and 12 deletions

View file

@ -373,7 +373,7 @@ BmFatalErrorEx (
/* Build the error string */
swprintf(FormatString,
L"\nAn error occurred (%08x) while attempting"
L"\nAn error occurred (%08x) while attempting "
L"to read the boot configuration data file %s\n",
ErrorStatus,
Buffer);
@ -685,7 +685,7 @@ BmMain (
PBL_RETURN_ARGUMENTS ReturnArguments;
BOOLEAN RebootOnError;
PGUID AppIdentifier;
// HANDLE BcdHandle;
HANDLE BcdHandle;
EfiPrintf(L"ReactOS UEFI Boot Manager Initializing...\n");
@ -733,8 +733,8 @@ BmMain (
BmFwInitializeBootDirectoryPath();
/* Load and initialize the boot configuration database (BCD) */
//Status = BmOpenDataStore(&BcdHandle);
//EfiPrintf(L"BCD Open: %lx\r\n", Status);
Status = BmOpenDataStore(&BcdHandle);
EfiPrintf(L"BCD Open: %lx\r\n", Status);
/* do more stuff!! */
EfiPrintf(L"We are A-OK!\r\n");

View file

@ -451,15 +451,18 @@ BlGetBootOptionBoolean (
return Status;
}
#define BI_FLUSH_HIVE 0x01
#define BI_FLUSH_HIVE 0x01
#define BI_HIVE_WRITEABLE 0x02
typedef struct _BI_KEY_HIVE
{
PVOID ImageBase;
PHBASE_BLOCK BaseBlock;
ULONG HiveSize;
PBL_FILE_PATH_DESCRIPTOR FilePath;
CMHIVE Hive;
LONG ReferenceCount;
ULONG Flags;
PCM_KEY_NODE RootNode;
} BI_KEY_HIVE, *PBI_KEY_HIVE;
typedef struct _BI_KEY_OBJECT
@ -646,7 +649,7 @@ BiOpenKey(
}
/* We found it -- get the key node out of it */
ParentNode = (PCM_KEY_NODE)Hive->GetCellRoutine(Hive, KeyCell);
ParentNode = (PCM_KEY_NODE)HvGetCell(Hive, KeyCell);
if (!ParentNode)
{
Status = STATUS_REGISTRY_CORRUPT;
@ -699,16 +702,386 @@ Quickie:
return Status;
}
BOOLEAN BiHiveHashLibraryInitialized;
ULONGLONG HvSymcryptSeed;
BOOLEAN
HvIsInPlaceBaseBlockValid (
_In_ PHBASE_BLOCK BaseBlock
)
{
ULONG HiveLength, HeaderSum;
BOOLEAN Valid;
/* Assume failure */
Valid = FALSE;
/* Check for incorrect signature, type, version, or format */
if ((BaseBlock->Signature == 'fger') &&
(BaseBlock->Type == 0) &&
(BaseBlock->Major <= 1) &&
(BaseBlock->Minor <= 5) &&
(BaseBlock->Minor >= 3) &&
(BaseBlock->Format == 1))
{
/* Check for invalid hive size */
HiveLength = BaseBlock->Length;
if (HiveLength)
{
/* Check for misaligned or too large hive size */
if (!(HiveLength & 0xFFF) && HiveLength <= 0x7FFFE000)
{
/* Check for invalid header checksum */
HeaderSum = HvpHiveHeaderChecksum(BaseBlock);
if (HeaderSum == BaseBlock->CheckSum)
{
/* All good */
Valid = TRUE;
}
}
}
}
/* Return validity */
return Valid;
}
NTSTATUS
BiInitializeAndValidateHive (
_In_ PBI_KEY_HIVE Hive
)
{
ULONG HiveSize;
NTSTATUS Status;
/* Make sure the hive is at least the size of a base block */
if (Hive->HiveSize < sizeof(HBASE_BLOCK))
{
return STATUS_REGISTRY_CORRUPT;
}
/* Make sure that the base block accurately describes the size of the hive */
HiveSize = Hive->BaseBlock->Length + sizeof(HBASE_BLOCK);
if ((HiveSize < sizeof(HBASE_BLOCK)) || (HiveSize > Hive->HiveSize))
{
return STATUS_REGISTRY_CORRUPT;
}
/* Initialize a flat memory hive */
RtlZeroMemory(&Hive->Hive, sizeof(Hive->Hive));
Status = HvInitialize(&Hive->Hive.Hive,
HINIT_FLAT,
0,
0,
Hive->BaseBlock,
CmpAllocate,
CmpFree,
NULL,
NULL,
NULL,
NULL,
0,
NULL);
if (NT_SUCCESS(Status))
{
/* Cleanup volatile/old data */
CmPrepareHive(&Hive->Hive.Hive); // CmCheckRegistry
Status = STATUS_SUCCESS;
}
/* Return the final status */
return Status;
}
NTSTATUS
BiLoadHive (
_In_ PBL_FILE_PATH_DESCRIPTOR FilePath,
_Out_ PHANDLE HiveHandle
)
{
/* This is TODO */
EfiPrintf(L"Loading a hive is not yet implemented\r\n");
*HiveHandle = NULL;
return STATUS_NOT_IMPLEMENTED;
ULONG DeviceId;
PHBASE_BLOCK BaseBlock, NewBaseBlock;
PBI_KEY_OBJECT KeyObject;
PBI_KEY_HIVE BcdHive;
PBL_DEVICE_DESCRIPTOR BcdDevice;
ULONG PathLength, DeviceLength, HiveSize, HiveLength, NewHiveSize;
PWCHAR HiveName, LogName;
BOOLEAN HaveWriteAccess;
NTSTATUS Status;
PVOID LogData;
PHHIVE Hive;
UNICODE_STRING KeyString;
PCM_KEY_NODE RootNode;
HCELL_INDEX CellIndex;
/* Initialize variables */
DeviceId = -1;
BaseBlock = NULL;
BcdHive = NULL;
KeyObject = NULL;
LogData = NULL;
LogName = NULL;
/* Initialize the crypto seed */
if (!BiHiveHashLibraryInitialized)
{
HvSymcryptSeed = 0x82EF4D887A4E55C5;
BiHiveHashLibraryInitialized = TRUE;
}
/* Extract and validate the input path */
BcdDevice = (PBL_DEVICE_DESCRIPTOR)&FilePath->Path;
PathLength = FilePath->Length;
DeviceLength = BcdDevice->Size;
HiveName = (PWCHAR)((ULONG_PTR)BcdDevice + BcdDevice->Size);
if (PathLength <= DeviceLength)
{
/* Doesn't make sense, bail out */
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
/* Attempt to open the underlying device for RW access */
HaveWriteAccess = TRUE;
Status = BlpDeviceOpen(BcdDevice,
BL_DEVICE_READ_ACCESS | BL_DEVICE_WRITE_ACCESS,
0,
&DeviceId);
if (!NT_SUCCESS(Status))
{
/* Try for RO access instead */
HaveWriteAccess = FALSE;
Status = BlpDeviceOpen(BcdDevice, BL_DEVICE_READ_ACCESS, 0, &DeviceId);
if (!NT_SUCCESS(Status))
{
/* No access at all -- bail out */
goto Quickie;
}
}
/* Now try to load the hive on disk */
Status = BlImgLoadImageWithProgress2(DeviceId,
BlLoaderRegistry,
HiveName,
(PVOID*)&BaseBlock,
&HiveSize,
0,
FALSE,
NULL,
NULL);
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"Hive read failure: % lx\r\n", Status);
goto Quickie;
}
/* Allocate a hive structure */
BcdHive = BlMmAllocateHeap(sizeof(*BcdHive));
if (!BcdHive)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Initialize it */
RtlZeroMemory(BcdHive, sizeof(*BcdHive));
BcdHive->BaseBlock = BaseBlock;
BcdHive->HiveSize = HiveSize;
if (HaveWriteAccess)
{
BcdHive->Flags |= BI_HIVE_WRITEABLE;
}
/* Make sure the hive was at least one bin long */
if (HiveSize < sizeof(*BaseBlock))
{
Status = STATUS_REGISTRY_CORRUPT;
goto Quickie;
}
/* Make sure the hive contents are at least one bin long */
HiveLength = BaseBlock->Length;
if (BaseBlock->Length < sizeof(*BaseBlock))
{
Status = STATUS_REGISTRY_CORRUPT;
goto Quickie;
}
/* Validate the initial bin (the base block) */
if (!HvIsInPlaceBaseBlockValid(BaseBlock))
{
EfiPrintf(L"Recovery not implemented\r\n");
Status = STATUS_REGISTRY_CORRUPT;
goto Quickie;
}
/* Check if there's log recovery that needs to happen */
if (BaseBlock->Sequence1 != BaseBlock->Sequence2)
{
EfiPrintf(L"Log fix not implemented: %lx %lx\r\n");
Status = STATUS_REGISTRY_CORRUPT;
goto Quickie;
}
/*
* Check if the whole hive doesn't fit in the buffer.
* Note: HiveLength does not include the size of the baseblock itself
*/
if (HiveSize < (HiveLength + sizeof(*BaseBlock)))
{
EfiPrintf(L"Need bigger hive buffer path\r\n");
/* Allocate a slightly bigger buffer */
NewHiveSize = HiveLength + sizeof(*BaseBlock);
Status = MmPapAllocatePagesInRange((PVOID*)&NewBaseBlock,
BlLoaderRegistry,
NewHiveSize >> PAGE_SHIFT,
0,
0,
NULL,
0);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Copy the current data in there */
RtlCopyMemory(NewBaseBlock, BaseBlock, HiveSize);
/* Free the old data */
EfiPrintf(L"Leaking old hive buffer\r\n");
//MmPapFreePages(BaseBlock, 1);
/* Update our pointers */
BaseBlock = NewBaseBlock;
HiveSize = NewHiveSize;
BcdHive->BaseBlock = BaseBlock;
BcdHive->HiveSize = HiveSize;
}
/* Check if any log stuff needs to happen */
if (LogData)
{
EfiPrintf(L"Log fix not implemented: %lx %lx\r\n");
Status = STATUS_REGISTRY_CORRUPT;
goto Quickie;
}
/* Call Hv to setup the hive library */
Status = BiInitializeAndValidateHive(BcdHive);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Now get the root node */
Hive = &BcdHive->Hive.Hive;
RootNode = (PCM_KEY_NODE)HvGetCell(Hive, Hive->BaseBlock->RootCell);
if (!RootNode)
{
Status = STATUS_OBJECT_NAME_NOT_FOUND;
goto Quickie;
}
/* Find the Objects subkey under it to see if it's a real BCD hive */
RtlInitUnicodeString(&KeyString, L"Objects");
CellIndex = CmpFindSubKeyByName(Hive, RootNode, &KeyString);
if (CellIndex == HCELL_NIL)
{
EfiPrintf(L"No OBJECTS subkey found!\r\n");
Status = STATUS_OBJECT_NAME_NOT_FOUND;
goto Quickie;
}
/* This is a valid BCD hive, store its root node here */
BcdHive->RootNode = RootNode;
/* Allocate a copy of the file path */
BcdHive->FilePath = BlMmAllocateHeap(FilePath->Length);
if (!BcdHive->FilePath)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Make a copy of it */
RtlCopyMemory(BcdHive->FilePath, FilePath, FilePath->Length);
/* Create a key object to describe the rot */
KeyObject = BlMmAllocateHeap(sizeof(*KeyObject));
if (!KeyObject)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Fill out the details */
KeyObject->KeyNode = RootNode;
KeyObject->KeyHive = BcdHive;
KeyObject->KeyName = NULL;
KeyObject->KeyCell = Hive->BaseBlock->RootCell;
/* One reference for the key object, plus one lifetime reference */
BcdHive->ReferenceCount = 2;
/* This is the hive handle */
*HiveHandle = KeyObject;
/* We're all good */
Status = STATUS_SUCCESS;
Quickie:
/* If we had a log name, free it */
if (LogName)
{
BlMmFreeHeap(LogName);
}
/* If we had logging data, free it */
if (LogData)
{
EfiPrintf(L"Leaking log buffer\r\n");
//MmPapFreePages(LogData, 1);
}
/* Check if this is the failure path */
if (!NT_SUCCESS(Status))
{
/* If we mapped the hive, free it */
if (BaseBlock)
{
EfiPrintf(L"Leaking base block on failure\r\n");
//MmPapFreePages(BaseBlock, 1u);
}
/* If we opened the device, close it */
if (DeviceId != -1)
{
BlDeviceClose(DeviceId);
}
/* Did we create a hive object? */
if (BcdHive)
{
/* Free the file path if we made a copy of it */
if (BcdHive->FilePath)
{
BlMmFreeHeap(BcdHive->FilePath);
}
/* Free the hive itself */
BlMmFreeHeap(BcdHive);
}
/* Finally, free the root key object if we created one */
if (KeyObject)
{
BlMmFreeHeap(KeyObject);
}
}
/* Return the final status */
return Status;
}
NTSTATUS
@ -759,7 +1132,6 @@ BcdOpenStoreFromFile (
/* Assume failure */
LocalHandle = NULL;
EfiPrintf(L"Opening BCD store: %wZ\n", FileName);
/* Allocate a path descriptor */
Length = FileName->Length + sizeof(*FilePath);