mirror of
https://github.com/reactos/reactos.git
synced 2025-02-23 17:05:46 +00:00
[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:
parent
0f6b79b197
commit
1a9d2da6dc
2 changed files with 384 additions and 12 deletions
|
@ -373,7 +373,7 @@ BmFatalErrorEx (
|
||||||
|
|
||||||
/* Build the error string */
|
/* Build the error string */
|
||||||
swprintf(FormatString,
|
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",
|
L"to read the boot configuration data file %s\n",
|
||||||
ErrorStatus,
|
ErrorStatus,
|
||||||
Buffer);
|
Buffer);
|
||||||
|
@ -685,7 +685,7 @@ BmMain (
|
||||||
PBL_RETURN_ARGUMENTS ReturnArguments;
|
PBL_RETURN_ARGUMENTS ReturnArguments;
|
||||||
BOOLEAN RebootOnError;
|
BOOLEAN RebootOnError;
|
||||||
PGUID AppIdentifier;
|
PGUID AppIdentifier;
|
||||||
// HANDLE BcdHandle;
|
HANDLE BcdHandle;
|
||||||
|
|
||||||
EfiPrintf(L"ReactOS UEFI Boot Manager Initializing...\n");
|
EfiPrintf(L"ReactOS UEFI Boot Manager Initializing...\n");
|
||||||
|
|
||||||
|
@ -733,8 +733,8 @@ BmMain (
|
||||||
BmFwInitializeBootDirectoryPath();
|
BmFwInitializeBootDirectoryPath();
|
||||||
|
|
||||||
/* Load and initialize the boot configuration database (BCD) */
|
/* Load and initialize the boot configuration database (BCD) */
|
||||||
//Status = BmOpenDataStore(&BcdHandle);
|
Status = BmOpenDataStore(&BcdHandle);
|
||||||
//EfiPrintf(L"BCD Open: %lx\r\n", Status);
|
EfiPrintf(L"BCD Open: %lx\r\n", Status);
|
||||||
|
|
||||||
/* do more stuff!! */
|
/* do more stuff!! */
|
||||||
EfiPrintf(L"We are A-OK!\r\n");
|
EfiPrintf(L"We are A-OK!\r\n");
|
||||||
|
|
|
@ -452,14 +452,17 @@ BlGetBootOptionBoolean (
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BI_FLUSH_HIVE 0x01
|
#define BI_FLUSH_HIVE 0x01
|
||||||
|
#define BI_HIVE_WRITEABLE 0x02
|
||||||
|
|
||||||
typedef struct _BI_KEY_HIVE
|
typedef struct _BI_KEY_HIVE
|
||||||
{
|
{
|
||||||
PVOID ImageBase;
|
PHBASE_BLOCK BaseBlock;
|
||||||
|
ULONG HiveSize;
|
||||||
PBL_FILE_PATH_DESCRIPTOR FilePath;
|
PBL_FILE_PATH_DESCRIPTOR FilePath;
|
||||||
CMHIVE Hive;
|
CMHIVE Hive;
|
||||||
LONG ReferenceCount;
|
LONG ReferenceCount;
|
||||||
ULONG Flags;
|
ULONG Flags;
|
||||||
|
PCM_KEY_NODE RootNode;
|
||||||
} BI_KEY_HIVE, *PBI_KEY_HIVE;
|
} BI_KEY_HIVE, *PBI_KEY_HIVE;
|
||||||
|
|
||||||
typedef struct _BI_KEY_OBJECT
|
typedef struct _BI_KEY_OBJECT
|
||||||
|
@ -646,7 +649,7 @@ BiOpenKey(
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We found it -- get the key node out of it */
|
/* 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)
|
if (!ParentNode)
|
||||||
{
|
{
|
||||||
Status = STATUS_REGISTRY_CORRUPT;
|
Status = STATUS_REGISTRY_CORRUPT;
|
||||||
|
@ -699,16 +702,386 @@ Quickie:
|
||||||
return Status;
|
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
|
NTSTATUS
|
||||||
BiLoadHive (
|
BiLoadHive (
|
||||||
_In_ PBL_FILE_PATH_DESCRIPTOR FilePath,
|
_In_ PBL_FILE_PATH_DESCRIPTOR FilePath,
|
||||||
_Out_ PHANDLE HiveHandle
|
_Out_ PHANDLE HiveHandle
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
/* This is TODO */
|
ULONG DeviceId;
|
||||||
EfiPrintf(L"Loading a hive is not yet implemented\r\n");
|
PHBASE_BLOCK BaseBlock, NewBaseBlock;
|
||||||
*HiveHandle = NULL;
|
PBI_KEY_OBJECT KeyObject;
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
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
|
NTSTATUS
|
||||||
|
@ -759,7 +1132,6 @@ BcdOpenStoreFromFile (
|
||||||
|
|
||||||
/* Assume failure */
|
/* Assume failure */
|
||||||
LocalHandle = NULL;
|
LocalHandle = NULL;
|
||||||
EfiPrintf(L"Opening BCD store: %wZ\n", FileName);
|
|
||||||
|
|
||||||
/* Allocate a path descriptor */
|
/* Allocate a path descriptor */
|
||||||
Length = FileName->Length + sizeof(*FilePath);
|
Length = FileName->Length + sizeof(*FilePath);
|
||||||
|
|
Loading…
Reference in a new issue