[NTOS:CM] Adapt cmboot.c for usage in NT/ReactOS bootloader.
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Mon, 21 Mar 2022 22:16:19 +0000 (23:16 +0100)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sat, 16 Apr 2022 16:37:45 +0000 (18:37 +0200)
- 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
ntoskrnl/config/cmsysini.c
ntoskrnl/include/internal/cm.h
ntoskrnl/include/internal/cmboot.h [new file with mode: 0644]
ntoskrnl/include/internal/io.h

index 98dd2a0..fdd1a6e 100644 (file)
 /*
- * 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@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@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 */
index 9b9c37b..5260cb6 100644 (file)
@@ -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
index a251ab1..bd3dbe5 100644 (file)
@@ -5,9 +5,12 @@
  * PURPOSE:         Internal header for the Configuration Manager
  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@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 (file)
index 0000000..39d0ce0
--- /dev/null
@@ -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);
index 46470e9..ca18912 100644 (file)
@@ -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@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@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
 //