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@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 + #define NDEBUG -#include "debug.h" +#include -/* GLOBALS ********************************************************************/ +#ifdef _BLDR_ + +#undef CODE_SEG +#define CODE_SEG(...) + +#include +#include +#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); + 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 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); + /* 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; - HCELL_INDEX OrderCell; - PULONG TagOrder, DriverTag; - ULONG CurrentTag, Length; PCM_KEY_NODE Node; + HCELL_INDEX OrderCell; + PULONG DriverTag, TagOrder; + ULONG CurrentTag, Length; 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) { - /* Always add it to the list */ - CmpAddDriverToList(Hive, - DriverCell, - GroupOrderCell, - &KeyPath, - DriverListHead); + CMTRACE(CM_BOOT_DEBUG, "Adding Boot FileSystem '%S'\n", + BootFileSystem); - /* Mark it as critical so it always loads */ - FsNode = CONTAINING_RECORD(DriverListHead->Flink, - BOOT_DRIVER_NODE, - ListEntry.Link); - FsNode->ErrorControl = SERVICE_ERROR_CRITICAL; + /* Always add it to the list */ + 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); + 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 recurive sort algorithm */ - return CmpDoSort(DriverListHead, &DependList); + /* 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@reactos.org) */ -#define _CM_ -#include "cmlib.h" + +#pragma once + +#include #include +#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@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 //