https://git.reactos.org/?p=reactos.git;a=commitdiff;h=6ff02323684cac98a944b…
commit 6ff02323684cac98a944b54916ad3fb652a1304d
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Mon Mar 21 23:16:19 2022 +0100
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Sat Apr 16 18:37:45 2022 +0200
[NTOS:CM] Adapt cmboot.c for usage in NT/ReactOS bootloader.
- Add a new cmboot.h header to isolate the boot-support definitions
shared with the NT/ReactOS bootloader.
- Move CmpFreeDriverList() to cmboot.c so that we can use it for
cleanup paths in the NT/ReactOS bootloader.
- CmpFindControlSet(): Directly build the control set name in UNICODE,
instead of doing an ANSI->UNICODE conversion.
- Directly assign the CurrentControlSet\Services constant string,
instead of going the route of init-empty-string + append-string.
This is possible since that string is not modified later.
- Remove ASSERT(FALSE), replacing them with correct failure handling.
- Add cleanup paths in CmpAddDriverToList().
- Simplify and fix CmpFreeDriverList(): it's the full DriverNode
that needs to be freed; not the LIST_ENTRY pointer.
- Add other validity checks:
* Registry value types and data sizes;
* For multi-strings, verify that they are NULL-terminated.
* For (multi-)strings, check whether they are NULL-terminated before
optionally removing their trailing NULL character from the count.
Check also whether they are of zero-length and take appropriate
action where necessary.
- Add CmpIsDriverInList() for future usage in CMBOOT compiled in
bootloader mode.
- Add SAL annotations and Doxygen documentation.
- Add debug traces.
- Formatting / code style fixes.
** TODO: Fix SafeBoot support **
---
ntoskrnl/config/cmboot.c | 953 +++++++++++++++++++++++++++----------
ntoskrnl/config/cmsysini.c | 49 --
ntoskrnl/include/internal/cm.h | 52 +-
ntoskrnl/include/internal/cmboot.h | 80 ++++
ntoskrnl/include/internal/io.h | 24 +-
5 files changed, 786 insertions(+), 372 deletions(-)
diff --git a/ntoskrnl/config/cmboot.c b/ntoskrnl/config/cmboot.c
index 98dd2a053ef..fdd1a6ed6c4 100644
--- a/ntoskrnl/config/cmboot.c
+++ b/ntoskrnl/config/cmboot.c
@@ -1,166 +1,260 @@
/*
- * PROJECT: ReactOS Kernel
- * LICENSE: BSD - See COPYING.ARM in the top level directory
- * FILE: ntoskrnl/config/cmboot.c
- * PURPOSE: Configuration Manager - Boot Initialization
- * PROGRAMMERS: ReactOS Portable Systems Group
- * Alex Ionescu (alex.ionescu(a)reactos.org)
+ * PROJECT: ReactOS Kernel
+ * LICENSE: BSD - See COPYING.ARM in the top level directory
+ * PURPOSE: Configuration Manager - Boot Initialization
+ * COPYRIGHT: Copyright 2007 Alex Ionescu (alex.ionescu(a)reactos.org)
+ * Copyright 2010 ReactOS Portable Systems Group
+ * Copyright 2022 Hermès Bélusca-Maïto
+ *
+ * NOTE: This module is shared by both the kernel and the bootloader.
*/
/* INCLUDES *******************************************************************/
-#include "ntoskrnl.h"
+#include <ntoskrnl.h>
+
#define NDEBUG
-#include "debug.h"
+#include <debug.h>
-/* GLOBALS ********************************************************************/
+#ifdef _BLDR_
+
+#undef CODE_SEG
+#define CODE_SEG(...)
+
+#include <ntstrsafe.h>
+#include <cmlib.h>
+#include "internal/cmboot.h"
+
+// HACK: This is part of non-NT-compatible SafeBoot support in kernel.
+ULONG InitSafeBootMode = 0;
+
+DBG_DEFAULT_CHANNEL(REGISTRY);
+#define CMTRACE(x, fmt, ...) TRACE(fmt, ##__VA_ARGS__) // DPRINT
+
+#endif /* _BLDR_ */
+
+
+/* DEFINES ********************************************************************/
+
+#define CM_BOOT_DEBUG 0x20
+
+#define IS_NULL_TERMINATED(Buffer, Size) \
+ (((Size) >= sizeof(WCHAR)) && ((Buffer)[(Size) / sizeof(WCHAR) - 1] ==
UNICODE_NULL))
-extern ULONG InitSafeBootMode;
/* FUNCTIONS ******************************************************************/
+// HACK: This is part of non-NT-compatible SafeBoot support in kernel.
+extern ULONG InitSafeBootMode;
+
+CODE_SEG("INIT")
+static
+BOOLEAN
+CmpIsSafe(
+ _In_ PHHIVE Hive,
+ _In_ HCELL_INDEX SafeBootCell,
+ _In_ HCELL_INDEX DriverCell);
+
+/**
+ * @brief
+ * Finds the corresponding "HKLM\SYSTEM\ControlSetXXX" system control set
+ * registry key, according to the "Current", "Default", or
"LastKnownGood"
+ * values in the "HKLM\SYSTEM\Select" registry key.
+ *
+ * @param[in] SystemHive
+ * The SYSTEM hive.
+ *
+ * @param[in] RootCell
+ * The root cell of the SYSTEM hive.
+ *
+ * @param[in] SelectKeyName
+ * The control set to check for: either "Current", "Default", or
+ * "LastKnownGood", the value of which selects the corresponding
+ * "HKLM\SYSTEM\ControlSetXXX" control set registry key.
+ *
+ * @param[out] AutoSelect
+ * Value of the "AutoSelect" registry value (unused).
+ *
+ * @return
+ * The control set registry key's hive cell (if found), or HCELL_NIL.
+ **/
CODE_SEG("INIT")
HCELL_INDEX
NTAPI
-CmpFindControlSet(IN PHHIVE SystemHive,
- IN HCELL_INDEX RootCell,
- IN PUNICODE_STRING SelectKeyName,
- OUT PBOOLEAN AutoSelect)
+CmpFindControlSet(
+ _In_ PHHIVE SystemHive,
+ _In_ HCELL_INDEX RootCell,
+ _In_ PCUNICODE_STRING SelectKeyName,
+ _Out_ PBOOLEAN AutoSelect)
{
- UNICODE_STRING KeyName;
+ UNICODE_STRING Name;
PCM_KEY_NODE Node;
HCELL_INDEX SelectCell, AutoSelectCell, SelectValueCell, ControlSetCell;
HCELL_INDEX CurrentValueCell;
- PCM_KEY_VALUE KeyValue;
+ PCM_KEY_VALUE Value;
ULONG Length;
- PULONG ControlSetId;
- ANSI_STRING ControlSetAnsiName;
- CHAR Buffer[128];
- WCHAR WideBuffer[128];
NTSTATUS Status;
PULONG CurrentData;
+ PULONG ControlSetId;
+ WCHAR Buffer[128];
- /* Sanity check */
+ /* Sanity check: We shouldn't need to release any acquired cells */
ASSERT(SystemHive->ReleaseCellRoutine == NULL);
- /* Get the Select subkey */
- RtlInitUnicodeString(&KeyName, L"select");
+ /* Get the Select key */
+ RtlInitUnicodeString(&Name, L"select");
Node = (PCM_KEY_NODE)HvGetCell(SystemHive, RootCell);
if (!Node) return HCELL_NIL;
- SelectCell = CmpFindSubKeyByName(SystemHive, Node, &KeyName);
- if (SelectCell == HCELL_NIL) return SelectCell;
+ SelectCell = CmpFindSubKeyByName(SystemHive, Node, &Name);
+ if (SelectCell == HCELL_NIL) return HCELL_NIL;
/* Get AutoSelect value */
- RtlInitUnicodeString(&KeyName, L"AutoSelect");
+ RtlInitUnicodeString(&Name, L"AutoSelect");
Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell);
if (!Node) return HCELL_NIL;
- AutoSelectCell = CmpFindValueByName(SystemHive, Node, &KeyName);
+ AutoSelectCell = CmpFindValueByName(SystemHive, Node, &Name);
if (AutoSelectCell == HCELL_NIL)
{
- /* Assume TRUE if the value is missing. */
+ /* Assume TRUE if the value is missing */
*AutoSelect = TRUE;
}
else
{
/* Read the value */
- KeyValue = (PCM_KEY_VALUE)HvGetCell(SystemHive, AutoSelectCell);
- if (KeyValue == NULL) return HCELL_NIL;
+ Value = (PCM_KEY_VALUE)HvGetCell(SystemHive, AutoSelectCell);
+ if (!Value) return HCELL_NIL;
+ // if (Value->Type != REG_DWORD) return HCELL_NIL;
/* Convert it to a boolean */
- *AutoSelect = *(PBOOLEAN)CmpValueToData(SystemHive, KeyValue, &Length);
+ CurrentData = (PULONG)CmpValueToData(SystemHive, Value, &Length);
+ if (!CurrentData) return HCELL_NIL;
+ // if (Length < sizeof(ULONG)) return HCELL_NIL;
+
+ *AutoSelect = *(PBOOLEAN)CurrentData;
}
/* Now find the control set being looked up */
Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell);
if (!Node) return HCELL_NIL;
SelectValueCell = CmpFindValueByName(SystemHive, Node, SelectKeyName);
- if (SelectValueCell == HCELL_NIL) return SelectValueCell;
+ if (SelectValueCell == HCELL_NIL) return HCELL_NIL;
/* Read the value (corresponding to the CCS ID) */
- KeyValue = (PCM_KEY_VALUE)HvGetCell(SystemHive, SelectValueCell);
- if (!KeyValue) return HCELL_NIL;
- if (KeyValue->Type != REG_DWORD) return HCELL_NIL;
- ControlSetId = (PULONG)CmpValueToData(SystemHive, KeyValue, &Length);
-
- /* Now build an Ansi String for the CCS's Name */
- sprintf(Buffer, "ControlSet%03lu", *ControlSetId);
- ControlSetAnsiName.Length = (USHORT)strlen(Buffer);
- ControlSetAnsiName.MaximumLength = (USHORT)strlen(Buffer);
- ControlSetAnsiName.Buffer = Buffer;
-
- /* And convert it to Unicode... */
- KeyName.MaximumLength = 256;
- KeyName.Buffer = WideBuffer;
- Status = RtlAnsiStringToUnicodeString(&KeyName,
- &ControlSetAnsiName,
- FALSE);
+ Value = (PCM_KEY_VALUE)HvGetCell(SystemHive, SelectValueCell);
+ if (!Value) return HCELL_NIL;
+ if (Value->Type != REG_DWORD) return HCELL_NIL;
+ ControlSetId = (PULONG)CmpValueToData(SystemHive, Value, &Length);
+ if (!ControlSetId) return HCELL_NIL;
+ if (Length < sizeof(ULONG)) return HCELL_NIL;
+
+ /* Now build the CCS's Name */
+ Status = RtlStringCbPrintfW(Buffer, sizeof(Buffer),
+ L"ControlSet%03lu", *ControlSetId);
if (!NT_SUCCESS(Status)) return HCELL_NIL;
+ /* RtlStringCbPrintfW ensures the buffer to be NULL-terminated */
+ RtlInitUnicodeString(&Name, Buffer);
/* Now open it */
Node = (PCM_KEY_NODE)HvGetCell(SystemHive, RootCell);
if (!Node) return HCELL_NIL;
- ControlSetCell = CmpFindSubKeyByName(SystemHive, Node, &KeyName);
- if (ControlSetCell == HCELL_NIL) return ControlSetCell;
+ ControlSetCell = CmpFindSubKeyByName(SystemHive, Node, &Name);
+ if (ControlSetCell == HCELL_NIL) return HCELL_NIL;
/* Get the value of the "Current" CCS */
- RtlInitUnicodeString(&KeyName, L"Current");
+ RtlInitUnicodeString(&Name, L"Current");
Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell);
if (!Node) return HCELL_NIL;
- CurrentValueCell = CmpFindValueByName(SystemHive, Node, &KeyName);
+ CurrentValueCell = CmpFindValueByName(SystemHive, Node, &Name);
/* Make sure it exists */
if (CurrentValueCell != HCELL_NIL)
{
- /* Get the current value and make sure its a ULONG */
- KeyValue = (PCM_KEY_VALUE)HvGetCell(SystemHive, CurrentValueCell);
- if (!KeyValue) return HCELL_NIL;
- if (KeyValue->Type == REG_DWORD)
+ /* Get the current value and make sure it's a ULONG */
+ Value = (PCM_KEY_VALUE)HvGetCell(SystemHive, CurrentValueCell);
+ if (!Value) return HCELL_NIL;
+ if (Value->Type == REG_DWORD)
{
/* Get the data and update it */
- CurrentData = (PULONG)CmpValueToData(SystemHive,
- KeyValue,
- &Length);
+ CurrentData = (PULONG)CmpValueToData(SystemHive, Value, &Length);
if (!CurrentData) return HCELL_NIL;
+ if (Length < sizeof(ULONG)) return HCELL_NIL;
+
*CurrentData = *ControlSetId;
}
}
- /* Return the CCS Cell */
+ /* Return the CCS cell */
return ControlSetCell;
}
+/**
+ * @brief
+ * Finds the index of the driver's "Tag" value
+ * in its corresponding group ordering list.
+ *
+ * @param[in] Hive
+ * The SYSTEM hive.
+ *
+ * @param[in] TagCell
+ * The driver's "Tag" registry value's hive cell.
+ *
+ * @param[in] GroupOrderCell
+ * The hive cell of the "Control\GroupOrderList" registry key
+ * inside the currently selected control set.
+ *
+ * @param[in] GroupName
+ * The driver's group name.
+ *
+ * @return
+ * The corresponding tag index, or -1 (last position),
+ * or -2 (next-to-last position).
+ **/
CODE_SEG("INIT")
+static
ULONG
-NTAPI
-CmpFindTagIndex(IN PHHIVE Hive,
- IN HCELL_INDEX TagCell,
- IN HCELL_INDEX GroupOrderCell,
- IN PUNICODE_STRING GroupName)
+CmpFindTagIndex(
+ _In_ PHHIVE Hive,
+ _In_ HCELL_INDEX TagCell,
+ _In_ HCELL_INDEX GroupOrderCell,
+ _In_ PCUNICODE_STRING GroupName)
{
PCM_KEY_VALUE TagValue, Value;
+ PCM_KEY_NODE Node;
HCELL_INDEX OrderCell;
- PULONG TagOrder, DriverTag;
+ PULONG DriverTag, TagOrder;
ULONG CurrentTag, Length;
- PCM_KEY_NODE Node;
BOOLEAN BufferAllocated;
+
+ /* Sanity check: We shouldn't need to release any acquired cells */
ASSERT(Hive->ReleaseCellRoutine == NULL);
/* Get the tag */
Value = (PCM_KEY_VALUE)HvGetCell(Hive, TagCell);
- ASSERT(Value);
+ if (!Value) return -2;
+ if (Value->Type != REG_DWORD) return -2;
DriverTag = (PULONG)CmpValueToData(Hive, Value, &Length);
- ASSERT(DriverTag);
+ if (!DriverTag) return -2;
+ if (Length < sizeof(ULONG)) return -2;
/* Get the order array */
Node = (PCM_KEY_NODE)HvGetCell(Hive, GroupOrderCell);
- ASSERT(Node);
+ if (!Node) return -2;
OrderCell = CmpFindValueByName(Hive, Node, GroupName);
if (OrderCell == HCELL_NIL) return -2;
/* And read it */
TagValue = (PCM_KEY_VALUE)HvGetCell(Hive, OrderCell);
- CmpGetValueData(Hive, TagValue, &Length, (PVOID*)&TagOrder,
&BufferAllocated, &OrderCell);
- ASSERT(TagOrder);
+ if (!TagValue) return -2;
+ if (!CmpGetValueData(Hive,
+ TagValue,
+ &Length,
+ (PVOID*)&TagOrder,
+ &BufferAllocated,
+ &OrderCell)
+ || !TagOrder)
+ {
+ return -2;
+ }
/* Parse each tag */
for (CurrentTag = 1; CurrentTag <= TagOrder[0]; CurrentTag++)
@@ -169,58 +263,154 @@ CmpFindTagIndex(IN PHHIVE Hive,
if (TagOrder[CurrentTag] == *DriverTag)
{
/* Found it -- return the tag */
- if (BufferAllocated) ExFreePool(TagOrder);
+ if (BufferAllocated) Hive->Free(TagOrder, Length);
return CurrentTag;
}
}
/* No matches, so assume next to last ordering */
- if (BufferAllocated) ExFreePool(TagOrder);
+ if (BufferAllocated) Hive->Free(TagOrder, Length);
return -2;
}
+#ifdef _BLDR_
+
+/**
+ * @brief
+ * Checks whether the specified named driver is already in the driver list.
+ * Optionally returns its corresponding driver node.
+ *
+ * @remarks Used in bootloader only.
+ *
+ * @param[in] DriverListHead
+ * The driver list.
+ *
+ * @param[in] DriverName
+ * The name of the driver to search for.
+ *
+ * @param[out] FoundDriver
+ * Optional pointer that receives in output the address of the
+ * matching driver node, if any, or NULL if none has been found.
+ *
+ * @return
+ * TRUE if the driver has been found, FALSE if not.
+ **/
CODE_SEG("INIT")
BOOLEAN
NTAPI
-CmpAddDriverToList(IN PHHIVE Hive,
- IN HCELL_INDEX DriverCell,
- IN HCELL_INDEX GroupOrderCell,
- IN PUNICODE_STRING RegistryPath,
- IN PLIST_ENTRY BootDriverListHead)
+CmpIsDriverInList(
+ _In_ PLIST_ENTRY DriverListHead,
+ _In_ PCUNICODE_STRING DriverName,
+ _Out_opt_ PBOOT_DRIVER_NODE* FoundDriver)
+{
+ PLIST_ENTRY Entry;
+ PBOOT_DRIVER_NODE DriverNode;
+
+ for (Entry = DriverListHead->Flink;
+ Entry != DriverListHead;
+ Entry = Entry->Flink)
+ {
+ DriverNode = CONTAINING_RECORD(Entry,
+ BOOT_DRIVER_NODE,
+ ListEntry.Link);
+
+ if (RtlEqualUnicodeString(&DriverNode->Name,
+ DriverName,
+ TRUE))
+ {
+ /* The driver node has been found */
+ if (FoundDriver)
+ *FoundDriver = DriverNode;
+ return TRUE;
+ }
+ }
+
+ /* None has been found */
+ if (FoundDriver)
+ *FoundDriver = NULL;
+ return FALSE;
+}
+
+#endif /* _BLDR_ */
+
+/**
+ * @brief
+ * Inserts the specified driver entry into the driver list.
+ *
+ * @param[in] Hive
+ * The SYSTEM hive.
+ *
+ * @param[in] DriverCell
+ * The registry key's hive cell of the driver to be added, inside
+ * the "Services" sub-key of the currently selected control set.
+ *
+ * @param[in] GroupOrderCell
+ * The hive cell of the "Control\GroupOrderList" registry key
+ * inside the currently selected control set.
+ *
+ * @param[in] RegistryPath
+ * Constant UNICODE_STRING pointing to
+ * "\\Registry\\Machine\\System\\CurrentControlSet\\Services\\".
+ *
+ * @param[in,out] DriverListHead
+ * The driver list where to insert the driver entry.
+ *
+ * @return
+ * TRUE if the driver has been inserted into the list, FALSE if not.
+ **/
+CODE_SEG("INIT")
+BOOLEAN
+NTAPI
+CmpAddDriverToList(
+ _In_ PHHIVE Hive,
+ _In_ HCELL_INDEX DriverCell,
+ _In_ HCELL_INDEX GroupOrderCell,
+ _In_ PCUNICODE_STRING RegistryPath,
+ _Inout_ PLIST_ENTRY DriverListHead)
{
PBOOT_DRIVER_NODE DriverNode;
PBOOT_DRIVER_LIST_ENTRY DriverEntry;
PCM_KEY_NODE Node;
+ PCM_KEY_VALUE Value;
ULONG Length;
USHORT NameLength;
- HCELL_INDEX ValueCell, TagCell; PCM_KEY_VALUE Value;
- PUNICODE_STRING FileName, RegistryString;
- UNICODE_STRING UnicodeString;
+ HCELL_INDEX ValueCell, TagCell;
+ PUNICODE_STRING FilePath, RegistryString;
+ UNICODE_STRING Name;
PULONG ErrorControl;
PWCHAR Buffer;
+
+ /* Sanity check: We shouldn't need to release any acquired cells */
ASSERT(Hive->ReleaseCellRoutine == NULL);
/* Allocate a driver node and initialize it */
- DriverNode = CmpAllocate(sizeof(BOOT_DRIVER_NODE), FALSE, TAG_CM);
- if (!DriverNode) return FALSE;
+ DriverNode = Hive->Allocate(sizeof(BOOT_DRIVER_NODE), FALSE, TAG_CM);
+ if (!DriverNode)
+ return FALSE;
+
+ RtlZeroMemory(DriverNode, sizeof(BOOT_DRIVER_NODE));
DriverEntry = &DriverNode->ListEntry;
- DriverEntry->RegistryPath.Buffer = NULL;
- DriverEntry->FilePath.Buffer = NULL;
/* Get the driver cell */
Node = (PCM_KEY_NODE)HvGetCell(Hive, DriverCell);
- ASSERT(Node);
+ if (!Node)
+ goto Failure;
/* Get the name from the cell */
- DriverNode->Name.Length = Node->Flags & KEY_COMP_NAME ?
- CmpCompressedNameSize(Node->Name, Node->NameLength)
:
- Node->NameLength;
- DriverNode->Name.MaximumLength = DriverNode->Name.Length;
- NameLength = DriverNode->Name.Length;
+ NameLength = (Node->Flags & KEY_COMP_NAME) ?
+ CmpCompressedNameSize(Node->Name, Node->NameLength) :
+ Node->NameLength;
+ if (NameLength < sizeof(WCHAR))
+ goto Failure;
/* Now allocate the buffer for it and copy the name */
- DriverNode->Name.Buffer = CmpAllocate(NameLength, FALSE, TAG_CM);
- if (!DriverNode->Name.Buffer) return FALSE;
+ RtlInitEmptyUnicodeString(&DriverNode->Name,
+ Hive->Allocate(NameLength, FALSE, TAG_CM),
+ NameLength);
+ if (!DriverNode->Name.Buffer)
+ goto Failure;
+
+ DriverNode->Name.Length = NameLength;
if (Node->Flags & KEY_COMP_NAME)
{
/* Compressed name */
@@ -236,98 +426,134 @@ CmpAddDriverToList(IN PHHIVE Hive,
}
/* Now find the image path */
- RtlInitUnicodeString(&UnicodeString, L"ImagePath");
- ValueCell = CmpFindValueByName(Hive, Node, &UnicodeString);
+ RtlInitUnicodeString(&Name, L"ImagePath");
+ ValueCell = CmpFindValueByName(Hive, Node, &Name);
if (ValueCell == HCELL_NIL)
{
- /* Couldn't find it, so assume the drivers path */
+ /* Could not find it, so assume the drivers path */
Length = sizeof(L"System32\\Drivers\\") + NameLength +
sizeof(L".sys");
/* Allocate the path name */
- FileName = &DriverEntry->FilePath;
- FileName->Length = 0;
- FileName->MaximumLength = (USHORT)Length;
- FileName->Buffer = CmpAllocate(Length, FALSE,TAG_CM);
- if (!FileName->Buffer) return FALSE;
+ FilePath = &DriverEntry->FilePath;
+ RtlInitEmptyUnicodeString(FilePath,
+ Hive->Allocate(Length, FALSE, TAG_CM),
+ (USHORT)Length);
+ if (!FilePath->Buffer)
+ goto Failure;
/* Write the path name */
- RtlAppendUnicodeToString(FileName, L"System32\\Drivers\\");
- RtlAppendUnicodeStringToString(FileName, &DriverNode->Name);
- RtlAppendUnicodeToString(FileName, L".sys");
+ if (!NT_SUCCESS(RtlAppendUnicodeToString(FilePath,
L"System32\\Drivers\\")) ||
+ !NT_SUCCESS(RtlAppendUnicodeStringToString(FilePath,
&DriverNode->Name)) ||
+ !NT_SUCCESS(RtlAppendUnicodeToString(FilePath, L".sys")))
+ {
+ goto Failure;
+ }
}
else
{
/* Path name exists, so grab it */
Value = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell);
- ASSERT(Value);
+ if (!Value)
+ goto Failure;
+ if ((Value->Type != REG_SZ) && (Value->Type != REG_EXPAND_SZ))
+ goto Failure;
+ Buffer = (PWCHAR)CmpValueToData(Hive, Value, &Length);
+ if (!Buffer)
+ goto Failure;
+ if (IS_NULL_TERMINATED(Buffer, Length))
+ Length -= sizeof(UNICODE_NULL);
+ if (Length < sizeof(WCHAR))
+ goto Failure;
/* Allocate and setup the path name */
- FileName = &DriverEntry->FilePath;
- Buffer = (PWCHAR)CmpValueToData(Hive, Value, &Length);
- FileName->MaximumLength = FileName->Length = (USHORT)Length;
- FileName->Buffer = CmpAllocate(Length, FALSE, TAG_CM);
+ FilePath = &DriverEntry->FilePath;
+ RtlInitEmptyUnicodeString(FilePath,
+ Hive->Allocate(Length, FALSE, TAG_CM),
+ (USHORT)Length);
+ if (!FilePath->Buffer)
+ goto Failure;
/* Transfer the data */
- if (!(FileName->Buffer) || !(Buffer)) return FALSE;
- RtlCopyMemory(FileName->Buffer, Buffer, Length);
+ RtlCopyMemory(FilePath->Buffer, Buffer, Length);
+ FilePath->Length = (USHORT)Length;
}
/* Now build the registry path */
RegistryString = &DriverEntry->RegistryPath;
- RegistryString->Length = 0;
- RegistryString->MaximumLength = RegistryPath->Length + NameLength;
- RegistryString->Buffer = CmpAllocate(RegistryString->MaximumLength, FALSE,
TAG_CM);
- if (!RegistryString->Buffer) return FALSE;
+ Length = RegistryPath->Length + NameLength;
+ RtlInitEmptyUnicodeString(RegistryString,
+ Hive->Allocate(Length, FALSE, TAG_CM),
+ (USHORT)Length);
+ if (!RegistryString->Buffer)
+ goto Failure;
/* Add the driver name to it */
- RtlAppendUnicodeStringToString(RegistryString, RegistryPath);
- RtlAppendUnicodeStringToString(RegistryString, &DriverNode->Name);
+ if (!NT_SUCCESS(RtlAppendUnicodeStringToString(RegistryString, RegistryPath)) ||
+ !NT_SUCCESS(RtlAppendUnicodeStringToString(RegistryString,
&DriverNode->Name)))
+ {
+ goto Failure;
+ }
/* The entry is done, add it */
- InsertHeadList(BootDriverListHead, &DriverEntry->Link);
+ InsertHeadList(DriverListHead, &DriverEntry->Link);
/* Now find error control settings */
- RtlInitUnicodeString(&UnicodeString, L"ErrorControl");
- ValueCell = CmpFindValueByName(Hive, Node, &UnicodeString);
+ RtlInitUnicodeString(&Name, L"ErrorControl");
+ ValueCell = CmpFindValueByName(Hive, Node, &Name);
if (ValueCell == HCELL_NIL)
{
- /* Couldn't find it, so assume default */
+ /* Could not find it, so assume default */
DriverNode->ErrorControl = NormalError;
}
else
{
/* Otherwise, read whatever the data says */
Value = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell);
- ASSERT(Value);
+ if (!Value)
+ goto Failure;
+ if (Value->Type != REG_DWORD)
+ goto Failure;
ErrorControl = (PULONG)CmpValueToData(Hive, Value, &Length);
- ASSERT(ErrorControl);
+ if (!ErrorControl)
+ goto Failure;
+ if (Length < sizeof(ULONG))
+ goto Failure;
+
DriverNode->ErrorControl = *ErrorControl;
}
/* Next, get the group cell */
- RtlInitUnicodeString(&UnicodeString, L"group");
- ValueCell = CmpFindValueByName(Hive, Node, &UnicodeString);
+ RtlInitUnicodeString(&Name, L"group");
+ ValueCell = CmpFindValueByName(Hive, Node, &Name);
if (ValueCell == HCELL_NIL)
{
- /* Couldn't find, so set an empty string */
+ /* Could not find it, so set an empty string */
RtlInitEmptyUnicodeString(&DriverNode->Group, NULL, 0);
}
else
{
/* Found it, read the group value */
Value = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell);
- ASSERT(Value);
+ if (!Value)
+ goto Failure;
+ if (Value->Type != REG_SZ) // REG_EXPAND_SZ not really allowed there.
+ goto Failure;
/* Copy it into the node */
- DriverNode->Group.Buffer = (PWCHAR)CmpValueToData(Hive, Value, &Length);
- if (!DriverNode->Group.Buffer) return FALSE;
- DriverNode->Group.Length = (USHORT)Length - sizeof(UNICODE_NULL);
+ Buffer = (PWCHAR)CmpValueToData(Hive, Value, &Length);
+ if (!Buffer)
+ goto Failure;
+ if (IS_NULL_TERMINATED(Buffer, Length))
+ Length -= sizeof(UNICODE_NULL);
+
+ DriverNode->Group.Buffer = Buffer;
+ DriverNode->Group.Length = (USHORT)Length;
DriverNode->Group.MaximumLength = DriverNode->Group.Length;
}
/* Finally, find the tag */
- RtlInitUnicodeString(&UnicodeString, L"Tag");
- TagCell = CmpFindValueByName(Hive, Node, &UnicodeString);
+ RtlInitUnicodeString(&Name, L"Tag");
+ TagCell = CmpFindValueByName(Hive, Node, &Name);
if (TagCell == HCELL_NIL)
{
/* No tag, so load last */
@@ -342,63 +568,135 @@ CmpAddDriverToList(IN PHHIVE Hive,
&DriverNode->Group);
}
+ CMTRACE(CM_BOOT_DEBUG, "Adding boot driver: '%wZ',
'%wZ'\n",
+ &DriverNode->Name, &DriverEntry->FilePath);
+
/* All done! */
return TRUE;
+
+Failure:
+ if (DriverEntry->RegistryPath.Buffer)
+ {
+ Hive->Free(DriverEntry->RegistryPath.Buffer,
+ DriverEntry->RegistryPath.MaximumLength);
+ }
+ if (DriverEntry->FilePath.Buffer)
+ {
+ Hive->Free(DriverEntry->FilePath.Buffer,
+ DriverEntry->FilePath.MaximumLength);
+ }
+ if (DriverNode->Name.Buffer)
+ {
+ Hive->Free(DriverNode->Name.Buffer,
+ DriverNode->Name.MaximumLength);
+ }
+ Hive->Free(DriverNode, sizeof(BOOT_DRIVER_NODE));
+
+ return FALSE;
}
+/**
+ * @brief
+ * Checks whether the specified driver has the expected load type.
+ *
+ * @param[in] Hive
+ * The SYSTEM hive.
+ *
+ * @param[in] DriverCell
+ * The registry key's hive cell of the driver, inside the
+ * "Services" sub-key of the currently selected control set.
+ *
+ * @param[in] LoadType
+ * The load type the driver should match.
+ *
+ * @return
+ * TRUE if the driver's load type matches, FALSE if not.
+ **/
CODE_SEG("INIT")
+static
BOOLEAN
-NTAPI
-CmpIsLoadType(IN PHHIVE Hive,
- IN HCELL_INDEX Cell,
- IN SERVICE_LOAD_TYPE LoadType)
+CmpIsLoadType(
+ _In_ PHHIVE Hive,
+ _In_ HCELL_INDEX Cell,
+ _In_ SERVICE_LOAD_TYPE LoadType)
{
PCM_KEY_NODE Node;
- HCELL_INDEX ValueCell;
- UNICODE_STRING ValueString = RTL_CONSTANT_STRING(L"Start");
PCM_KEY_VALUE Value;
+ UNICODE_STRING Name = RTL_CONSTANT_STRING(L"Start");
+ HCELL_INDEX ValueCell;
ULONG Length;
- PLONG Data;
+ PULONG Data;
+
+ /* Sanity check: We shouldn't need to release any acquired cells */
ASSERT(Hive->ReleaseCellRoutine == NULL);
/* Open the start cell */
Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
- ASSERT(Node);
- ValueCell = CmpFindValueByName(Hive, Node, &ValueString);
+ if (!Node) return FALSE;
+ ValueCell = CmpFindValueByName(Hive, Node, &Name);
if (ValueCell == HCELL_NIL) return FALSE;
/* Read the start value */
Value = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell);
- ASSERT(Value);
- Data = (PLONG)CmpValueToData(Hive, Value, &Length);
- ASSERT(Data);
+ if (!Value) return FALSE;
+ if (Value->Type != REG_DWORD) return FALSE;
+ Data = (PULONG)CmpValueToData(Hive, Value, &Length);
+ if (!Data) return FALSE;
+ if (Length < sizeof(ULONG)) return FALSE;
/* Return if the type matches */
return (*Data == LoadType);
}
+/**
+ * @brief
+ * Enumerates all drivers within the given control set and load type,
+ * present in the "Services" sub-key, and inserts them into the driver list.
+ *
+ * @param[in] Hive
+ * The SYSTEM hive.
+ *
+ * @param[in] ControlSet
+ * The control set registry key's hive cell.
+ *
+ * @param[in] LoadType
+ * The load type the driver should match.
+ *
+ * @param[in] BootFileSystem
+ * Optional name of the boot file system, for which to insert
+ * its corresponding driver.
+ *
+ * @param[in,out] DriverListHead
+ * The driver list where to insert the enumerated drivers.
+ *
+ * @return
+ * TRUE if the drivers have been successfully enumerated and inserted,
+ * FALSE if not.
+ **/
CODE_SEG("INIT")
BOOLEAN
NTAPI
-CmpFindDrivers(IN PHHIVE Hive,
- IN HCELL_INDEX ControlSet,
- IN SERVICE_LOAD_TYPE LoadType,
- IN PWCHAR BootFileSystem OPTIONAL,
- IN PLIST_ENTRY DriverListHead)
+CmpFindDrivers(
+ _In_ PHHIVE Hive,
+ _In_ HCELL_INDEX ControlSet,
+ _In_ SERVICE_LOAD_TYPE LoadType,
+ _In_opt_ PCWSTR BootFileSystem,
+ _Inout_ PLIST_ENTRY DriverListHead)
{
HCELL_INDEX ServicesCell, ControlCell, GroupOrderCell, DriverCell;
HCELL_INDEX SafeBootCell = HCELL_NIL;
- UNICODE_STRING Name;
ULONG i;
- WCHAR Buffer[128];
- UNICODE_STRING UnicodeString, KeyPath;
- PBOOT_DRIVER_NODE FsNode;
+ UNICODE_STRING Name;
+ UNICODE_STRING KeyPath;
PCM_KEY_NODE ControlNode, ServicesNode, Node;
+ PBOOT_DRIVER_NODE FsNode;
+
+ /* Sanity check: We shouldn't need to release any acquired cells */
ASSERT(Hive->ReleaseCellRoutine == NULL);
/* Open the control set key */
ControlNode = (PCM_KEY_NODE)HvGetCell(Hive, ControlSet);
- ASSERT(ControlNode);
+ if (!ControlNode) return FALSE;
/* Get services cell */
RtlInitUnicodeString(&Name, L"Services");
@@ -407,7 +705,7 @@ CmpFindDrivers(IN PHHIVE Hive,
/* Open services key */
ServicesNode = (PCM_KEY_NODE)HvGetCell(Hive, ServicesCell);
- ASSERT(ServicesNode);
+ if (!ServicesNode) return FALSE;
/* Get control cell */
RtlInitUnicodeString(&Name, L"Control");
@@ -415,26 +713,26 @@ CmpFindDrivers(IN PHHIVE Hive,
if (ControlCell == HCELL_NIL) return FALSE;
/* Get the group order cell and read it */
- RtlInitUnicodeString(&Name, L"GroupOrderList");
Node = (PCM_KEY_NODE)HvGetCell(Hive, ControlCell);
- ASSERT(Node);
+ if (!Node) return FALSE;
+ RtlInitUnicodeString(&Name, L"GroupOrderList");
GroupOrderCell = CmpFindSubKeyByName(Hive, Node, &Name);
if (GroupOrderCell == HCELL_NIL) return FALSE;
/* Get Safe Boot cell */
- if(InitSafeBootMode)
+ if (InitSafeBootMode)
{
/* Open the Safe Boot key */
RtlInitUnicodeString(&Name, L"SafeBoot");
Node = (PCM_KEY_NODE)HvGetCell(Hive, ControlCell);
- ASSERT(Node);
+ if (!Node) return FALSE;
SafeBootCell = CmpFindSubKeyByName(Hive, Node, &Name);
if (SafeBootCell == HCELL_NIL) return FALSE;
/* Open the correct start key (depending on the mode) */
Node = (PCM_KEY_NODE)HvGetCell(Hive, SafeBootCell);
- ASSERT(Node);
- switch(InitSafeBootMode)
+ if (!Node) return FALSE;
+ switch (InitSafeBootMode)
{
/* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
case 1:
@@ -443,14 +741,13 @@ CmpFindDrivers(IN PHHIVE Hive,
default: return FALSE;
}
SafeBootCell = CmpFindSubKeyByName(Hive, Node, &Name);
- if(SafeBootCell == HCELL_NIL) return FALSE;
+ if (SafeBootCell == HCELL_NIL) return FALSE;
}
/* Build the root registry path */
- RtlInitEmptyUnicodeString(&KeyPath, Buffer, sizeof(Buffer));
- RtlAppendUnicodeToString(&KeyPath,
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
+ RtlInitUnicodeString(&KeyPath,
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
- /* Find the first subkey (ie: the first driver or service) */
+ /* Enumerate each sub-key */
i = 0;
DriverCell = CmpFindSubKeyByNumber(Hive, ServicesNode, i);
while (DriverCell != HCELL_NIL)
@@ -460,15 +757,17 @@ CmpFindDrivers(IN PHHIVE Hive,
CmpIsSafe(Hive, SafeBootCell, DriverCell))
{
/* Add it to the list */
- CmpAddDriverToList(Hive,
- DriverCell,
- GroupOrderCell,
- &KeyPath,
- DriverListHead);
-
+ if (!CmpAddDriverToList(Hive,
+ DriverCell,
+ GroupOrderCell,
+ &KeyPath,
+ DriverListHead))
+ {
+ CMTRACE(CM_BOOT_DEBUG, " Failed to add boot driver\n");
+ }
}
- /* Try the next subkey */
+ /* Go to the next sub-key */
DriverCell = CmpFindSubKeyByNumber(Hive, ServicesNode, ++i);
}
@@ -476,22 +775,30 @@ CmpFindDrivers(IN PHHIVE Hive,
if (BootFileSystem)
{
/* Find it */
- RtlInitUnicodeString(&UnicodeString, BootFileSystem);
- DriverCell = CmpFindSubKeyByName(Hive, ServicesNode, &UnicodeString);
+ RtlInitUnicodeString(&Name, BootFileSystem);
+ DriverCell = CmpFindSubKeyByName(Hive, ServicesNode, &Name);
if (DriverCell != HCELL_NIL)
{
+ CMTRACE(CM_BOOT_DEBUG, "Adding Boot FileSystem '%S'\n",
+ BootFileSystem);
+
/* Always add it to the list */
- CmpAddDriverToList(Hive,
- DriverCell,
- GroupOrderCell,
- &KeyPath,
- DriverListHead);
-
- /* Mark it as critical so it always loads */
- FsNode = CONTAINING_RECORD(DriverListHead->Flink,
- BOOT_DRIVER_NODE,
- ListEntry.Link);
- FsNode->ErrorControl = SERVICE_ERROR_CRITICAL;
+ if (!CmpAddDriverToList(Hive,
+ DriverCell,
+ GroupOrderCell,
+ &KeyPath,
+ DriverListHead))
+ {
+ CMTRACE(CM_BOOT_DEBUG, " Failed to add boot driver\n");
+ }
+ else
+ {
+ /* Mark it as critical so it always loads */
+ FsNode = CONTAINING_RECORD(DriverListHead->Flink,
+ BOOT_DRIVER_NODE,
+ ListEntry.Link);
+ FsNode->ErrorControl = SERVICE_ERROR_CRITICAL;
+ }
}
}
@@ -499,15 +806,32 @@ CmpFindDrivers(IN PHHIVE Hive,
return TRUE;
}
+/**
+ * @brief
+ * Performs the driver list sorting, according to the ordering list.
+ *
+ * @param[in] Hive
+ * The SYSTEM hive.
+ *
+ * @param[in] ControlSet
+ * The control set registry key's hive cell.
+ *
+ * @param[in,out] DriverListHead
+ * The driver list to sort.
+ *
+ * @return
+ * TRUE if sorting has been successfully done, FALSE if not.
+ **/
CODE_SEG("INIT")
+static
BOOLEAN
-NTAPI
-CmpDoSort(IN PLIST_ENTRY DriverListHead,
- IN PUNICODE_STRING OrderList)
+CmpDoSort(
+ _Inout_ PLIST_ENTRY DriverListHead,
+ _In_ PCUNICODE_STRING OrderList)
{
PWCHAR Current, End = NULL;
- PLIST_ENTRY NextEntry;
UNICODE_STRING GroupName;
+ PLIST_ENTRY NextEntry;
PBOOT_DRIVER_NODE CurrentNode;
/* We're going from end to start, so get to the last group and keep going */
@@ -536,11 +860,11 @@ CmpDoSort(IN PLIST_ENTRY DriverListHead,
ListEntry.Link);
/* Get the next entry now since we'll do a relink */
- NextEntry = CurrentNode->ListEntry.Link.Flink;
+ NextEntry = NextEntry->Flink;
/* Is there a group name and does it match the current group? */
- if ((CurrentNode->Group.Buffer) &&
- (RtlEqualUnicodeString(&GroupName, &CurrentNode->Group,
TRUE)))
+ if (CurrentNode->Group.Buffer &&
+ RtlEqualUnicodeString(&GroupName, &CurrentNode->Group, TRUE))
{
/* Remove from this location and re-link in the new one */
RemoveEntryList(&CurrentNode->ListEntry.Link);
@@ -549,67 +873,89 @@ CmpDoSort(IN PLIST_ENTRY DriverListHead,
}
/* Move on */
- Current--;
+ --Current;
}
/* All done */
return TRUE;
}
+/**
+ * @brief
+ * Sorts the driver list, according to the drivers' group load ordering.
+ *
+ * @param[in] Hive
+ * The SYSTEM hive.
+ *
+ * @param[in] ControlSet
+ * The control set registry key's hive cell.
+ *
+ * @param[in,out] DriverListHead
+ * The driver list to sort.
+ *
+ * @return
+ * TRUE if sorting has been successfully done, FALSE if not.
+ **/
CODE_SEG("INIT")
BOOLEAN
NTAPI
-CmpSortDriverList(IN PHHIVE Hive,
- IN HCELL_INDEX ControlSet,
- IN PLIST_ENTRY DriverListHead)
+CmpSortDriverList(
+ _In_ PHHIVE Hive,
+ _In_ HCELL_INDEX ControlSet,
+ _Inout_ PLIST_ENTRY DriverListHead)
{
- HCELL_INDEX Controls, GroupOrder, ListCell;
- UNICODE_STRING Name, DependList;
- PCM_KEY_VALUE ListNode;
- ULONG Length;
PCM_KEY_NODE Node;
+ PCM_KEY_VALUE ListValue;
+ HCELL_INDEX ControlCell, GroupOrder, ListCell;
+ UNICODE_STRING Name, OrderList;
+ ULONG Length;
+
+ /* Sanity check: We shouldn't need to release any acquired cells */
ASSERT(Hive->ReleaseCellRoutine == NULL);
/* Open the control key */
Node = (PCM_KEY_NODE)HvGetCell(Hive, ControlSet);
- ASSERT(Node);
+ if (!Node) return FALSE;
RtlInitUnicodeString(&Name, L"Control");
- Controls = CmpFindSubKeyByName(Hive, Node, &Name);
- if (Controls == HCELL_NIL) return FALSE;
+ ControlCell = CmpFindSubKeyByName(Hive, Node, &Name);
+ if (ControlCell == HCELL_NIL) return FALSE;
/* Open the service group order */
- Node = (PCM_KEY_NODE)HvGetCell(Hive, Controls);
- ASSERT(Node);
+ Node = (PCM_KEY_NODE)HvGetCell(Hive, ControlCell);
+ if (!Node) return FALSE;
RtlInitUnicodeString(&Name, L"ServiceGroupOrder");
GroupOrder = CmpFindSubKeyByName(Hive, Node, &Name);
if (GroupOrder == HCELL_NIL) return FALSE;
/* Open the list key */
Node = (PCM_KEY_NODE)HvGetCell(Hive, GroupOrder);
- ASSERT(Node);
+ if (!Node) return FALSE;
RtlInitUnicodeString(&Name, L"list");
ListCell = CmpFindValueByName(Hive, Node, &Name);
if (ListCell == HCELL_NIL) return FALSE;
- /* Now read the actual list */
- ListNode = (PCM_KEY_VALUE)HvGetCell(Hive, ListCell);
- ASSERT(ListNode);
- if (ListNode->Type != REG_MULTI_SZ) return FALSE;
+ /* Read the actual list */
+ ListValue = (PCM_KEY_VALUE)HvGetCell(Hive, ListCell);
+ if (!ListValue) return FALSE;
+ if (ListValue->Type != REG_MULTI_SZ) return FALSE;
/* Copy it into a buffer */
- DependList.Buffer = (PWCHAR)CmpValueToData(Hive, ListNode, &Length);
- if (!DependList.Buffer) return FALSE;
- DependList.Length = DependList.MaximumLength = (USHORT)Length -
sizeof(UNICODE_NULL);
-
- /* And start the recurive sort algorithm */
- return CmpDoSort(DriverListHead, &DependList);
+ OrderList.Buffer = (PWCHAR)CmpValueToData(Hive, ListValue, &Length);
+ if (!OrderList.Buffer) return FALSE;
+ if (!IS_NULL_TERMINATED(OrderList.Buffer, Length)) return FALSE;
+ OrderList.Length = (USHORT)Length - sizeof(UNICODE_NULL);
+ OrderList.MaximumLength = OrderList.Length;
+
+ /* And start the sort algorithm */
+ return CmpDoSort(DriverListHead, &OrderList);
}
CODE_SEG("INIT")
+static
BOOLEAN
-NTAPI
-CmpOrderGroup(IN PBOOT_DRIVER_NODE StartNode,
- IN PBOOT_DRIVER_NODE EndNode)
+CmpOrderGroup(
+ _In_ PBOOT_DRIVER_NODE StartNode,
+ _In_ PBOOT_DRIVER_NODE EndNode)
{
PBOOT_DRIVER_NODE CurrentNode, PreviousNode;
PLIST_ENTRY ListEntry;
@@ -668,10 +1014,21 @@ CmpOrderGroup(IN PBOOT_DRIVER_NODE StartNode,
return TRUE;
}
+/**
+ * @brief
+ * Removes potential circular dependencies (cycles) and sorts the driver list.
+ *
+ * @param[in,out] DriverListHead
+ * The driver list to sort.
+ *
+ * @return
+ * Always TRUE.
+ **/
CODE_SEG("INIT")
BOOLEAN
NTAPI
-CmpResolveDriverDependencies(IN PLIST_ENTRY DriverListHead)
+CmpResolveDriverDependencies(
+ _Inout_ PLIST_ENTRY DriverListHead)
{
PLIST_ENTRY NextEntry;
PBOOT_DRIVER_NODE StartNode, EndNode, CurrentNode;
@@ -719,60 +1076,76 @@ CmpResolveDriverDependencies(IN PLIST_ENTRY DriverListHead)
}
CODE_SEG("INIT")
+static
BOOLEAN
-NTAPI
-CmpIsSafe(IN PHHIVE Hive,
- IN HCELL_INDEX SafeBootCell,
- IN HCELL_INDEX DriverCell)
+CmpIsSafe(
+ _In_ PHHIVE Hive,
+ _In_ HCELL_INDEX SafeBootCell,
+ _In_ HCELL_INDEX DriverCell)
{
PCM_KEY_NODE SafeBootNode;
PCM_KEY_NODE DriverNode;
PCM_KEY_VALUE KeyValue;
HCELL_INDEX CellIndex;
- ULONG Length = 0;
+ ULONG Length;
UNICODE_STRING Name;
- PWCHAR OriginalName;
+ PWCHAR Buffer;
+
+ /* Sanity check: We shouldn't need to release any acquired cells */
ASSERT(Hive->ReleaseCellRoutine == NULL);
/* Driver key node (mandatory) */
ASSERT(DriverCell != HCELL_NIL);
DriverNode = (PCM_KEY_NODE)HvGetCell(Hive, DriverCell);
- ASSERT(DriverNode);
+ if (!DriverNode) return FALSE;
/* Safe boot key node (optional but return TRUE if not present) */
- if(SafeBootCell == HCELL_NIL) return TRUE;
+ if (SafeBootCell == HCELL_NIL) return TRUE;
SafeBootNode = (PCM_KEY_NODE)HvGetCell(Hive, SafeBootCell);
- if(!SafeBootNode) return FALSE;
+ if (!SafeBootNode) return FALSE;
/* Search by the name from the group */
RtlInitUnicodeString(&Name, L"Group");
CellIndex = CmpFindValueByName(Hive, DriverNode, &Name);
- if(CellIndex != HCELL_NIL)
+ if (CellIndex != HCELL_NIL)
{
KeyValue = (PCM_KEY_VALUE)HvGetCell(Hive, CellIndex);
- ASSERT(KeyValue);
- if (KeyValue->Type == REG_SZ || KeyValue->Type == REG_EXPAND_SZ)
+ if (!KeyValue) return FALSE;
+
+ if (KeyValue->Type == REG_SZ) // REG_EXPAND_SZ not really allowed there.
{
/* Compose the search 'key' */
- Name.Buffer = (PWCHAR)CmpValueToData(Hive, KeyValue, &Length);
- if (!Name.Buffer) return FALSE;
- Name.Length = (USHORT)Length - sizeof(UNICODE_NULL);
+ Buffer = (PWCHAR)CmpValueToData(Hive, KeyValue, &Length);
+ if (!Buffer)
+ return FALSE;
+ if (IS_NULL_TERMINATED(Buffer, Length))
+ Length -= sizeof(UNICODE_NULL);
+
+ Name.Buffer = Buffer;
+ Name.Length = (USHORT)Length;
Name.MaximumLength = Name.Length;
+
/* Search for corresponding key in the Safe Boot key */
CellIndex = CmpFindSubKeyByName(Hive, SafeBootNode, &Name);
- if(CellIndex != HCELL_NIL) return TRUE;
+ if (CellIndex != HCELL_NIL) return TRUE;
}
}
/* Group has not been found - find driver name */
- Name.Length = DriverNode->Flags & KEY_COMP_NAME ?
- CmpCompressedNameSize(DriverNode->Name,
- DriverNode->NameLength) :
- DriverNode->NameLength;
- Name.MaximumLength = Name.Length;
+ Length = (DriverNode->Flags & KEY_COMP_NAME) ?
+ CmpCompressedNameSize(DriverNode->Name, DriverNode->NameLength) :
+ DriverNode->NameLength;
+ if (Length < sizeof(WCHAR))
+ return FALSE;
+
/* Now allocate the buffer for it and copy the name */
- Name.Buffer = CmpAllocate(Name.Length, FALSE, TAG_CM);
- if (!Name.Buffer) return FALSE;
+ RtlInitEmptyUnicodeString(&Name,
+ Hive->Allocate(Length, FALSE, TAG_CM),
+ (USHORT)Length);
+ if (!Name.Buffer)
+ return FALSE;
+
+ Name.Length = (USHORT)Length;
if (DriverNode->Flags & KEY_COMP_NAME)
{
/* Compressed name */
@@ -786,38 +1159,102 @@ CmpIsSafe(IN PHHIVE Hive,
/* Normal name */
RtlCopyMemory(Name.Buffer, DriverNode->Name, DriverNode->NameLength);
}
+
CellIndex = CmpFindSubKeyByName(Hive, SafeBootNode, &Name);
- RtlFreeUnicodeString(&Name);
- if(CellIndex != HCELL_NIL) return TRUE;
+ Hive->Free(Name.Buffer, Name.MaximumLength);
+ if (CellIndex != HCELL_NIL) return TRUE;
/* Not group or driver name - search by image name */
RtlInitUnicodeString(&Name, L"ImagePath");
CellIndex = CmpFindValueByName(Hive, DriverNode, &Name);
- if(CellIndex != HCELL_NIL)
+ if (CellIndex != HCELL_NIL)
{
KeyValue = (PCM_KEY_VALUE)HvGetCell(Hive, CellIndex);
- ASSERT(KeyValue);
- if (KeyValue->Type == REG_SZ || KeyValue->Type == REG_EXPAND_SZ)
+ if (!KeyValue) return FALSE;
+
+ if ((KeyValue->Type == REG_SZ) || (KeyValue->Type == REG_EXPAND_SZ))
{
/* Compose the search 'key' */
- OriginalName = (PWCHAR)CmpValueToData(Hive, KeyValue, &Length);
- if (!OriginalName) return FALSE;
+ Buffer = (PWCHAR)CmpValueToData(Hive, KeyValue, &Length);
+ if (!Buffer) return FALSE;
+ if (Length < sizeof(WCHAR)) return FALSE;
+
/* Get the base image file name */
- Name.Buffer = wcsrchr(OriginalName, L'\\');
+ // FIXME: wcsrchr() may fail if Buffer is *not* NULL-terminated!
+ Name.Buffer = wcsrchr(Buffer, OBJ_NAME_PATH_SEPARATOR);
if (!Name.Buffer) return FALSE;
++Name.Buffer;
- /* Length of the base name must be >=1 */
- Name.Length = (USHORT)Length - (USHORT)((PUCHAR)Name.Buffer -
(PUCHAR)OriginalName)
- - sizeof(UNICODE_NULL);
- if(Name.Length < 1) return FALSE;
+
+ /* Length of the base name must be >=1 WCHAR */
+ if (((ULONG_PTR)Name.Buffer - (ULONG_PTR)Buffer) >= Length)
+ return FALSE;
+ Length -= ((ULONG_PTR)Name.Buffer - (ULONG_PTR)Buffer);
+ if (IS_NULL_TERMINATED(Name.Buffer, Length))
+ Length -= sizeof(UNICODE_NULL);
+ if (Length < sizeof(WCHAR)) return FALSE;
+
+ Name.Length = (USHORT)Length;
Name.MaximumLength = Name.Length;
+
/* Search for corresponding key in the Safe Boot key */
CellIndex = CmpFindSubKeyByName(Hive, SafeBootNode, &Name);
- if(CellIndex != HCELL_NIL) return TRUE;
+ if (CellIndex != HCELL_NIL) return TRUE;
}
}
+
/* Nothing found - nothing else to search */
return FALSE;
}
+/**
+ * @brief
+ * Empties the driver list and frees all allocated driver nodes in it.
+ *
+ * @param[in] Hive
+ * The SYSTEM hive (used only for the Hive->Free() memory deallocator).
+ *
+ * @param[in,out] DriverListHead
+ * The driver list to free.
+ *
+ * @return None
+ **/
+CODE_SEG("INIT")
+VOID
+NTAPI
+CmpFreeDriverList(
+ _In_ PHHIVE Hive,
+ _Inout_ PLIST_ENTRY DriverListHead)
+{
+ PLIST_ENTRY Entry;
+ PBOOT_DRIVER_NODE DriverNode;
+
+ /* Loop through the list and remove each driver node */
+ while (!IsListEmpty(DriverListHead))
+ {
+ /* Get the driver node */
+ Entry = RemoveHeadList(DriverListHead);
+ DriverNode = CONTAINING_RECORD(Entry,
+ BOOT_DRIVER_NODE,
+ ListEntry.Link);
+
+ /* Free any allocated string buffers, then the node */
+ if (DriverNode->ListEntry.RegistryPath.Buffer)
+ {
+ Hive->Free(DriverNode->ListEntry.RegistryPath.Buffer,
+ DriverNode->ListEntry.RegistryPath.MaximumLength);
+ }
+ if (DriverNode->ListEntry.FilePath.Buffer)
+ {
+ Hive->Free(DriverNode->ListEntry.FilePath.Buffer,
+ DriverNode->ListEntry.FilePath.MaximumLength);
+ }
+ if (DriverNode->Name.Buffer)
+ {
+ Hive->Free(DriverNode->Name.Buffer,
+ DriverNode->Name.MaximumLength);
+ }
+ Hive->Free(DriverNode, sizeof(BOOT_DRIVER_NODE));
+ }
+}
+
/* EOF */
diff --git a/ntoskrnl/config/cmsysini.c b/ntoskrnl/config/cmsysini.c
index 9b9c37bd27a..5260cb69a42 100644
--- a/ntoskrnl/config/cmsysini.c
+++ b/ntoskrnl/config/cmsysini.c
@@ -1721,55 +1721,6 @@ CmInitSystem1(VOID)
return TRUE;
}
-CODE_SEG("INIT")
-VOID
-NTAPI
-CmpFreeDriverList(IN PHHIVE Hive,
- IN PLIST_ENTRY DriverList)
-{
- PLIST_ENTRY NextEntry, OldEntry;
- PBOOT_DRIVER_NODE DriverNode;
- PAGED_CODE();
-
- /* Parse the current list */
- NextEntry = DriverList->Flink;
- while (NextEntry != DriverList)
- {
- /* Get the driver node */
- DriverNode = CONTAINING_RECORD(NextEntry, BOOT_DRIVER_NODE, ListEntry.Link);
-
- /* Get the next entry now, since we're going to free it later */
- OldEntry = NextEntry;
- NextEntry = NextEntry->Flink;
-
- /* Was there a name? */
- if (DriverNode->Name.Buffer)
- {
- /* Free it */
- CmpFree(DriverNode->Name.Buffer, DriverNode->Name.Length);
- }
-
- /* Was there a registry path? */
- if (DriverNode->ListEntry.RegistryPath.Buffer)
- {
- /* Free it */
- CmpFree(DriverNode->ListEntry.RegistryPath.Buffer,
- DriverNode->ListEntry.RegistryPath.MaximumLength);
- }
-
- /* Was there a file path? */
- if (DriverNode->ListEntry.FilePath.Buffer)
- {
- /* Free it */
- CmpFree(DriverNode->ListEntry.FilePath.Buffer,
- DriverNode->ListEntry.FilePath.MaximumLength);
- }
-
- /* Now free the node, and move on */
- CmpFree(OldEntry, sizeof(BOOT_DRIVER_NODE));
- }
-}
-
CODE_SEG("INIT")
PUNICODE_STRING*
NTAPI
diff --git a/ntoskrnl/include/internal/cm.h b/ntoskrnl/include/internal/cm.h
index a251ab1bead..bd3dbe515e8 100644
--- a/ntoskrnl/include/internal/cm.h
+++ b/ntoskrnl/include/internal/cm.h
@@ -5,9 +5,12 @@
* PURPOSE: Internal header for the Configuration Manager
* PROGRAMMERS: Alex Ionescu (alex.ionescu(a)reactos.org)
*/
-#define _CM_
-#include "cmlib.h"
+
+#pragma once
+
+#include <cmlib.h>
#include <cmreslist.h>
+#include "cmboot.h"
//
// Define this if you want debugging support
@@ -1168,16 +1171,6 @@ CmpCreateLinkNode(
//
// Boot Routines
//
-CODE_SEG("INIT")
-HCELL_INDEX
-NTAPI
-CmpFindControlSet(
- IN PHHIVE SystemHive,
- IN HCELL_INDEX RootCell,
- IN PUNICODE_STRING SelectKeyName,
- OUT PBOOLEAN AutoSelect
-);
-
CODE_SEG("INIT")
VOID
NTAPI
@@ -1453,41 +1446,6 @@ CmGetSystemDriverList(
VOID
);
-CODE_SEG("INIT")
-BOOLEAN
-NTAPI
-CmpFindDrivers(
- IN PHHIVE Hive,
- IN HCELL_INDEX ControlSet,
- IN SERVICE_LOAD_TYPE LoadType,
- IN PWSTR BootFileSystem OPTIONAL,
- IN PLIST_ENTRY DriverListHead
-);
-
-CODE_SEG("INIT")
-BOOLEAN
-NTAPI
-CmpSortDriverList(
- IN PHHIVE Hive,
- IN HCELL_INDEX ControlSet,
- IN PLIST_ENTRY DriverListHead
-);
-
-CODE_SEG("INIT")
-BOOLEAN
-NTAPI
-CmpResolveDriverDependencies(
- IN PLIST_ENTRY DriverListHead
-);
-
-CODE_SEG("INIT")
-BOOLEAN
-NTAPI
-CmpIsSafe(
- IN PHHIVE Hive,
- IN HCELL_INDEX SafeBootCell,
- IN HCELL_INDEX DriverCell);
-
//
// Global variables accessible from all of Cm
//
diff --git a/ntoskrnl/include/internal/cmboot.h b/ntoskrnl/include/internal/cmboot.h
new file mode 100644
index 00000000000..39d0ce098c2
--- /dev/null
+++ b/ntoskrnl/include/internal/cmboot.h
@@ -0,0 +1,80 @@
+/*
+ * PROJECT: ReactOS Kernel
+ * LICENSE: BSD - See COPYING.ARM in the top level directory
+ * PURPOSE: Configuration Manager - Boot Initialization Internal header
+ * COPYRIGHT: Copyright 2010 ReactOS Portable Systems Group
+ *
+ * NOTE: This module is shared by both the kernel and the bootloader.
+ */
+
+//
+// Boot Driver Node
+//
+typedef struct _BOOT_DRIVER_NODE
+{
+ BOOT_DRIVER_LIST_ENTRY ListEntry;
+ UNICODE_STRING Group;
+ UNICODE_STRING Name;
+ ULONG Tag;
+ ULONG ErrorControl;
+} BOOT_DRIVER_NODE, *PBOOT_DRIVER_NODE;
+
+
+//
+// Boot Routines
+//
+CODE_SEG("INIT")
+HCELL_INDEX
+NTAPI
+CmpFindControlSet(
+ _In_ PHHIVE SystemHive,
+ _In_ HCELL_INDEX RootCell,
+ _In_ PCUNICODE_STRING SelectKeyName,
+ _Out_ PBOOLEAN AutoSelect);
+
+
+//
+// Driver List Routines
+//
+#ifdef _BLDR_
+
+CODE_SEG("INIT")
+BOOLEAN
+NTAPI
+CmpIsDriverInList(
+ _In_ PLIST_ENTRY DriverListHead,
+ _In_ PCUNICODE_STRING DriverName,
+ _Out_opt_ PBOOT_DRIVER_NODE* FoundDriver);
+
+#endif /* _BLDR_ */
+
+CODE_SEG("INIT")
+BOOLEAN
+NTAPI
+CmpFindDrivers(
+ _In_ PHHIVE Hive,
+ _In_ HCELL_INDEX ControlSet,
+ _In_ SERVICE_LOAD_TYPE LoadType,
+ _In_opt_ PCWSTR BootFileSystem,
+ _Inout_ PLIST_ENTRY DriverListHead);
+
+CODE_SEG("INIT")
+BOOLEAN
+NTAPI
+CmpSortDriverList(
+ _In_ PHHIVE Hive,
+ _In_ HCELL_INDEX ControlSet,
+ _Inout_ PLIST_ENTRY DriverListHead);
+
+CODE_SEG("INIT")
+BOOLEAN
+NTAPI
+CmpResolveDriverDependencies(
+ _Inout_ PLIST_ENTRY DriverListHead);
+
+CODE_SEG("INIT")
+VOID
+NTAPI
+CmpFreeDriverList(
+ _In_ PHHIVE Hive,
+ _Inout_ PLIST_ENTRY DriverListHead);
diff --git a/ntoskrnl/include/internal/io.h b/ntoskrnl/include/internal/io.h
index 46470e9835c..ca18912a941 100644
--- a/ntoskrnl/include/internal/io.h
+++ b/ntoskrnl/include/internal/io.h
@@ -1,10 +1,10 @@
/*
-* PROJECT: ReactOS Kernel
-* LICENSE: GPL - See COPYING in the top level directory
-* FILE: ntoskrnl/include/internal/io.h
-* PURPOSE: Internal header for the I/O Manager
-* PROGRAMMERS: Alex Ionescu (alex.ionescu(a)reactos.org)
-*/
+ * PROJECT: ReactOS Kernel
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: ntoskrnl/include/internal/io.h
+ * PURPOSE: Internal header for the I/O Manager
+ * PROGRAMMERS: Alex Ionescu (alex.ionescu(a)reactos.org)
+ */
#include "ntdddisk.h"
@@ -410,18 +410,6 @@ typedef struct _DRIVER_INFORMATION
NTSTATUS Status;
} DRIVER_INFORMATION, *PDRIVER_INFORMATION;
-//
-// Boot Driver Node
-//
-typedef struct _BOOT_DRIVER_NODE
-{
- BOOT_DRIVER_LIST_ENTRY ListEntry;
- UNICODE_STRING Group;
- UNICODE_STRING Name;
- ULONG Tag;
- ULONG ErrorControl;
-} BOOT_DRIVER_NODE, *PBOOT_DRIVER_NODE;
-
//
// List of Bus Type GUIDs
//