[FREELDR:NTLDR] Use NTOS kernel's CMBOOT functions to enumerate and build the boot-time driver list.

They are correct and are more performant.

- Rewrite WinLdrAddDriverToList() on the model of CmpAddDriverToList()
  with support for CmpIsDriverInList().

- Disable RegEnumKey() as it is now unused.
This commit is contained in:
Hermès Bélusca-Maïto 2022-03-22 04:14:35 +01:00
parent 02e659d248
commit 94874baf19
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
7 changed files with 336 additions and 432 deletions

View file

@ -48,6 +48,7 @@ list(APPEND FREELDR_BOOTLIB_SOURCE
lib/mm/heap.c)
list(APPEND FREELDR_NTLDR_SOURCE
${REACTOS_SOURCE_DIR}/ntoskrnl/config/cmboot.c
ntldr/conversion.c
ntldr/registry.c
ntldr/winldr.c

View file

@ -242,6 +242,7 @@ GetNextPathElement(
return TRUE;
}
#if 0
LONG
RegEnumKey(
_In_ HKEY Key,
@ -312,6 +313,7 @@ RegEnumKey(
TRACE("RegEnumKey done -> %u, '%.*S'\n", *NameSize, *NameSize, Name);
return ERROR_SUCCESS;
}
#endif
LONG
RegOpenKey(

View file

@ -44,6 +44,7 @@ extern HKEY CurrentControlSetKey;
*/
#define RegCloseKey(hKey) (ERROR_SUCCESS)
#if 0
LONG
RegEnumKey(
_In_ HKEY Key,
@ -51,6 +52,7 @@ RegEnumKey(
_Out_ PWCHAR Name,
_Inout_ PULONG NameSize,
_Out_opt_ PHKEY SubKey);
#endif
LONG
RegOpenKey(

View file

@ -135,17 +135,22 @@ SetupLdrInitErrataInf(
}
static VOID
SetupLdrScanBootDrivers(PLIST_ENTRY BootDriverListHead, HINF InfHandle, PCSTR SearchPath)
SetupLdrScanBootDrivers(
_Inout_ PLIST_ENTRY BootDriverListHead,
_In_ HINF InfHandle,
_In_ PCSTR SearchPath)
{
INFCONTEXT InfContext, dirContext;
BOOLEAN Success;
PCSTR Media, DriverName, dirIndex, ImagePath;
WCHAR ServiceName[256];
WCHAR ImagePathW[256];
BOOLEAN Success;
WCHAR ImagePathW[MAX_PATH];
WCHAR DriverNameW[256];
/* Open inf section */
UNREFERENCED_PARAMETER(SearchPath);
/* Open INF section */
if (!InfFindFirstLine(InfHandle, "SourceDisksFiles", NULL, &InfContext))
return;
goto Quit;
/* Load all listed boot drivers */
do
@ -158,30 +163,51 @@ SetupLdrScanBootDrivers(PLIST_ENTRY BootDriverListHead, HINF InfHandle, PCSTR Se
InfFindFirstLine(InfHandle, "Directories", dirIndex, &dirContext) &&
InfGetDataField(&dirContext, 1, &ImagePath))
{
/* Convert name to widechar */
swprintf(ServiceName, L"%S", DriverName);
/* Prepare image path */
swprintf(ImagePathW, L"%S", ImagePath);
wcscat(ImagePathW, L"\\");
wcscat(ImagePathW, ServiceName);
RtlStringCbPrintfW(ImagePathW, sizeof(ImagePathW),
L"%S\\%S", ImagePath, DriverName);
/* Remove .sys extension */
ServiceName[wcslen(ServiceName) - 4] = 0;
/* Convert name to unicode and remove .sys extension */
RtlStringCbPrintfW(DriverNameW, sizeof(DriverNameW),
L"%S", DriverName);
DriverNameW[wcslen(DriverNameW) - 4] = UNICODE_NULL;
/* Add it to the list */
Success = WinLdrAddDriverToList(BootDriverListHead,
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\",
FALSE,
DriverNameW,
ImagePathW,
ServiceName);
NULL,
SERVICE_ERROR_NORMAL,
-1);
if (!Success)
{
ERR("Could not add boot driver '%s', '%s'\n", SearchPath, DriverName);
return;
ERR("Could not add boot driver '%s'\n", DriverName);
/* Ignore and continue adding other drivers */
}
}
}
} while (InfFindNextLine(&InfContext, &InfContext));
Quit:
/* Finally, add the boot filesystem driver to the list */
if (BootFileSystem)
{
TRACE("Adding filesystem driver %S\n", BootFileSystem);
Success = WinLdrAddDriverToList(BootDriverListHead,
FALSE,
BootFileSystem,
NULL,
L"Boot File System",
SERVICE_ERROR_CRITICAL,
-1);
if (!Success)
ERR("Failed to add filesystem driver %S\n", BootFileSystem);
}
else
{
TRACE("No required filesystem driver\n");
}
}

View file

@ -10,6 +10,7 @@
#include "winldr.h"
#include "ntldropts.h"
#include "registry.h"
#include <internal/cmboot.h>
#include <debug.h>
DBG_DEFAULT_CHANNEL(WINDOWS);
@ -26,6 +27,7 @@ extern BOOLEAN WinLdrTerminalConnected;
extern VOID WinLdrSetupEms(IN PCSTR BootOptions);
PLOADER_SYSTEM_BLOCK WinLdrSystemBlock;
/**/PCWSTR BootFileSystem = NULL;/**/
BOOLEAN VirtualBias = FALSE;
BOOLEAN SosEnabled = FALSE;
@ -363,23 +365,30 @@ WinLdrLoadBootDrivers(PLOADER_PARAMETER_BLOCK LoaderBlock,
PCSTR BootPath)
{
PLIST_ENTRY NextBd;
PBOOT_DRIVER_NODE DriverNode;
PBOOT_DRIVER_LIST_ENTRY BootDriver;
BOOLEAN Success;
BOOLEAN ret = TRUE;
// Walk through the boot drivers list
/* Walk through the boot drivers list */
NextBd = LoaderBlock->BootDriverListHead.Flink;
while (NextBd != &LoaderBlock->BootDriverListHead)
{
BootDriver = CONTAINING_RECORD(NextBd, BOOT_DRIVER_LIST_ENTRY, Link);
DriverNode = CONTAINING_RECORD(NextBd,
BOOT_DRIVER_NODE,
ListEntry.Link);
BootDriver = &DriverNode->ListEntry;
TRACE("BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath,
BootDriver->LdrEntry, &BootDriver->RegistryPath);
/* Get the next list entry as we may remove the current one on failure */
NextBd = BootDriver->Link.Flink;
TRACE("BootDriver %wZ DTE %08X RegPath: %wZ\n",
&BootDriver->FilePath, BootDriver->LdrEntry,
&BootDriver->RegistryPath);
// Paths are relative (FIXME: Are they always relative?)
// Load it
/* Load it */
UiIndicateProgress();
Success = WinLdrLoadDeviceDriver(&LoaderBlock->LoadOrderListHead,
BootPath,
@ -388,23 +397,25 @@ WinLdrLoadBootDrivers(PLOADER_PARAMETER_BLOCK LoaderBlock,
&BootDriver->LdrEntry);
if (Success)
{
// Convert the RegistryPath and DTE addresses to VA since we are not going to use it anymore
/* Convert the addresses to VA since we are not going to use them anymore */
BootDriver->RegistryPath.Buffer = PaToVa(BootDriver->RegistryPath.Buffer);
BootDriver->FilePath.Buffer = PaToVa(BootDriver->FilePath.Buffer);
BootDriver->LdrEntry = PaToVa(BootDriver->LdrEntry);
if (DriverNode->Group.Buffer)
DriverNode->Group.Buffer = PaToVa(DriverNode->Group.Buffer);
DriverNode->Name.Buffer = PaToVa(DriverNode->Name.Buffer);
}
else
{
// Loading failed - cry loudly
ERR("Can't load boot driver '%wZ'!\n", &BootDriver->FilePath);
UiMessageBox("Can't load boot driver '%wZ'!", &BootDriver->FilePath);
/* Loading failed: cry loudly */
ERR("Cannot load boot driver '%wZ'!\n", &BootDriver->FilePath);
UiMessageBox("Cannot load boot driver '%wZ'!", &BootDriver->FilePath);
ret = FALSE;
// Remove it from the list and try to continue
RemoveEntryList(NextBd);
/* Remove it from the list and try to continue */
RemoveEntryList(&BootDriver->Link);
}
NextBd = BootDriver->Link.Flink;
}
return ret;

View file

@ -61,6 +61,7 @@ typedef struct _LOADER_SYSTEM_BLOCK
} LOADER_SYSTEM_BLOCK, *PLOADER_SYSTEM_BLOCK;
extern PLOADER_SYSTEM_BLOCK WinLdrSystemBlock;
/**/extern PCWSTR BootFileSystem;/**/
// conversion.c
@ -71,7 +72,6 @@ VOID List_PaToVa(_In_ LIST_ENTRY *ListEntry);
#endif
VOID ConvertConfigToVA(PCONFIGURATION_COMPONENT_DATA Start);
// winldr.c
extern BOOLEAN SosEnabled;
#ifdef _M_IX86
@ -117,14 +117,6 @@ WinLdrInitSystemHive(
BOOLEAN WinLdrScanSystemHive(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
IN PCSTR SystemRoot);
// winldr.c
VOID
WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock,
PCSTR Options,
PCSTR SystemPath,
PCSTR BootPath,
USHORT VersionToBoot);
BOOLEAN
WinLdrLoadNLSData(
_Inout_ PLOADER_PARAMETER_BLOCK LoaderBlock,
@ -135,10 +127,22 @@ WinLdrLoadNLSData(
_In_ PCUNICODE_STRING OemHalFileName);
BOOLEAN
WinLdrAddDriverToList(LIST_ENTRY *BootDriverListHead,
PWSTR RegistryPath,
PWSTR ImagePath,
PWSTR ServiceName);
WinLdrAddDriverToList(
_Inout_ PLIST_ENTRY DriverListHead,
_In_ BOOLEAN InsertAtHead,
_In_ PCWSTR DriverName,
_In_opt_ PCWSTR ImagePath,
_In_opt_ PCWSTR GroupName,
_In_ ULONG ErrorControl,
_In_ ULONG Tag);
// winldr.c
VOID
WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock,
PCSTR Options,
PCSTR SystemPath,
PCSTR BootPath,
USHORT VersionToBoot);
VOID
WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock);

View file

@ -11,6 +11,7 @@
#include <freeldr.h>
#include "winldr.h"
#include "registry.h"
#include <internal/cmboot.h>
#include <debug.h>
DBG_DEFAULT_CHANNEL(WINDOWS);
@ -26,9 +27,9 @@ WinLdrGetNLSNames(
_Inout_ PUNICODE_STRING LangFileName, // CaseTable
_Inout_ PUNICODE_STRING OemHalFileName);
static VOID
WinLdrScanRegistry(IN OUT PLIST_ENTRY BootDriverListHead,
IN PCSTR SystemRoot);
static BOOLEAN
WinLdrScanRegistry(
IN OUT PLIST_ENTRY BootDriverListHead);
/* FUNCTIONS **************************************************************/
@ -47,7 +48,6 @@ WinLdrLoadSystemHive(
PVOID HiveDataPhysical;
PVOID HiveDataVirtual;
ULONG BytesRead;
PCWSTR FsService;
/* Concatenate path and filename to get the full name */
RtlStringCbCopyA(FullHiveName, sizeof(FullHiveName), DirectoryPath);
@ -99,23 +99,8 @@ WinLdrLoadSystemHive(
return FALSE;
}
/* Add boot filesystem driver to the list */
FsService = FsGetServiceName(FileId);
if (FsService)
{
BOOLEAN Success;
TRACE("Adding filesystem service %S\n", FsService);
Success = WinLdrAddDriverToList(&LoaderBlock->BootDriverListHead,
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\",
NULL,
(PWSTR)FsService);
if (!Success)
TRACE("Failed to add filesystem service\n");
}
else
{
TRACE("No required filesystem service\n");
}
// FIXME: HACK: Get the boot filesystem driver name now...
BootFileSystem = FsGetServiceName(FileId);
ArcClose(FileId);
return TRUE;
@ -184,7 +169,12 @@ BOOLEAN WinLdrScanSystemHive(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
CHAR SearchPath[1024];
/* Scan registry and prepare boot drivers list */
WinLdrScanRegistry(&LoaderBlock->BootDriverListHead, SystemRoot);
Success = WinLdrScanRegistry(&LoaderBlock->BootDriverListHead);
if (!Success)
{
UiMessageBox("Failed to load boot drivers!");
return FALSE;
}
/* Get names of NLS files */
Success = WinLdrGetNLSNames(CurrentControlSetKey,
@ -517,412 +507,280 @@ Quit:
return (Status == ESUCCESS);
}
static VOID
WinLdrScanRegistry(IN OUT PLIST_ENTRY BootDriverListHead,
IN PCSTR SystemRoot)
static BOOLEAN
WinLdrScanRegistry(
IN OUT PLIST_ENTRY BootDriverListHead)
{
LONG rc = 0;
HKEY hOrderKey, hServiceKey, hGroupKey, hDriverKey;
PWSTR GroupNameBuffer = NULL;
WCHAR ServiceName[256];
ULONG OrderList[128];
ULONG BufferSize;
ULONG Index;
ULONG TagIndex;
PWSTR GroupName;
ULONG ValueSize;
ULONG ValueType;
ULONG StartValue;
ULONG TagValue;
WCHAR DriverGroup[256];
ULONG DriverGroupSize;
CHAR ImagePath[256];
WCHAR TempImagePath[256];
BOOLEAN Success;
/* Get 'group order list' key */
rc = RegOpenKey(CurrentControlSetKey, L"Control\\GroupOrderList", &hOrderKey);
if (rc != ERROR_SUCCESS)
{
TRACE_CH(REACTOS, "Failed to open the 'GroupOrderList' key (rc %d)\n", (int)rc);
return;
}
/* Get 'services' key */
rc = RegOpenKey(CurrentControlSetKey, L"Services", &hServiceKey);
if (rc != ERROR_SUCCESS)
{
TRACE_CH(REACTOS, "Failed to open the 'Services' key (rc %d)\n", (int)rc);
RegCloseKey(hOrderKey);
return;
}
/* Get 'service group order' key */
rc = RegOpenKey(CurrentControlSetKey, L"Control\\ServiceGroupOrder", &hGroupKey);
if (rc != ERROR_SUCCESS)
{
TRACE_CH(REACTOS, "Failed to open the 'ServiceGroupOrder' key (rc %d)\n", (int)rc);
/* Find all boot drivers */
Success = CmpFindDrivers(SystemHive,
(HCELL_INDEX)CurrentControlSetKey,
BootLoad,
BootFileSystem,
BootDriverListHead);
if (!Success)
goto Quit;
}
/* Get the Group Order List */
BufferSize = 4096;
GroupNameBuffer = FrLdrHeapAlloc(BufferSize, TAG_WLDR_NAME);
if (!GroupNameBuffer)
{
TRACE_CH(REACTOS, "Failed to allocate buffer\n");
RegCloseKey(hGroupKey);
/* Sort by group/tag */
Success = CmpSortDriverList(SystemHive,
(HCELL_INDEX)CurrentControlSetKey,
BootDriverListHead);
if (!Success)
goto Quit;
}
rc = RegQueryValue(hGroupKey, L"List", NULL, (PUCHAR)GroupNameBuffer, &BufferSize);
RegCloseKey(hGroupKey);
if (rc != ERROR_SUCCESS)
{
TRACE_CH(REACTOS, "Failed to query the 'List' value (rc %d)\n", (int)rc);
/* Remove circular dependencies (cycles) and sort */
Success = CmpResolveDriverDependencies(BootDriverListHead);
if (!Success)
goto Quit;
}
TRACE_CH(REACTOS, "BufferSize: %d\n", (int)BufferSize);
TRACE_CH(REACTOS, "GroupNameBuffer: '%S'\n", GroupNameBuffer);
/* Loop through each group */
GroupName = GroupNameBuffer;
while (*GroupName)
{
TRACE("Driver group: '%S'\n", GroupName);
/* Query the Order */
BufferSize = sizeof(OrderList);
rc = RegQueryValue(hOrderKey, GroupName, NULL, (PUCHAR)OrderList, &BufferSize);
if (rc != ERROR_SUCCESS) OrderList[0] = 0;
/* Enumerate all drivers */
for (TagIndex = 1; TagIndex <= OrderList[0]; TagIndex++)
{
for (Index = 0; TRUE; Index++)
{
/* Get the Driver's Name */
ValueSize = sizeof(ServiceName);
rc = RegEnumKey(hServiceKey, Index, ServiceName, &ValueSize, &hDriverKey);
TRACE("RegEnumKey(): rc %d\n", (int)rc);
/* Make sure it's valid, and check if we're done */
if (rc == ERROR_NO_MORE_ITEMS)
break;
if (rc != ERROR_SUCCESS)
goto Quit;
//TRACE_CH(REACTOS, "Service %d: '%S'\n", (int)Index, ServiceName);
/* Read the Start Value */
ValueSize = sizeof(ULONG);
rc = RegQueryValue(hDriverKey, L"Start", &ValueType, (PUCHAR)&StartValue, &ValueSize);
if (rc != ERROR_SUCCESS) StartValue = (ULONG)-1;
//TRACE_CH(REACTOS, " Start: %x\n", (int)StartValue);
/* Read the Tag */
ValueSize = sizeof(ULONG);
rc = RegQueryValue(hDriverKey, L"Tag", &ValueType, (PUCHAR)&TagValue, &ValueSize);
if (rc != ERROR_SUCCESS) TagValue = (ULONG)-1;
//TRACE_CH(REACTOS, " Tag: %x\n", (int)TagValue);
/* Read the driver's group */
DriverGroupSize = sizeof(DriverGroup);
rc = RegQueryValue(hDriverKey, L"Group", NULL, (PUCHAR)DriverGroup, &DriverGroupSize);
//TRACE_CH(REACTOS, " Group: '%S'\n", DriverGroup);
/* Make sure it should be started */
if ((StartValue == 0) &&
(TagValue == OrderList[TagIndex]) &&
(_wcsicmp(DriverGroup, GroupName) == 0))
{
/* Get the Driver's Location */
ValueSize = sizeof(TempImagePath);
rc = RegQueryValue(hDriverKey, L"ImagePath", NULL, (PUCHAR)TempImagePath, &ValueSize);
/* Write the whole path if it succeeded, else prepare to fail */
if (rc != ERROR_SUCCESS)
{
TRACE_CH(REACTOS, "ImagePath: not found\n");
TempImagePath[0] = 0;
RtlStringCbPrintfA(ImagePath, sizeof(ImagePath), "%s\\system32\\drivers\\%S.sys", SystemRoot, ServiceName);
}
else if (TempImagePath[0] != L'\\')
{
RtlStringCbPrintfA(ImagePath, sizeof(ImagePath), "%s%S", SystemRoot, TempImagePath);
}
else
{
RtlStringCbPrintfA(ImagePath, sizeof(ImagePath), "%S", TempImagePath);
TRACE_CH(REACTOS, "ImagePath: '%s'\n", ImagePath);
}
TRACE("Adding boot driver: '%s'\n", ImagePath);
Success = WinLdrAddDriverToList(BootDriverListHead,
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\",
TempImagePath,
ServiceName);
if (!Success)
ERR("Failed to add boot driver\n");
}
else
{
//TRACE(" Skipping driver '%S' with Start %d, Tag %d and Group '%S' (Current Tag %d, current group '%S')\n",
// ServiceName, StartValue, TagValue, DriverGroup, OrderList[TagIndex], GroupName);
}
RegCloseKey(hDriverKey);
}
}
for (Index = 0; TRUE; Index++)
{
/* Get the Driver's Name */
ValueSize = sizeof(ServiceName);
rc = RegEnumKey(hServiceKey, Index, ServiceName, &ValueSize, &hDriverKey);
//TRACE_CH(REACTOS, "RegEnumKey(): rc %d\n", (int)rc);
if (rc == ERROR_NO_MORE_ITEMS)
break;
if (rc != ERROR_SUCCESS)
goto Quit;
TRACE("Service %d: '%S'\n", (int)Index, ServiceName);
/* Read the Start Value */
ValueSize = sizeof(ULONG);
rc = RegQueryValue(hDriverKey, L"Start", &ValueType, (PUCHAR)&StartValue, &ValueSize);
if (rc != ERROR_SUCCESS) StartValue = (ULONG)-1;
//TRACE_CH(REACTOS, " Start: %x\n", (int)StartValue);
/* Read the Tag */
ValueSize = sizeof(ULONG);
rc = RegQueryValue(hDriverKey, L"Tag", &ValueType, (PUCHAR)&TagValue, &ValueSize);
if (rc != ERROR_SUCCESS) TagValue = (ULONG)-1;
//TRACE_CH(REACTOS, " Tag: %x\n", (int)TagValue);
/* Read the driver's group */
DriverGroupSize = sizeof(DriverGroup);
rc = RegQueryValue(hDriverKey, L"Group", NULL, (PUCHAR)DriverGroup, &DriverGroupSize);
//TRACE_CH(REACTOS, " Group: '%S'\n", DriverGroup);
for (TagIndex = 1; TagIndex <= OrderList[0]; TagIndex++)
{
if (TagValue == OrderList[TagIndex]) break;
}
if ((StartValue == 0) &&
(TagIndex > OrderList[0]) &&
(_wcsicmp(DriverGroup, GroupName) == 0))
{
ValueSize = sizeof(TempImagePath);
rc = RegQueryValue(hDriverKey, L"ImagePath", NULL, (PUCHAR)TempImagePath, &ValueSize);
if (rc != ERROR_SUCCESS)
{
TRACE_CH(REACTOS, "ImagePath: not found\n");
TempImagePath[0] = 0;
RtlStringCbPrintfA(ImagePath, sizeof(ImagePath), "%ssystem32\\drivers\\%S.sys", SystemRoot, ServiceName);
}
else if (TempImagePath[0] != L'\\')
{
RtlStringCbPrintfA(ImagePath, sizeof(ImagePath), "%s%S", SystemRoot, TempImagePath);
}
else
{
RtlStringCbPrintfA(ImagePath, sizeof(ImagePath), "%S", TempImagePath);
TRACE_CH(REACTOS, "ImagePath: '%s'\n", ImagePath);
}
TRACE(" Adding boot driver: '%s'\n", ImagePath);
Success = WinLdrAddDriverToList(BootDriverListHead,
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\",
TempImagePath,
ServiceName);
if (!Success)
ERR(" Failed to add boot driver\n");
}
else
{
//TRACE(" Skipping driver '%S' with Start %d, Tag %d and Group '%S' (Current group '%S')\n",
// ServiceName, StartValue, TagValue, DriverGroup, GroupName);
}
RegCloseKey(hDriverKey);
}
/* Move to the next group name */
GroupName = GroupName + wcslen(GroupName) + 1;
}
Quit:
/* Free allocated memory */
if (GroupNameBuffer)
FrLdrHeapFree(GroupNameBuffer, TAG_WLDR_NAME);
/* In case of failure, free the boot driver list */
if (!Success)
CmpFreeDriverList(SystemHive, BootDriverListHead);
/* Close the registry key handles */
RegCloseKey(hServiceKey);
RegCloseKey(hOrderKey);
return Success;
}
static
/**
* @brief
* Inserts the specified driver entry into the driver list, or updates
* an existing entry with new ImagePath, ErrorControl, Group and Tag values.
*
* @param[in,out] DriverListHead
* The driver list where to insert the driver entry.
*
* @param[in] InsertAtHead
* Whether to insert the driver at the head (TRUE) or at the tail (FALSE)
* of the driver list.
*
* @param[in] DriverName
* The driver's name.
*
* @param[in] ImagePath
* Optional path the the driver's image. If none is specified,
* a default path is constructed out of the driver's name.
*
* @param[in] GroupName
* Optional driver group name.
*
* @param[in] ErrorControl
* @param[in] Tag
* The ErrorControl and group Tag values for the driver.
*
* @return
* TRUE if the driver has been inserted into the list or updated, FALSE if not.
**/
BOOLEAN
InsertInBootDriverList(
PLIST_ENTRY BootDriverListHead,
PBOOT_DRIVER_LIST_ENTRY BootDriverEntry)
WinLdrAddDriverToList(
_Inout_ PLIST_ENTRY DriverListHead,
_In_ BOOLEAN InsertAtHead,
_In_ PCWSTR DriverName,
_In_opt_ PCWSTR ImagePath,
_In_opt_ PCWSTR GroupName,
_In_ ULONG ErrorControl,
_In_ ULONG Tag)
{
PBOOT_DRIVER_NODE DriverNode;
PBOOT_DRIVER_LIST_ENTRY DriverEntry;
PLIST_ENTRY ListEntry;
ASSERT(BootDriverEntry->FilePath.Buffer != NULL);
ASSERT(BootDriverEntry->RegistryPath.Buffer != NULL);
for (ListEntry = BootDriverListHead->Flink;
ListEntry != BootDriverListHead;
ListEntry = ListEntry->Flink)
{
DriverEntry = CONTAINING_RECORD(ListEntry,
BOOT_DRIVER_LIST_ENTRY,
Link);
if ((DriverEntry->FilePath.Buffer != NULL) &&
RtlEqualUnicodeString(&BootDriverEntry->FilePath,
&DriverEntry->FilePath,
TRUE))
{
return FALSE;
}
if ((DriverEntry->RegistryPath.Buffer != NULL) &&
RtlEqualUnicodeString(&BootDriverEntry->RegistryPath,
&DriverEntry->RegistryPath,
TRUE))
{
return FALSE;
}
}
InsertTailList(BootDriverListHead, &BootDriverEntry->Link);
return TRUE;
}
BOOLEAN
WinLdrAddDriverToList(LIST_ENTRY *BootDriverListHead,
PWSTR RegistryPath,
PWSTR ImagePath,
PWSTR ServiceName)
{
PBOOT_DRIVER_LIST_ENTRY BootDriverEntry;
NTSTATUS Status;
BOOLEAN AlreadyInserted;
USHORT PathLength;
UNICODE_STRING DriverNameU;
UNICODE_STRING RegistryPath;
UNICODE_STRING FilePath = {0};
UNICODE_STRING RegistryString = {0};
UNICODE_STRING GroupString = {0};
BootDriverEntry = FrLdrHeapAlloc(sizeof(BOOT_DRIVER_LIST_ENTRY), TAG_WLDR_BDE);
if (!BootDriverEntry)
return FALSE;
// DTE will be filled during actual load of the driver
BootDriverEntry->LdrEntry = NULL;
// Check - if we have a valid ImagePath, if not - we need to build it
// like "System32\\Drivers\\blah.sys"
if (ImagePath && (ImagePath[0] != 0))
/* Check whether the driver is already in the list */
RtlInitUnicodeString(&DriverNameU, DriverName);
AlreadyInserted = CmpIsDriverInList(DriverListHead,
&DriverNameU,
&DriverNode);
if (AlreadyInserted)
{
// Just copy ImagePath to the corresponding field in the structure
PathLength = (USHORT)wcslen(ImagePath) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
BootDriverEntry->FilePath.Length = 0;
BootDriverEntry->FilePath.MaximumLength = PathLength;
BootDriverEntry->FilePath.Buffer = FrLdrHeapAlloc(PathLength, TAG_WLDR_NAME);
if (!BootDriverEntry->FilePath.Buffer)
{
FrLdrHeapFree(BootDriverEntry, TAG_WLDR_BDE);
return FALSE;
}
Status = RtlAppendUnicodeToString(&BootDriverEntry->FilePath, ImagePath);
if (!NT_SUCCESS(Status))
{
FrLdrHeapFree(BootDriverEntry->FilePath.Buffer, TAG_WLDR_NAME);
FrLdrHeapFree(BootDriverEntry, TAG_WLDR_BDE);
return FALSE;
}
/* If so, we have obtained its node */
ASSERT(DriverNode);
DriverEntry = &DriverNode->ListEntry;
}
else
{
// we have to construct ImagePath ourselves
PathLength = (USHORT)wcslen(ServiceName)*sizeof(WCHAR) + sizeof(L"system32\\drivers\\.sys");
BootDriverEntry->FilePath.Length = 0;
BootDriverEntry->FilePath.MaximumLength = PathLength;
BootDriverEntry->FilePath.Buffer = FrLdrHeapAlloc(PathLength, TAG_WLDR_NAME);
if (!BootDriverEntry->FilePath.Buffer)
{
FrLdrHeapFree(BootDriverEntry, TAG_WLDR_BDE);
/* Allocate a driver node and initialize it */
DriverNode = CmpAllocate(sizeof(BOOT_DRIVER_NODE), FALSE, TAG_CM);
if (!DriverNode)
return FALSE;
}
Status = RtlAppendUnicodeToString(&BootDriverEntry->FilePath, L"system32\\drivers\\");
if (!NT_SUCCESS(Status))
{
FrLdrHeapFree(BootDriverEntry->FilePath.Buffer, TAG_WLDR_NAME);
FrLdrHeapFree(BootDriverEntry, TAG_WLDR_BDE);
return FALSE;
}
RtlZeroMemory(DriverNode, sizeof(BOOT_DRIVER_NODE));
DriverEntry = &DriverNode->ListEntry;
Status = RtlAppendUnicodeToString(&BootDriverEntry->FilePath, ServiceName);
if (!NT_SUCCESS(Status))
{
FrLdrHeapFree(BootDriverEntry->FilePath.Buffer, TAG_WLDR_NAME);
FrLdrHeapFree(BootDriverEntry, TAG_WLDR_BDE);
return FALSE;
}
/* Driver Name */
RtlInitEmptyUnicodeString(&DriverNode->Name,
CmpAllocate(DriverNameU.Length, FALSE, TAG_CM),
DriverNameU.Length);
if (!DriverNode->Name.Buffer)
goto Failure;
Status = RtlAppendUnicodeToString(&BootDriverEntry->FilePath, L".sys");
if (!NT_SUCCESS(Status))
if (!NT_SUCCESS(RtlAppendUnicodeStringToString(&DriverNode->Name, &DriverNameU)))
goto Failure;
}
/* Check whether we have a valid ImagePath. If not, we need
* to build it like "System32\\Drivers\\blah.sys" */
if (ImagePath && *ImagePath)
{
/* Just copy ImagePath to the corresponding field in the structure */
PathLength = (USHORT)(wcslen(ImagePath)) * sizeof(WCHAR);
RtlInitEmptyUnicodeString(&FilePath,
CmpAllocate(PathLength, FALSE, TAG_WLDR_NAME),
PathLength);
if (!FilePath.Buffer)
goto Failure;
if (!NT_SUCCESS(RtlAppendUnicodeToString(&FilePath, ImagePath)))
goto Failure;
}
else
{
/* We have to construct ImagePath ourselves */
PathLength = DriverNode->Name.Length + sizeof(L"system32\\drivers\\.sys");
RtlInitEmptyUnicodeString(&FilePath,
CmpAllocate(PathLength, FALSE, TAG_WLDR_NAME),
PathLength);
if (!FilePath.Buffer)
goto Failure;
if (!NT_SUCCESS(RtlAppendUnicodeToString(&FilePath, L"system32\\drivers\\")) ||
!NT_SUCCESS(RtlAppendUnicodeStringToString(&FilePath, &DriverNode->Name)) ||
!NT_SUCCESS(RtlAppendUnicodeToString(&FilePath, L".sys")))
{
FrLdrHeapFree(BootDriverEntry->FilePath.Buffer, TAG_WLDR_NAME);
FrLdrHeapFree(BootDriverEntry, TAG_WLDR_BDE);
return FALSE;
goto Failure;
}
}
// Add registry path
PathLength = (USHORT)(wcslen(RegistryPath) + wcslen(ServiceName))*sizeof(WCHAR) + sizeof(UNICODE_NULL);
BootDriverEntry->RegistryPath.Length = 0;
BootDriverEntry->RegistryPath.MaximumLength = PathLength;
BootDriverEntry->RegistryPath.Buffer = FrLdrHeapAlloc(PathLength, TAG_WLDR_NAME);
if (!BootDriverEntry->RegistryPath.Buffer)
/* Registry path */
RtlInitUnicodeString(&RegistryPath,
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
PathLength = RegistryPath.Length + DriverNode->Name.Length;
RtlInitEmptyUnicodeString(&RegistryString,
CmpAllocate(PathLength, FALSE, TAG_WLDR_NAME),
PathLength);
if (!RegistryString.Buffer)
goto Failure;
if (!NT_SUCCESS(RtlAppendUnicodeStringToString(&RegistryString, &RegistryPath)) ||
!NT_SUCCESS(RtlAppendUnicodeStringToString(&RegistryString, &DriverNode->Name)))
{
FrLdrHeapFree(BootDriverEntry->FilePath.Buffer, TAG_WLDR_NAME);
FrLdrHeapFree(BootDriverEntry, TAG_WLDR_BDE);
return FALSE;
goto Failure;
}
Status = RtlAppendUnicodeToString(&BootDriverEntry->RegistryPath, RegistryPath);
if (!NT_SUCCESS(Status))
/* Group */
if (GroupName && *GroupName)
{
FrLdrHeapFree(BootDriverEntry->RegistryPath.Buffer, TAG_WLDR_NAME);
FrLdrHeapFree(BootDriverEntry->FilePath.Buffer, TAG_WLDR_NAME);
FrLdrHeapFree(BootDriverEntry, TAG_WLDR_BDE);
return FALSE;
/*
* NOTE: Here we can use our own allocator as we alone maintain the
* group string. This is different from the other allocated strings,
* where we instead need to use the same (hive) allocator as the
* one used by CmpAddDriverToList(), for interoperability purposes.
*/
RtlCreateUnicodeString(&GroupString, GroupName);
if (!GroupString.Buffer)
goto Failure;
}
else
{
RtlInitEmptyUnicodeString(&GroupString, NULL, 0);
}
Status = RtlAppendUnicodeToString(&BootDriverEntry->RegistryPath, ServiceName);
if (!NT_SUCCESS(Status))
/* Set or replace the driver node's file path */
if (DriverEntry->FilePath.Buffer)
{
FrLdrHeapFree(BootDriverEntry->RegistryPath.Buffer, TAG_WLDR_NAME);
FrLdrHeapFree(BootDriverEntry->FilePath.Buffer, TAG_WLDR_NAME);
FrLdrHeapFree(BootDriverEntry, TAG_WLDR_BDE);
return FALSE;
CmpFree(DriverEntry->FilePath.Buffer,
DriverEntry->FilePath.MaximumLength);
}
DriverEntry->FilePath = FilePath;
FilePath.Buffer = NULL;
// Insert entry into the list
if (!InsertInBootDriverList(BootDriverListHead, BootDriverEntry))
/* Set or replace the driver node's registry path */
if (DriverEntry->RegistryPath.Buffer)
{
// It was already there, so delete our entry
FrLdrHeapFree(BootDriverEntry->RegistryPath.Buffer, TAG_WLDR_NAME);
FrLdrHeapFree(BootDriverEntry->FilePath.Buffer, TAG_WLDR_NAME);
FrLdrHeapFree(BootDriverEntry, TAG_WLDR_BDE);
CmpFree(DriverEntry->RegistryPath.Buffer,
DriverEntry->RegistryPath.MaximumLength);
}
DriverEntry->RegistryPath = RegistryString;
RegistryString.Buffer = NULL;
/* Set or replace the driver node's group */
if (DriverNode->Group.Buffer)
{
/*
* If the buffer is inside the registry hive's memory, this means that
* it has been set by CmpAddDriverToList() to point to some data within
* the hive; thus we should not free the buffer but just replace it.
* Otherwise, this is a buffer previously allocated by ourselves, that
* we can free.
*
* NOTE: This function does not have an explicit LoaderBlock input
* parameter pointer, since it does not need it, except for this
* very place. So instead, use the global WinLdrSystemBlock pointer.
*/
PLOADER_PARAMETER_BLOCK LoaderBlock =
(WinLdrSystemBlock ? &WinLdrSystemBlock->LoaderBlock : NULL);
if (!LoaderBlock || !LoaderBlock->RegistryBase || !LoaderBlock->RegistryLength ||
((ULONG_PTR)DriverNode->Group.Buffer <
(ULONG_PTR)VaToPa(LoaderBlock->RegistryBase)) ||
((ULONG_PTR)DriverNode->Group.Buffer >=
(ULONG_PTR)VaToPa(LoaderBlock->RegistryBase) + LoaderBlock->RegistryLength))
{
RtlFreeUnicodeString(&DriverNode->Group);
}
}
DriverNode->Group = GroupString;
GroupString.Buffer = NULL;
/* ErrorControl and Tag */
DriverNode->ErrorControl = ErrorControl;
DriverNode->Tag = Tag;
/* Insert the entry into the list if it does not exist there already */
if (!AlreadyInserted)
{
if (InsertAtHead)
InsertHeadList(DriverListHead, &DriverEntry->Link);
else
InsertTailList(DriverListHead, &DriverEntry->Link);
}
return TRUE;
Failure:
if (GroupString.Buffer)
RtlFreeUnicodeString(&GroupString);
if (RegistryString.Buffer)
CmpFree(RegistryString.Buffer, RegistryString.MaximumLength);
if (FilePath.Buffer)
CmpFree(FilePath.Buffer, FilePath.MaximumLength);
/* If it does not exist in the list already, free the allocated
* driver node, otherwise keep the original one in place. */
if (!AlreadyInserted)
{
if (DriverEntry->RegistryPath.Buffer)
{
CmpFree(DriverEntry->RegistryPath.Buffer,
DriverEntry->RegistryPath.MaximumLength);
}
if (DriverEntry->FilePath.Buffer)
{
CmpFree(DriverEntry->FilePath.Buffer,
DriverEntry->FilePath.MaximumLength);
}
if (DriverNode->Name.Buffer)
{
CmpFree(DriverNode->Name.Buffer,
DriverNode->Name.MaximumLength);
}
CmpFree(DriverNode, sizeof(BOOT_DRIVER_NODE));
}
return FALSE;
}