Reactos

[NTOS:CM] Adapt cmboot.c for usage in NT/ReactOS bootloader.

- Add a new cmboot.h header to isolate the boot-support definitions
shared with the NT/ReactOS bootloader.

- Move CmpFreeDriverList() to cmboot.c so that we can use it for
cleanup paths in the NT/ReactOS bootloader.

- CmpFindControlSet(): Directly build the control set name in UNICODE,
instead of doing an ANSI->UNICODE conversion.

- Directly assign the CurrentControlSet\Services constant string,
instead of going the route of init-empty-string + append-string.
This is possible since that string is not modified later.

- Remove ASSERT(FALSE), replacing them with correct failure handling.

- Add cleanup paths in CmpAddDriverToList().

- Simplify and fix CmpFreeDriverList(): it's the full DriverNode
that needs to be freed; not the LIST_ENTRY pointer.

- Add other validity checks:
* Registry value types and data sizes;
* For multi-strings, verify that they are NULL-terminated.
* For (multi-)strings, check whether they are NULL-terminated before
optionally removing their trailing NULL character from the count.
Check also whether they are of zero-length and take appropriate
action where necessary.

- Add CmpIsDriverInList() for future usage in CMBOOT compiled in
bootloader mode.

- Add SAL annotations and Doxygen documentation.

- Add debug traces.

- Formatting / code style fixes.

** TODO: Fix SafeBoot support **

+784 -370
+693 -256
ntoskrnl/config/cmboot.c
··· 1 1 /* 2 - * PROJECT: ReactOS Kernel 3 - * LICENSE: BSD - See COPYING.ARM in the top level directory 4 - * FILE: ntoskrnl/config/cmboot.c 5 - * PURPOSE: Configuration Manager - Boot Initialization 6 - * PROGRAMMERS: ReactOS Portable Systems Group 7 - * Alex Ionescu (alex.ionescu@reactos.org) 2 + * PROJECT: ReactOS Kernel 3 + * LICENSE: BSD - See COPYING.ARM in the top level directory 4 + * PURPOSE: Configuration Manager - Boot Initialization 5 + * COPYRIGHT: Copyright 2007 Alex Ionescu (alex.ionescu@reactos.org) 6 + * Copyright 2010 ReactOS Portable Systems Group 7 + * Copyright 2022 Hermès Bélusca-Maïto 8 + * 9 + * NOTE: This module is shared by both the kernel and the bootloader. 8 10 */ 9 11 10 12 /* INCLUDES *******************************************************************/ 11 13 12 - #include "ntoskrnl.h" 14 + #include <ntoskrnl.h> 15 + 13 16 #define NDEBUG 14 - #include "debug.h" 17 + #include <debug.h> 15 18 16 - /* GLOBALS ********************************************************************/ 19 + #ifdef _BLDR_ 20 + 21 + #undef CODE_SEG 22 + #define CODE_SEG(...) 17 23 18 - extern ULONG InitSafeBootMode; 24 + #include <ntstrsafe.h> 25 + #include <cmlib.h> 26 + #include "internal/cmboot.h" 27 + 28 + // HACK: This is part of non-NT-compatible SafeBoot support in kernel. 29 + ULONG InitSafeBootMode = 0; 30 + 31 + DBG_DEFAULT_CHANNEL(REGISTRY); 32 + #define CMTRACE(x, fmt, ...) TRACE(fmt, ##__VA_ARGS__) // DPRINT 33 + 34 + #endif /* _BLDR_ */ 35 + 36 + 37 + /* DEFINES ********************************************************************/ 38 + 39 + #define CM_BOOT_DEBUG 0x20 40 + 41 + #define IS_NULL_TERMINATED(Buffer, Size) \ 42 + (((Size) >= sizeof(WCHAR)) && ((Buffer)[(Size) / sizeof(WCHAR) - 1] == UNICODE_NULL)) 43 + 19 44 20 45 /* FUNCTIONS ******************************************************************/ 21 46 47 + // HACK: This is part of non-NT-compatible SafeBoot support in kernel. 48 + extern ULONG InitSafeBootMode; 49 + 50 + CODE_SEG("INIT") 51 + static 52 + BOOLEAN 53 + CmpIsSafe( 54 + _In_ PHHIVE Hive, 55 + _In_ HCELL_INDEX SafeBootCell, 56 + _In_ HCELL_INDEX DriverCell); 57 + 58 + /** 59 + * @brief 60 + * Finds the corresponding "HKLM\SYSTEM\ControlSetXXX" system control set 61 + * registry key, according to the "Current", "Default", or "LastKnownGood" 62 + * values in the "HKLM\SYSTEM\Select" registry key. 63 + * 64 + * @param[in] SystemHive 65 + * The SYSTEM hive. 66 + * 67 + * @param[in] RootCell 68 + * The root cell of the SYSTEM hive. 69 + * 70 + * @param[in] SelectKeyName 71 + * The control set to check for: either "Current", "Default", or 72 + * "LastKnownGood", the value of which selects the corresponding 73 + * "HKLM\SYSTEM\ControlSetXXX" control set registry key. 74 + * 75 + * @param[out] AutoSelect 76 + * Value of the "AutoSelect" registry value (unused). 77 + * 78 + * @return 79 + * The control set registry key's hive cell (if found), or HCELL_NIL. 80 + **/ 22 81 CODE_SEG("INIT") 23 82 HCELL_INDEX 24 83 NTAPI 25 - CmpFindControlSet(IN PHHIVE SystemHive, 26 - IN HCELL_INDEX RootCell, 27 - IN PUNICODE_STRING SelectKeyName, 28 - OUT PBOOLEAN AutoSelect) 84 + CmpFindControlSet( 85 + _In_ PHHIVE SystemHive, 86 + _In_ HCELL_INDEX RootCell, 87 + _In_ PCUNICODE_STRING SelectKeyName, 88 + _Out_ PBOOLEAN AutoSelect) 29 89 { 30 - UNICODE_STRING KeyName; 90 + UNICODE_STRING Name; 31 91 PCM_KEY_NODE Node; 32 92 HCELL_INDEX SelectCell, AutoSelectCell, SelectValueCell, ControlSetCell; 33 93 HCELL_INDEX CurrentValueCell; 34 - PCM_KEY_VALUE KeyValue; 94 + PCM_KEY_VALUE Value; 35 95 ULONG Length; 36 - PULONG ControlSetId; 37 - ANSI_STRING ControlSetAnsiName; 38 - CHAR Buffer[128]; 39 - WCHAR WideBuffer[128]; 40 96 NTSTATUS Status; 41 97 PULONG CurrentData; 98 + PULONG ControlSetId; 99 + WCHAR Buffer[128]; 42 100 43 - /* Sanity check */ 101 + /* Sanity check: We shouldn't need to release any acquired cells */ 44 102 ASSERT(SystemHive->ReleaseCellRoutine == NULL); 45 103 46 - /* Get the Select subkey */ 47 - RtlInitUnicodeString(&KeyName, L"select"); 104 + /* Get the Select key */ 105 + RtlInitUnicodeString(&Name, L"select"); 48 106 Node = (PCM_KEY_NODE)HvGetCell(SystemHive, RootCell); 49 107 if (!Node) return HCELL_NIL; 50 - SelectCell = CmpFindSubKeyByName(SystemHive, Node, &KeyName); 51 - if (SelectCell == HCELL_NIL) return SelectCell; 108 + SelectCell = CmpFindSubKeyByName(SystemHive, Node, &Name); 109 + if (SelectCell == HCELL_NIL) return HCELL_NIL; 52 110 53 111 /* Get AutoSelect value */ 54 - RtlInitUnicodeString(&KeyName, L"AutoSelect"); 112 + RtlInitUnicodeString(&Name, L"AutoSelect"); 55 113 Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell); 56 114 if (!Node) return HCELL_NIL; 57 - AutoSelectCell = CmpFindValueByName(SystemHive, Node, &KeyName); 115 + AutoSelectCell = CmpFindValueByName(SystemHive, Node, &Name); 58 116 if (AutoSelectCell == HCELL_NIL) 59 117 { 60 - /* Assume TRUE if the value is missing. */ 118 + /* Assume TRUE if the value is missing */ 61 119 *AutoSelect = TRUE; 62 120 } 63 121 else 64 122 { 65 123 /* Read the value */ 66 - KeyValue = (PCM_KEY_VALUE)HvGetCell(SystemHive, AutoSelectCell); 67 - if (KeyValue == NULL) return HCELL_NIL; 124 + Value = (PCM_KEY_VALUE)HvGetCell(SystemHive, AutoSelectCell); 125 + if (!Value) return HCELL_NIL; 126 + // if (Value->Type != REG_DWORD) return HCELL_NIL; 68 127 69 128 /* Convert it to a boolean */ 70 - *AutoSelect = *(PBOOLEAN)CmpValueToData(SystemHive, KeyValue, &Length); 129 + CurrentData = (PULONG)CmpValueToData(SystemHive, Value, &Length); 130 + if (!CurrentData) return HCELL_NIL; 131 + // if (Length < sizeof(ULONG)) return HCELL_NIL; 132 + 133 + *AutoSelect = *(PBOOLEAN)CurrentData; 71 134 } 72 135 73 136 /* Now find the control set being looked up */ 74 137 Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell); 75 138 if (!Node) return HCELL_NIL; 76 139 SelectValueCell = CmpFindValueByName(SystemHive, Node, SelectKeyName); 77 - if (SelectValueCell == HCELL_NIL) return SelectValueCell; 140 + if (SelectValueCell == HCELL_NIL) return HCELL_NIL; 78 141 79 142 /* Read the value (corresponding to the CCS ID) */ 80 - KeyValue = (PCM_KEY_VALUE)HvGetCell(SystemHive, SelectValueCell); 81 - if (!KeyValue) return HCELL_NIL; 82 - if (KeyValue->Type != REG_DWORD) return HCELL_NIL; 83 - ControlSetId = (PULONG)CmpValueToData(SystemHive, KeyValue, &Length); 84 - 85 - /* Now build an Ansi String for the CCS's Name */ 86 - sprintf(Buffer, "ControlSet%03lu", *ControlSetId); 87 - ControlSetAnsiName.Length = (USHORT)strlen(Buffer); 88 - ControlSetAnsiName.MaximumLength = (USHORT)strlen(Buffer); 89 - ControlSetAnsiName.Buffer = Buffer; 143 + Value = (PCM_KEY_VALUE)HvGetCell(SystemHive, SelectValueCell); 144 + if (!Value) return HCELL_NIL; 145 + if (Value->Type != REG_DWORD) return HCELL_NIL; 146 + ControlSetId = (PULONG)CmpValueToData(SystemHive, Value, &Length); 147 + if (!ControlSetId) return HCELL_NIL; 148 + if (Length < sizeof(ULONG)) return HCELL_NIL; 90 149 91 - /* And convert it to Unicode... */ 92 - KeyName.MaximumLength = 256; 93 - KeyName.Buffer = WideBuffer; 94 - Status = RtlAnsiStringToUnicodeString(&KeyName, 95 - &ControlSetAnsiName, 96 - FALSE); 150 + /* Now build the CCS's Name */ 151 + Status = RtlStringCbPrintfW(Buffer, sizeof(Buffer), 152 + L"ControlSet%03lu", *ControlSetId); 97 153 if (!NT_SUCCESS(Status)) return HCELL_NIL; 154 + /* RtlStringCbPrintfW ensures the buffer to be NULL-terminated */ 155 + RtlInitUnicodeString(&Name, Buffer); 98 156 99 157 /* Now open it */ 100 158 Node = (PCM_KEY_NODE)HvGetCell(SystemHive, RootCell); 101 159 if (!Node) return HCELL_NIL; 102 - ControlSetCell = CmpFindSubKeyByName(SystemHive, Node, &KeyName); 103 - if (ControlSetCell == HCELL_NIL) return ControlSetCell; 160 + ControlSetCell = CmpFindSubKeyByName(SystemHive, Node, &Name); 161 + if (ControlSetCell == HCELL_NIL) return HCELL_NIL; 104 162 105 163 /* Get the value of the "Current" CCS */ 106 - RtlInitUnicodeString(&KeyName, L"Current"); 164 + RtlInitUnicodeString(&Name, L"Current"); 107 165 Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell); 108 166 if (!Node) return HCELL_NIL; 109 - CurrentValueCell = CmpFindValueByName(SystemHive, Node, &KeyName); 167 + CurrentValueCell = CmpFindValueByName(SystemHive, Node, &Name); 110 168 111 169 /* Make sure it exists */ 112 170 if (CurrentValueCell != HCELL_NIL) 113 171 { 114 - /* Get the current value and make sure its a ULONG */ 115 - KeyValue = (PCM_KEY_VALUE)HvGetCell(SystemHive, CurrentValueCell); 116 - if (!KeyValue) return HCELL_NIL; 117 - if (KeyValue->Type == REG_DWORD) 172 + /* Get the current value and make sure it's a ULONG */ 173 + Value = (PCM_KEY_VALUE)HvGetCell(SystemHive, CurrentValueCell); 174 + if (!Value) return HCELL_NIL; 175 + if (Value->Type == REG_DWORD) 118 176 { 119 177 /* Get the data and update it */ 120 - CurrentData = (PULONG)CmpValueToData(SystemHive, 121 - KeyValue, 122 - &Length); 178 + CurrentData = (PULONG)CmpValueToData(SystemHive, Value, &Length); 123 179 if (!CurrentData) return HCELL_NIL; 180 + if (Length < sizeof(ULONG)) return HCELL_NIL; 181 + 124 182 *CurrentData = *ControlSetId; 125 183 } 126 184 } 127 185 128 - /* Return the CCS Cell */ 186 + /* Return the CCS cell */ 129 187 return ControlSetCell; 130 188 } 131 189 190 + /** 191 + * @brief 192 + * Finds the index of the driver's "Tag" value 193 + * in its corresponding group ordering list. 194 + * 195 + * @param[in] Hive 196 + * The SYSTEM hive. 197 + * 198 + * @param[in] TagCell 199 + * The driver's "Tag" registry value's hive cell. 200 + * 201 + * @param[in] GroupOrderCell 202 + * The hive cell of the "Control\GroupOrderList" registry key 203 + * inside the currently selected control set. 204 + * 205 + * @param[in] GroupName 206 + * The driver's group name. 207 + * 208 + * @return 209 + * The corresponding tag index, or -1 (last position), 210 + * or -2 (next-to-last position). 211 + **/ 132 212 CODE_SEG("INIT") 213 + static 133 214 ULONG 134 - NTAPI 135 - CmpFindTagIndex(IN PHHIVE Hive, 136 - IN HCELL_INDEX TagCell, 137 - IN HCELL_INDEX GroupOrderCell, 138 - IN PUNICODE_STRING GroupName) 215 + CmpFindTagIndex( 216 + _In_ PHHIVE Hive, 217 + _In_ HCELL_INDEX TagCell, 218 + _In_ HCELL_INDEX GroupOrderCell, 219 + _In_ PCUNICODE_STRING GroupName) 139 220 { 140 221 PCM_KEY_VALUE TagValue, Value; 222 + PCM_KEY_NODE Node; 141 223 HCELL_INDEX OrderCell; 142 - PULONG TagOrder, DriverTag; 224 + PULONG DriverTag, TagOrder; 143 225 ULONG CurrentTag, Length; 144 - PCM_KEY_NODE Node; 145 226 BOOLEAN BufferAllocated; 227 + 228 + /* Sanity check: We shouldn't need to release any acquired cells */ 146 229 ASSERT(Hive->ReleaseCellRoutine == NULL); 147 230 148 231 /* Get the tag */ 149 232 Value = (PCM_KEY_VALUE)HvGetCell(Hive, TagCell); 150 - ASSERT(Value); 233 + if (!Value) return -2; 234 + if (Value->Type != REG_DWORD) return -2; 151 235 DriverTag = (PULONG)CmpValueToData(Hive, Value, &Length); 152 - ASSERT(DriverTag); 236 + if (!DriverTag) return -2; 237 + if (Length < sizeof(ULONG)) return -2; 153 238 154 239 /* Get the order array */ 155 240 Node = (PCM_KEY_NODE)HvGetCell(Hive, GroupOrderCell); 156 - ASSERT(Node); 241 + if (!Node) return -2; 157 242 OrderCell = CmpFindValueByName(Hive, Node, GroupName); 158 243 if (OrderCell == HCELL_NIL) return -2; 159 244 160 245 /* And read it */ 161 246 TagValue = (PCM_KEY_VALUE)HvGetCell(Hive, OrderCell); 162 - CmpGetValueData(Hive, TagValue, &Length, (PVOID*)&TagOrder, &BufferAllocated, &OrderCell); 163 - ASSERT(TagOrder); 247 + if (!TagValue) return -2; 248 + if (!CmpGetValueData(Hive, 249 + TagValue, 250 + &Length, 251 + (PVOID*)&TagOrder, 252 + &BufferAllocated, 253 + &OrderCell) 254 + || !TagOrder) 255 + { 256 + return -2; 257 + } 164 258 165 259 /* Parse each tag */ 166 260 for (CurrentTag = 1; CurrentTag <= TagOrder[0]; CurrentTag++) ··· 169 263 if (TagOrder[CurrentTag] == *DriverTag) 170 264 { 171 265 /* Found it -- return the tag */ 172 - if (BufferAllocated) ExFreePool(TagOrder); 266 + if (BufferAllocated) Hive->Free(TagOrder, Length); 173 267 return CurrentTag; 174 268 } 175 269 } 176 270 177 271 /* No matches, so assume next to last ordering */ 178 - if (BufferAllocated) ExFreePool(TagOrder); 272 + if (BufferAllocated) Hive->Free(TagOrder, Length); 179 273 return -2; 180 274 } 181 275 276 + #ifdef _BLDR_ 277 + 278 + /** 279 + * @brief 280 + * Checks whether the specified named driver is already in the driver list. 281 + * Optionally returns its corresponding driver node. 282 + * 283 + * @remarks Used in bootloader only. 284 + * 285 + * @param[in] DriverListHead 286 + * The driver list. 287 + * 288 + * @param[in] DriverName 289 + * The name of the driver to search for. 290 + * 291 + * @param[out] FoundDriver 292 + * Optional pointer that receives in output the address of the 293 + * matching driver node, if any, or NULL if none has been found. 294 + * 295 + * @return 296 + * TRUE if the driver has been found, FALSE if not. 297 + **/ 182 298 CODE_SEG("INIT") 183 299 BOOLEAN 184 300 NTAPI 185 - CmpAddDriverToList(IN PHHIVE Hive, 186 - IN HCELL_INDEX DriverCell, 187 - IN HCELL_INDEX GroupOrderCell, 188 - IN PUNICODE_STRING RegistryPath, 189 - IN PLIST_ENTRY BootDriverListHead) 301 + CmpIsDriverInList( 302 + _In_ PLIST_ENTRY DriverListHead, 303 + _In_ PCUNICODE_STRING DriverName, 304 + _Out_opt_ PBOOT_DRIVER_NODE* FoundDriver) 305 + { 306 + PLIST_ENTRY Entry; 307 + PBOOT_DRIVER_NODE DriverNode; 308 + 309 + for (Entry = DriverListHead->Flink; 310 + Entry != DriverListHead; 311 + Entry = Entry->Flink) 312 + { 313 + DriverNode = CONTAINING_RECORD(Entry, 314 + BOOT_DRIVER_NODE, 315 + ListEntry.Link); 316 + 317 + if (RtlEqualUnicodeString(&DriverNode->Name, 318 + DriverName, 319 + TRUE)) 320 + { 321 + /* The driver node has been found */ 322 + if (FoundDriver) 323 + *FoundDriver = DriverNode; 324 + return TRUE; 325 + } 326 + } 327 + 328 + /* None has been found */ 329 + if (FoundDriver) 330 + *FoundDriver = NULL; 331 + return FALSE; 332 + } 333 + 334 + #endif /* _BLDR_ */ 335 + 336 + /** 337 + * @brief 338 + * Inserts the specified driver entry into the driver list. 339 + * 340 + * @param[in] Hive 341 + * The SYSTEM hive. 342 + * 343 + * @param[in] DriverCell 344 + * The registry key's hive cell of the driver to be added, inside 345 + * the "Services" sub-key of the currently selected control set. 346 + * 347 + * @param[in] GroupOrderCell 348 + * The hive cell of the "Control\GroupOrderList" registry key 349 + * inside the currently selected control set. 350 + * 351 + * @param[in] RegistryPath 352 + * Constant UNICODE_STRING pointing to 353 + * "\\Registry\\Machine\\System\\CurrentControlSet\\Services\\". 354 + * 355 + * @param[in,out] DriverListHead 356 + * The driver list where to insert the driver entry. 357 + * 358 + * @return 359 + * TRUE if the driver has been inserted into the list, FALSE if not. 360 + **/ 361 + CODE_SEG("INIT") 362 + BOOLEAN 363 + NTAPI 364 + CmpAddDriverToList( 365 + _In_ PHHIVE Hive, 366 + _In_ HCELL_INDEX DriverCell, 367 + _In_ HCELL_INDEX GroupOrderCell, 368 + _In_ PCUNICODE_STRING RegistryPath, 369 + _Inout_ PLIST_ENTRY DriverListHead) 190 370 { 191 371 PBOOT_DRIVER_NODE DriverNode; 192 372 PBOOT_DRIVER_LIST_ENTRY DriverEntry; 193 373 PCM_KEY_NODE Node; 374 + PCM_KEY_VALUE Value; 194 375 ULONG Length; 195 376 USHORT NameLength; 196 - HCELL_INDEX ValueCell, TagCell; PCM_KEY_VALUE Value; 197 - PUNICODE_STRING FileName, RegistryString; 198 - UNICODE_STRING UnicodeString; 377 + HCELL_INDEX ValueCell, TagCell; 378 + PUNICODE_STRING FilePath, RegistryString; 379 + UNICODE_STRING Name; 199 380 PULONG ErrorControl; 200 381 PWCHAR Buffer; 382 + 383 + /* Sanity check: We shouldn't need to release any acquired cells */ 201 384 ASSERT(Hive->ReleaseCellRoutine == NULL); 202 385 203 386 /* Allocate a driver node and initialize it */ 204 - DriverNode = CmpAllocate(sizeof(BOOT_DRIVER_NODE), FALSE, TAG_CM); 205 - if (!DriverNode) return FALSE; 387 + DriverNode = Hive->Allocate(sizeof(BOOT_DRIVER_NODE), FALSE, TAG_CM); 388 + if (!DriverNode) 389 + return FALSE; 390 + 391 + RtlZeroMemory(DriverNode, sizeof(BOOT_DRIVER_NODE)); 206 392 DriverEntry = &DriverNode->ListEntry; 207 - DriverEntry->RegistryPath.Buffer = NULL; 208 - DriverEntry->FilePath.Buffer = NULL; 209 393 210 394 /* Get the driver cell */ 211 395 Node = (PCM_KEY_NODE)HvGetCell(Hive, DriverCell); 212 - ASSERT(Node); 396 + if (!Node) 397 + goto Failure; 213 398 214 399 /* Get the name from the cell */ 215 - DriverNode->Name.Length = Node->Flags & KEY_COMP_NAME ? 216 - CmpCompressedNameSize(Node->Name, Node->NameLength) : 217 - Node->NameLength; 218 - DriverNode->Name.MaximumLength = DriverNode->Name.Length; 219 - NameLength = DriverNode->Name.Length; 400 + NameLength = (Node->Flags & KEY_COMP_NAME) ? 401 + CmpCompressedNameSize(Node->Name, Node->NameLength) : 402 + Node->NameLength; 403 + if (NameLength < sizeof(WCHAR)) 404 + goto Failure; 220 405 221 406 /* Now allocate the buffer for it and copy the name */ 222 - DriverNode->Name.Buffer = CmpAllocate(NameLength, FALSE, TAG_CM); 223 - if (!DriverNode->Name.Buffer) return FALSE; 407 + RtlInitEmptyUnicodeString(&DriverNode->Name, 408 + Hive->Allocate(NameLength, FALSE, TAG_CM), 409 + NameLength); 410 + if (!DriverNode->Name.Buffer) 411 + goto Failure; 412 + 413 + DriverNode->Name.Length = NameLength; 224 414 if (Node->Flags & KEY_COMP_NAME) 225 415 { 226 416 /* Compressed name */ ··· 236 426 } 237 427 238 428 /* Now find the image path */ 239 - RtlInitUnicodeString(&UnicodeString, L"ImagePath"); 240 - ValueCell = CmpFindValueByName(Hive, Node, &UnicodeString); 429 + RtlInitUnicodeString(&Name, L"ImagePath"); 430 + ValueCell = CmpFindValueByName(Hive, Node, &Name); 241 431 if (ValueCell == HCELL_NIL) 242 432 { 243 - /* Couldn't find it, so assume the drivers path */ 433 + /* Could not find it, so assume the drivers path */ 244 434 Length = sizeof(L"System32\\Drivers\\") + NameLength + sizeof(L".sys"); 245 435 246 436 /* Allocate the path name */ 247 - FileName = &DriverEntry->FilePath; 248 - FileName->Length = 0; 249 - FileName->MaximumLength = (USHORT)Length; 250 - FileName->Buffer = CmpAllocate(Length, FALSE,TAG_CM); 251 - if (!FileName->Buffer) return FALSE; 437 + FilePath = &DriverEntry->FilePath; 438 + RtlInitEmptyUnicodeString(FilePath, 439 + Hive->Allocate(Length, FALSE, TAG_CM), 440 + (USHORT)Length); 441 + if (!FilePath->Buffer) 442 + goto Failure; 252 443 253 444 /* Write the path name */ 254 - RtlAppendUnicodeToString(FileName, L"System32\\Drivers\\"); 255 - RtlAppendUnicodeStringToString(FileName, &DriverNode->Name); 256 - RtlAppendUnicodeToString(FileName, L".sys"); 445 + if (!NT_SUCCESS(RtlAppendUnicodeToString(FilePath, L"System32\\Drivers\\")) || 446 + !NT_SUCCESS(RtlAppendUnicodeStringToString(FilePath, &DriverNode->Name)) || 447 + !NT_SUCCESS(RtlAppendUnicodeToString(FilePath, L".sys"))) 448 + { 449 + goto Failure; 450 + } 257 451 } 258 452 else 259 453 { 260 454 /* Path name exists, so grab it */ 261 455 Value = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell); 262 - ASSERT(Value); 456 + if (!Value) 457 + goto Failure; 458 + if ((Value->Type != REG_SZ) && (Value->Type != REG_EXPAND_SZ)) 459 + goto Failure; 460 + Buffer = (PWCHAR)CmpValueToData(Hive, Value, &Length); 461 + if (!Buffer) 462 + goto Failure; 463 + if (IS_NULL_TERMINATED(Buffer, Length)) 464 + Length -= sizeof(UNICODE_NULL); 465 + if (Length < sizeof(WCHAR)) 466 + goto Failure; 263 467 264 468 /* Allocate and setup the path name */ 265 - FileName = &DriverEntry->FilePath; 266 - Buffer = (PWCHAR)CmpValueToData(Hive, Value, &Length); 267 - FileName->MaximumLength = FileName->Length = (USHORT)Length; 268 - FileName->Buffer = CmpAllocate(Length, FALSE, TAG_CM); 469 + FilePath = &DriverEntry->FilePath; 470 + RtlInitEmptyUnicodeString(FilePath, 471 + Hive->Allocate(Length, FALSE, TAG_CM), 472 + (USHORT)Length); 473 + if (!FilePath->Buffer) 474 + goto Failure; 269 475 270 476 /* Transfer the data */ 271 - if (!(FileName->Buffer) || !(Buffer)) return FALSE; 272 - RtlCopyMemory(FileName->Buffer, Buffer, Length); 477 + RtlCopyMemory(FilePath->Buffer, Buffer, Length); 478 + FilePath->Length = (USHORT)Length; 273 479 } 274 480 275 481 /* Now build the registry path */ 276 482 RegistryString = &DriverEntry->RegistryPath; 277 - RegistryString->Length = 0; 278 - RegistryString->MaximumLength = RegistryPath->Length + NameLength; 279 - RegistryString->Buffer = CmpAllocate(RegistryString->MaximumLength, FALSE, TAG_CM); 280 - if (!RegistryString->Buffer) return FALSE; 483 + Length = RegistryPath->Length + NameLength; 484 + RtlInitEmptyUnicodeString(RegistryString, 485 + Hive->Allocate(Length, FALSE, TAG_CM), 486 + (USHORT)Length); 487 + if (!RegistryString->Buffer) 488 + goto Failure; 281 489 282 490 /* Add the driver name to it */ 283 - RtlAppendUnicodeStringToString(RegistryString, RegistryPath); 284 - RtlAppendUnicodeStringToString(RegistryString, &DriverNode->Name); 491 + if (!NT_SUCCESS(RtlAppendUnicodeStringToString(RegistryString, RegistryPath)) || 492 + !NT_SUCCESS(RtlAppendUnicodeStringToString(RegistryString, &DriverNode->Name))) 493 + { 494 + goto Failure; 495 + } 285 496 286 497 /* The entry is done, add it */ 287 - InsertHeadList(BootDriverListHead, &DriverEntry->Link); 498 + InsertHeadList(DriverListHead, &DriverEntry->Link); 288 499 289 500 /* Now find error control settings */ 290 - RtlInitUnicodeString(&UnicodeString, L"ErrorControl"); 291 - ValueCell = CmpFindValueByName(Hive, Node, &UnicodeString); 501 + RtlInitUnicodeString(&Name, L"ErrorControl"); 502 + ValueCell = CmpFindValueByName(Hive, Node, &Name); 292 503 if (ValueCell == HCELL_NIL) 293 504 { 294 - /* Couldn't find it, so assume default */ 505 + /* Could not find it, so assume default */ 295 506 DriverNode->ErrorControl = NormalError; 296 507 } 297 508 else 298 509 { 299 510 /* Otherwise, read whatever the data says */ 300 511 Value = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell); 301 - ASSERT(Value); 512 + if (!Value) 513 + goto Failure; 514 + if (Value->Type != REG_DWORD) 515 + goto Failure; 302 516 ErrorControl = (PULONG)CmpValueToData(Hive, Value, &Length); 303 - ASSERT(ErrorControl); 517 + if (!ErrorControl) 518 + goto Failure; 519 + if (Length < sizeof(ULONG)) 520 + goto Failure; 521 + 304 522 DriverNode->ErrorControl = *ErrorControl; 305 523 } 306 524 307 525 /* Next, get the group cell */ 308 - RtlInitUnicodeString(&UnicodeString, L"group"); 309 - ValueCell = CmpFindValueByName(Hive, Node, &UnicodeString); 526 + RtlInitUnicodeString(&Name, L"group"); 527 + ValueCell = CmpFindValueByName(Hive, Node, &Name); 310 528 if (ValueCell == HCELL_NIL) 311 529 { 312 - /* Couldn't find, so set an empty string */ 530 + /* Could not find it, so set an empty string */ 313 531 RtlInitEmptyUnicodeString(&DriverNode->Group, NULL, 0); 314 532 } 315 533 else 316 534 { 317 535 /* Found it, read the group value */ 318 536 Value = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell); 319 - ASSERT(Value); 537 + if (!Value) 538 + goto Failure; 539 + if (Value->Type != REG_SZ) // REG_EXPAND_SZ not really allowed there. 540 + goto Failure; 320 541 321 542 /* Copy it into the node */ 322 - DriverNode->Group.Buffer = (PWCHAR)CmpValueToData(Hive, Value, &Length); 323 - if (!DriverNode->Group.Buffer) return FALSE; 324 - DriverNode->Group.Length = (USHORT)Length - sizeof(UNICODE_NULL); 543 + Buffer = (PWCHAR)CmpValueToData(Hive, Value, &Length); 544 + if (!Buffer) 545 + goto Failure; 546 + if (IS_NULL_TERMINATED(Buffer, Length)) 547 + Length -= sizeof(UNICODE_NULL); 548 + 549 + DriverNode->Group.Buffer = Buffer; 550 + DriverNode->Group.Length = (USHORT)Length; 325 551 DriverNode->Group.MaximumLength = DriverNode->Group.Length; 326 552 } 327 553 328 554 /* Finally, find the tag */ 329 - RtlInitUnicodeString(&UnicodeString, L"Tag"); 330 - TagCell = CmpFindValueByName(Hive, Node, &UnicodeString); 555 + RtlInitUnicodeString(&Name, L"Tag"); 556 + TagCell = CmpFindValueByName(Hive, Node, &Name); 331 557 if (TagCell == HCELL_NIL) 332 558 { 333 559 /* No tag, so load last */ ··· 342 568 &DriverNode->Group); 343 569 } 344 570 571 + CMTRACE(CM_BOOT_DEBUG, "Adding boot driver: '%wZ', '%wZ'\n", 572 + &DriverNode->Name, &DriverEntry->FilePath); 573 + 345 574 /* All done! */ 346 575 return TRUE; 576 + 577 + Failure: 578 + if (DriverEntry->RegistryPath.Buffer) 579 + { 580 + Hive->Free(DriverEntry->RegistryPath.Buffer, 581 + DriverEntry->RegistryPath.MaximumLength); 582 + } 583 + if (DriverEntry->FilePath.Buffer) 584 + { 585 + Hive->Free(DriverEntry->FilePath.Buffer, 586 + DriverEntry->FilePath.MaximumLength); 587 + } 588 + if (DriverNode->Name.Buffer) 589 + { 590 + Hive->Free(DriverNode->Name.Buffer, 591 + DriverNode->Name.MaximumLength); 592 + } 593 + Hive->Free(DriverNode, sizeof(BOOT_DRIVER_NODE)); 594 + 595 + return FALSE; 347 596 } 348 597 598 + /** 599 + * @brief 600 + * Checks whether the specified driver has the expected load type. 601 + * 602 + * @param[in] Hive 603 + * The SYSTEM hive. 604 + * 605 + * @param[in] DriverCell 606 + * The registry key's hive cell of the driver, inside the 607 + * "Services" sub-key of the currently selected control set. 608 + * 609 + * @param[in] LoadType 610 + * The load type the driver should match. 611 + * 612 + * @return 613 + * TRUE if the driver's load type matches, FALSE if not. 614 + **/ 349 615 CODE_SEG("INIT") 616 + static 350 617 BOOLEAN 351 - NTAPI 352 - CmpIsLoadType(IN PHHIVE Hive, 353 - IN HCELL_INDEX Cell, 354 - IN SERVICE_LOAD_TYPE LoadType) 618 + CmpIsLoadType( 619 + _In_ PHHIVE Hive, 620 + _In_ HCELL_INDEX Cell, 621 + _In_ SERVICE_LOAD_TYPE LoadType) 355 622 { 356 623 PCM_KEY_NODE Node; 624 + PCM_KEY_VALUE Value; 625 + UNICODE_STRING Name = RTL_CONSTANT_STRING(L"Start"); 357 626 HCELL_INDEX ValueCell; 358 - UNICODE_STRING ValueString = RTL_CONSTANT_STRING(L"Start"); 359 - PCM_KEY_VALUE Value; 360 627 ULONG Length; 361 - PLONG Data; 628 + PULONG Data; 629 + 630 + /* Sanity check: We shouldn't need to release any acquired cells */ 362 631 ASSERT(Hive->ReleaseCellRoutine == NULL); 363 632 364 633 /* Open the start cell */ 365 634 Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell); 366 - ASSERT(Node); 367 - ValueCell = CmpFindValueByName(Hive, Node, &ValueString); 635 + if (!Node) return FALSE; 636 + ValueCell = CmpFindValueByName(Hive, Node, &Name); 368 637 if (ValueCell == HCELL_NIL) return FALSE; 369 638 370 639 /* Read the start value */ 371 640 Value = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell); 372 - ASSERT(Value); 373 - Data = (PLONG)CmpValueToData(Hive, Value, &Length); 374 - ASSERT(Data); 641 + if (!Value) return FALSE; 642 + if (Value->Type != REG_DWORD) return FALSE; 643 + Data = (PULONG)CmpValueToData(Hive, Value, &Length); 644 + if (!Data) return FALSE; 645 + if (Length < sizeof(ULONG)) return FALSE; 375 646 376 647 /* Return if the type matches */ 377 648 return (*Data == LoadType); 378 649 } 379 650 651 + /** 652 + * @brief 653 + * Enumerates all drivers within the given control set and load type, 654 + * present in the "Services" sub-key, and inserts them into the driver list. 655 + * 656 + * @param[in] Hive 657 + * The SYSTEM hive. 658 + * 659 + * @param[in] ControlSet 660 + * The control set registry key's hive cell. 661 + * 662 + * @param[in] LoadType 663 + * The load type the driver should match. 664 + * 665 + * @param[in] BootFileSystem 666 + * Optional name of the boot file system, for which to insert 667 + * its corresponding driver. 668 + * 669 + * @param[in,out] DriverListHead 670 + * The driver list where to insert the enumerated drivers. 671 + * 672 + * @return 673 + * TRUE if the drivers have been successfully enumerated and inserted, 674 + * FALSE if not. 675 + **/ 380 676 CODE_SEG("INIT") 381 677 BOOLEAN 382 678 NTAPI 383 - CmpFindDrivers(IN PHHIVE Hive, 384 - IN HCELL_INDEX ControlSet, 385 - IN SERVICE_LOAD_TYPE LoadType, 386 - IN PWCHAR BootFileSystem OPTIONAL, 387 - IN PLIST_ENTRY DriverListHead) 679 + CmpFindDrivers( 680 + _In_ PHHIVE Hive, 681 + _In_ HCELL_INDEX ControlSet, 682 + _In_ SERVICE_LOAD_TYPE LoadType, 683 + _In_opt_ PCWSTR BootFileSystem, 684 + _Inout_ PLIST_ENTRY DriverListHead) 388 685 { 389 686 HCELL_INDEX ServicesCell, ControlCell, GroupOrderCell, DriverCell; 390 687 HCELL_INDEX SafeBootCell = HCELL_NIL; 391 - UNICODE_STRING Name; 392 688 ULONG i; 393 - WCHAR Buffer[128]; 394 - UNICODE_STRING UnicodeString, KeyPath; 689 + UNICODE_STRING Name; 690 + UNICODE_STRING KeyPath; 691 + PCM_KEY_NODE ControlNode, ServicesNode, Node; 395 692 PBOOT_DRIVER_NODE FsNode; 396 - PCM_KEY_NODE ControlNode, ServicesNode, Node; 693 + 694 + /* Sanity check: We shouldn't need to release any acquired cells */ 397 695 ASSERT(Hive->ReleaseCellRoutine == NULL); 398 696 399 697 /* Open the control set key */ 400 698 ControlNode = (PCM_KEY_NODE)HvGetCell(Hive, ControlSet); 401 - ASSERT(ControlNode); 699 + if (!ControlNode) return FALSE; 402 700 403 701 /* Get services cell */ 404 702 RtlInitUnicodeString(&Name, L"Services"); ··· 407 705 408 706 /* Open services key */ 409 707 ServicesNode = (PCM_KEY_NODE)HvGetCell(Hive, ServicesCell); 410 - ASSERT(ServicesNode); 708 + if (!ServicesNode) return FALSE; 411 709 412 710 /* Get control cell */ 413 711 RtlInitUnicodeString(&Name, L"Control"); ··· 415 713 if (ControlCell == HCELL_NIL) return FALSE; 416 714 417 715 /* Get the group order cell and read it */ 418 - RtlInitUnicodeString(&Name, L"GroupOrderList"); 419 716 Node = (PCM_KEY_NODE)HvGetCell(Hive, ControlCell); 420 - ASSERT(Node); 717 + if (!Node) return FALSE; 718 + RtlInitUnicodeString(&Name, L"GroupOrderList"); 421 719 GroupOrderCell = CmpFindSubKeyByName(Hive, Node, &Name); 422 720 if (GroupOrderCell == HCELL_NIL) return FALSE; 423 721 424 722 /* Get Safe Boot cell */ 425 - if(InitSafeBootMode) 723 + if (InitSafeBootMode) 426 724 { 427 725 /* Open the Safe Boot key */ 428 726 RtlInitUnicodeString(&Name, L"SafeBoot"); 429 727 Node = (PCM_KEY_NODE)HvGetCell(Hive, ControlCell); 430 - ASSERT(Node); 728 + if (!Node) return FALSE; 431 729 SafeBootCell = CmpFindSubKeyByName(Hive, Node, &Name); 432 730 if (SafeBootCell == HCELL_NIL) return FALSE; 433 731 434 732 /* Open the correct start key (depending on the mode) */ 435 733 Node = (PCM_KEY_NODE)HvGetCell(Hive, SafeBootCell); 436 - ASSERT(Node); 437 - switch(InitSafeBootMode) 734 + if (!Node) return FALSE; 735 + switch (InitSafeBootMode) 438 736 { 439 737 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */ 440 738 case 1: ··· 443 741 default: return FALSE; 444 742 } 445 743 SafeBootCell = CmpFindSubKeyByName(Hive, Node, &Name); 446 - if(SafeBootCell == HCELL_NIL) return FALSE; 744 + if (SafeBootCell == HCELL_NIL) return FALSE; 447 745 } 448 746 449 747 /* Build the root registry path */ 450 - RtlInitEmptyUnicodeString(&KeyPath, Buffer, sizeof(Buffer)); 451 - RtlAppendUnicodeToString(&KeyPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); 748 + RtlInitUnicodeString(&KeyPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); 452 749 453 - /* Find the first subkey (ie: the first driver or service) */ 750 + /* Enumerate each sub-key */ 454 751 i = 0; 455 752 DriverCell = CmpFindSubKeyByNumber(Hive, ServicesNode, i); 456 753 while (DriverCell != HCELL_NIL) ··· 460 757 CmpIsSafe(Hive, SafeBootCell, DriverCell)) 461 758 { 462 759 /* Add it to the list */ 463 - CmpAddDriverToList(Hive, 464 - DriverCell, 465 - GroupOrderCell, 466 - &KeyPath, 467 - DriverListHead); 468 - 760 + if (!CmpAddDriverToList(Hive, 761 + DriverCell, 762 + GroupOrderCell, 763 + &KeyPath, 764 + DriverListHead)) 765 + { 766 + CMTRACE(CM_BOOT_DEBUG, " Failed to add boot driver\n"); 767 + } 469 768 } 470 769 471 - /* Try the next subkey */ 770 + /* Go to the next sub-key */ 472 771 DriverCell = CmpFindSubKeyByNumber(Hive, ServicesNode, ++i); 473 772 } 474 773 ··· 476 775 if (BootFileSystem) 477 776 { 478 777 /* Find it */ 479 - RtlInitUnicodeString(&UnicodeString, BootFileSystem); 480 - DriverCell = CmpFindSubKeyByName(Hive, ServicesNode, &UnicodeString); 778 + RtlInitUnicodeString(&Name, BootFileSystem); 779 + DriverCell = CmpFindSubKeyByName(Hive, ServicesNode, &Name); 481 780 if (DriverCell != HCELL_NIL) 482 781 { 483 - /* Always add it to the list */ 484 - CmpAddDriverToList(Hive, 485 - DriverCell, 486 - GroupOrderCell, 487 - &KeyPath, 488 - DriverListHead); 782 + CMTRACE(CM_BOOT_DEBUG, "Adding Boot FileSystem '%S'\n", 783 + BootFileSystem); 489 784 490 - /* Mark it as critical so it always loads */ 491 - FsNode = CONTAINING_RECORD(DriverListHead->Flink, 492 - BOOT_DRIVER_NODE, 493 - ListEntry.Link); 494 - FsNode->ErrorControl = SERVICE_ERROR_CRITICAL; 785 + /* Always add it to the list */ 786 + if (!CmpAddDriverToList(Hive, 787 + DriverCell, 788 + GroupOrderCell, 789 + &KeyPath, 790 + DriverListHead)) 791 + { 792 + CMTRACE(CM_BOOT_DEBUG, " Failed to add boot driver\n"); 793 + } 794 + else 795 + { 796 + /* Mark it as critical so it always loads */ 797 + FsNode = CONTAINING_RECORD(DriverListHead->Flink, 798 + BOOT_DRIVER_NODE, 799 + ListEntry.Link); 800 + FsNode->ErrorControl = SERVICE_ERROR_CRITICAL; 801 + } 495 802 } 496 803 } 497 804 ··· 499 806 return TRUE; 500 807 } 501 808 809 + /** 810 + * @brief 811 + * Performs the driver list sorting, according to the ordering list. 812 + * 813 + * @param[in] Hive 814 + * The SYSTEM hive. 815 + * 816 + * @param[in] ControlSet 817 + * The control set registry key's hive cell. 818 + * 819 + * @param[in,out] DriverListHead 820 + * The driver list to sort. 821 + * 822 + * @return 823 + * TRUE if sorting has been successfully done, FALSE if not. 824 + **/ 502 825 CODE_SEG("INIT") 826 + static 503 827 BOOLEAN 504 - NTAPI 505 - CmpDoSort(IN PLIST_ENTRY DriverListHead, 506 - IN PUNICODE_STRING OrderList) 828 + CmpDoSort( 829 + _Inout_ PLIST_ENTRY DriverListHead, 830 + _In_ PCUNICODE_STRING OrderList) 507 831 { 508 832 PWCHAR Current, End = NULL; 833 + UNICODE_STRING GroupName; 509 834 PLIST_ENTRY NextEntry; 510 - UNICODE_STRING GroupName; 511 835 PBOOT_DRIVER_NODE CurrentNode; 512 836 513 837 /* We're going from end to start, so get to the last group and keep going */ ··· 536 860 ListEntry.Link); 537 861 538 862 /* Get the next entry now since we'll do a relink */ 539 - NextEntry = CurrentNode->ListEntry.Link.Flink; 863 + NextEntry = NextEntry->Flink; 540 864 541 865 /* Is there a group name and does it match the current group? */ 542 - if ((CurrentNode->Group.Buffer) && 543 - (RtlEqualUnicodeString(&GroupName, &CurrentNode->Group, TRUE))) 866 + if (CurrentNode->Group.Buffer && 867 + RtlEqualUnicodeString(&GroupName, &CurrentNode->Group, TRUE)) 544 868 { 545 869 /* Remove from this location and re-link in the new one */ 546 870 RemoveEntryList(&CurrentNode->ListEntry.Link); ··· 549 873 } 550 874 551 875 /* Move on */ 552 - Current--; 876 + --Current; 553 877 } 554 878 555 879 /* All done */ 556 880 return TRUE; 557 881 } 558 882 883 + /** 884 + * @brief 885 + * Sorts the driver list, according to the drivers' group load ordering. 886 + * 887 + * @param[in] Hive 888 + * The SYSTEM hive. 889 + * 890 + * @param[in] ControlSet 891 + * The control set registry key's hive cell. 892 + * 893 + * @param[in,out] DriverListHead 894 + * The driver list to sort. 895 + * 896 + * @return 897 + * TRUE if sorting has been successfully done, FALSE if not. 898 + **/ 559 899 CODE_SEG("INIT") 560 900 BOOLEAN 561 901 NTAPI 562 - CmpSortDriverList(IN PHHIVE Hive, 563 - IN HCELL_INDEX ControlSet, 564 - IN PLIST_ENTRY DriverListHead) 902 + CmpSortDriverList( 903 + _In_ PHHIVE Hive, 904 + _In_ HCELL_INDEX ControlSet, 905 + _Inout_ PLIST_ENTRY DriverListHead) 565 906 { 566 - HCELL_INDEX Controls, GroupOrder, ListCell; 567 - UNICODE_STRING Name, DependList; 568 - PCM_KEY_VALUE ListNode; 569 - ULONG Length; 570 907 PCM_KEY_NODE Node; 908 + PCM_KEY_VALUE ListValue; 909 + HCELL_INDEX ControlCell, GroupOrder, ListCell; 910 + UNICODE_STRING Name, OrderList; 911 + ULONG Length; 912 + 913 + /* Sanity check: We shouldn't need to release any acquired cells */ 571 914 ASSERT(Hive->ReleaseCellRoutine == NULL); 572 915 573 916 /* Open the control key */ 574 917 Node = (PCM_KEY_NODE)HvGetCell(Hive, ControlSet); 575 - ASSERT(Node); 918 + if (!Node) return FALSE; 576 919 RtlInitUnicodeString(&Name, L"Control"); 577 - Controls = CmpFindSubKeyByName(Hive, Node, &Name); 578 - if (Controls == HCELL_NIL) return FALSE; 920 + ControlCell = CmpFindSubKeyByName(Hive, Node, &Name); 921 + if (ControlCell == HCELL_NIL) return FALSE; 579 922 580 923 /* Open the service group order */ 581 - Node = (PCM_KEY_NODE)HvGetCell(Hive, Controls); 582 - ASSERT(Node); 924 + Node = (PCM_KEY_NODE)HvGetCell(Hive, ControlCell); 925 + if (!Node) return FALSE; 583 926 RtlInitUnicodeString(&Name, L"ServiceGroupOrder"); 584 927 GroupOrder = CmpFindSubKeyByName(Hive, Node, &Name); 585 928 if (GroupOrder == HCELL_NIL) return FALSE; 586 929 587 930 /* Open the list key */ 588 931 Node = (PCM_KEY_NODE)HvGetCell(Hive, GroupOrder); 589 - ASSERT(Node); 932 + if (!Node) return FALSE; 590 933 RtlInitUnicodeString(&Name, L"list"); 591 934 ListCell = CmpFindValueByName(Hive, Node, &Name); 592 935 if (ListCell == HCELL_NIL) return FALSE; 593 936 594 - /* Now read the actual list */ 595 - ListNode = (PCM_KEY_VALUE)HvGetCell(Hive, ListCell); 596 - ASSERT(ListNode); 597 - if (ListNode->Type != REG_MULTI_SZ) return FALSE; 937 + /* Read the actual list */ 938 + ListValue = (PCM_KEY_VALUE)HvGetCell(Hive, ListCell); 939 + if (!ListValue) return FALSE; 940 + if (ListValue->Type != REG_MULTI_SZ) return FALSE; 598 941 599 942 /* Copy it into a buffer */ 600 - DependList.Buffer = (PWCHAR)CmpValueToData(Hive, ListNode, &Length); 601 - if (!DependList.Buffer) return FALSE; 602 - DependList.Length = DependList.MaximumLength = (USHORT)Length - sizeof(UNICODE_NULL); 943 + OrderList.Buffer = (PWCHAR)CmpValueToData(Hive, ListValue, &Length); 944 + if (!OrderList.Buffer) return FALSE; 945 + if (!IS_NULL_TERMINATED(OrderList.Buffer, Length)) return FALSE; 946 + OrderList.Length = (USHORT)Length - sizeof(UNICODE_NULL); 947 + OrderList.MaximumLength = OrderList.Length; 603 948 604 - /* And start the recurive sort algorithm */ 605 - return CmpDoSort(DriverListHead, &DependList); 949 + /* And start the sort algorithm */ 950 + return CmpDoSort(DriverListHead, &OrderList); 606 951 } 607 952 608 953 CODE_SEG("INIT") 954 + static 609 955 BOOLEAN 610 - NTAPI 611 - CmpOrderGroup(IN PBOOT_DRIVER_NODE StartNode, 612 - IN PBOOT_DRIVER_NODE EndNode) 956 + CmpOrderGroup( 957 + _In_ PBOOT_DRIVER_NODE StartNode, 958 + _In_ PBOOT_DRIVER_NODE EndNode) 613 959 { 614 960 PBOOT_DRIVER_NODE CurrentNode, PreviousNode; 615 961 PLIST_ENTRY ListEntry; ··· 668 1014 return TRUE; 669 1015 } 670 1016 1017 + /** 1018 + * @brief 1019 + * Removes potential circular dependencies (cycles) and sorts the driver list. 1020 + * 1021 + * @param[in,out] DriverListHead 1022 + * The driver list to sort. 1023 + * 1024 + * @return 1025 + * Always TRUE. 1026 + **/ 671 1027 CODE_SEG("INIT") 672 1028 BOOLEAN 673 1029 NTAPI 674 - CmpResolveDriverDependencies(IN PLIST_ENTRY DriverListHead) 1030 + CmpResolveDriverDependencies( 1031 + _Inout_ PLIST_ENTRY DriverListHead) 675 1032 { 676 1033 PLIST_ENTRY NextEntry; 677 1034 PBOOT_DRIVER_NODE StartNode, EndNode, CurrentNode; ··· 719 1076 } 720 1077 721 1078 CODE_SEG("INIT") 1079 + static 722 1080 BOOLEAN 723 - NTAPI 724 - CmpIsSafe(IN PHHIVE Hive, 725 - IN HCELL_INDEX SafeBootCell, 726 - IN HCELL_INDEX DriverCell) 1081 + CmpIsSafe( 1082 + _In_ PHHIVE Hive, 1083 + _In_ HCELL_INDEX SafeBootCell, 1084 + _In_ HCELL_INDEX DriverCell) 727 1085 { 728 1086 PCM_KEY_NODE SafeBootNode; 729 1087 PCM_KEY_NODE DriverNode; 730 1088 PCM_KEY_VALUE KeyValue; 731 1089 HCELL_INDEX CellIndex; 732 - ULONG Length = 0; 1090 + ULONG Length; 733 1091 UNICODE_STRING Name; 734 - PWCHAR OriginalName; 1092 + PWCHAR Buffer; 1093 + 1094 + /* Sanity check: We shouldn't need to release any acquired cells */ 735 1095 ASSERT(Hive->ReleaseCellRoutine == NULL); 736 1096 737 1097 /* Driver key node (mandatory) */ 738 1098 ASSERT(DriverCell != HCELL_NIL); 739 1099 DriverNode = (PCM_KEY_NODE)HvGetCell(Hive, DriverCell); 740 - ASSERT(DriverNode); 1100 + if (!DriverNode) return FALSE; 741 1101 742 1102 /* Safe boot key node (optional but return TRUE if not present) */ 743 - if(SafeBootCell == HCELL_NIL) return TRUE; 1103 + if (SafeBootCell == HCELL_NIL) return TRUE; 744 1104 SafeBootNode = (PCM_KEY_NODE)HvGetCell(Hive, SafeBootCell); 745 - if(!SafeBootNode) return FALSE; 1105 + if (!SafeBootNode) return FALSE; 746 1106 747 1107 /* Search by the name from the group */ 748 1108 RtlInitUnicodeString(&Name, L"Group"); 749 1109 CellIndex = CmpFindValueByName(Hive, DriverNode, &Name); 750 - if(CellIndex != HCELL_NIL) 1110 + if (CellIndex != HCELL_NIL) 751 1111 { 752 1112 KeyValue = (PCM_KEY_VALUE)HvGetCell(Hive, CellIndex); 753 - ASSERT(KeyValue); 754 - if (KeyValue->Type == REG_SZ || KeyValue->Type == REG_EXPAND_SZ) 1113 + if (!KeyValue) return FALSE; 1114 + 1115 + if (KeyValue->Type == REG_SZ) // REG_EXPAND_SZ not really allowed there. 755 1116 { 756 1117 /* Compose the search 'key' */ 757 - Name.Buffer = (PWCHAR)CmpValueToData(Hive, KeyValue, &Length); 758 - if (!Name.Buffer) return FALSE; 759 - Name.Length = (USHORT)Length - sizeof(UNICODE_NULL); 1118 + Buffer = (PWCHAR)CmpValueToData(Hive, KeyValue, &Length); 1119 + if (!Buffer) 1120 + return FALSE; 1121 + if (IS_NULL_TERMINATED(Buffer, Length)) 1122 + Length -= sizeof(UNICODE_NULL); 1123 + 1124 + Name.Buffer = Buffer; 1125 + Name.Length = (USHORT)Length; 760 1126 Name.MaximumLength = Name.Length; 1127 + 761 1128 /* Search for corresponding key in the Safe Boot key */ 762 1129 CellIndex = CmpFindSubKeyByName(Hive, SafeBootNode, &Name); 763 - if(CellIndex != HCELL_NIL) return TRUE; 1130 + if (CellIndex != HCELL_NIL) return TRUE; 764 1131 } 765 1132 } 766 1133 767 1134 /* Group has not been found - find driver name */ 768 - Name.Length = DriverNode->Flags & KEY_COMP_NAME ? 769 - CmpCompressedNameSize(DriverNode->Name, 770 - DriverNode->NameLength) : 771 - DriverNode->NameLength; 772 - Name.MaximumLength = Name.Length; 1135 + Length = (DriverNode->Flags & KEY_COMP_NAME) ? 1136 + CmpCompressedNameSize(DriverNode->Name, DriverNode->NameLength) : 1137 + DriverNode->NameLength; 1138 + if (Length < sizeof(WCHAR)) 1139 + return FALSE; 1140 + 773 1141 /* Now allocate the buffer for it and copy the name */ 774 - Name.Buffer = CmpAllocate(Name.Length, FALSE, TAG_CM); 775 - if (!Name.Buffer) return FALSE; 1142 + RtlInitEmptyUnicodeString(&Name, 1143 + Hive->Allocate(Length, FALSE, TAG_CM), 1144 + (USHORT)Length); 1145 + if (!Name.Buffer) 1146 + return FALSE; 1147 + 1148 + Name.Length = (USHORT)Length; 776 1149 if (DriverNode->Flags & KEY_COMP_NAME) 777 1150 { 778 1151 /* Compressed name */ ··· 786 1159 /* Normal name */ 787 1160 RtlCopyMemory(Name.Buffer, DriverNode->Name, DriverNode->NameLength); 788 1161 } 1162 + 789 1163 CellIndex = CmpFindSubKeyByName(Hive, SafeBootNode, &Name); 790 - RtlFreeUnicodeString(&Name); 791 - if(CellIndex != HCELL_NIL) return TRUE; 1164 + Hive->Free(Name.Buffer, Name.MaximumLength); 1165 + if (CellIndex != HCELL_NIL) return TRUE; 792 1166 793 1167 /* Not group or driver name - search by image name */ 794 1168 RtlInitUnicodeString(&Name, L"ImagePath"); 795 1169 CellIndex = CmpFindValueByName(Hive, DriverNode, &Name); 796 - if(CellIndex != HCELL_NIL) 1170 + if (CellIndex != HCELL_NIL) 797 1171 { 798 1172 KeyValue = (PCM_KEY_VALUE)HvGetCell(Hive, CellIndex); 799 - ASSERT(KeyValue); 800 - if (KeyValue->Type == REG_SZ || KeyValue->Type == REG_EXPAND_SZ) 1173 + if (!KeyValue) return FALSE; 1174 + 1175 + if ((KeyValue->Type == REG_SZ) || (KeyValue->Type == REG_EXPAND_SZ)) 801 1176 { 802 1177 /* Compose the search 'key' */ 803 - OriginalName = (PWCHAR)CmpValueToData(Hive, KeyValue, &Length); 804 - if (!OriginalName) return FALSE; 1178 + Buffer = (PWCHAR)CmpValueToData(Hive, KeyValue, &Length); 1179 + if (!Buffer) return FALSE; 1180 + if (Length < sizeof(WCHAR)) return FALSE; 1181 + 805 1182 /* Get the base image file name */ 806 - Name.Buffer = wcsrchr(OriginalName, L'\\'); 1183 + // FIXME: wcsrchr() may fail if Buffer is *not* NULL-terminated! 1184 + Name.Buffer = wcsrchr(Buffer, OBJ_NAME_PATH_SEPARATOR); 807 1185 if (!Name.Buffer) return FALSE; 808 1186 ++Name.Buffer; 809 - /* Length of the base name must be >=1 */ 810 - Name.Length = (USHORT)Length - (USHORT)((PUCHAR)Name.Buffer - (PUCHAR)OriginalName) 811 - - sizeof(UNICODE_NULL); 812 - if(Name.Length < 1) return FALSE; 1187 + 1188 + /* Length of the base name must be >=1 WCHAR */ 1189 + if (((ULONG_PTR)Name.Buffer - (ULONG_PTR)Buffer) >= Length) 1190 + return FALSE; 1191 + Length -= ((ULONG_PTR)Name.Buffer - (ULONG_PTR)Buffer); 1192 + if (IS_NULL_TERMINATED(Name.Buffer, Length)) 1193 + Length -= sizeof(UNICODE_NULL); 1194 + if (Length < sizeof(WCHAR)) return FALSE; 1195 + 1196 + Name.Length = (USHORT)Length; 813 1197 Name.MaximumLength = Name.Length; 1198 + 814 1199 /* Search for corresponding key in the Safe Boot key */ 815 1200 CellIndex = CmpFindSubKeyByName(Hive, SafeBootNode, &Name); 816 - if(CellIndex != HCELL_NIL) return TRUE; 1201 + if (CellIndex != HCELL_NIL) return TRUE; 817 1202 } 818 1203 } 1204 + 819 1205 /* Nothing found - nothing else to search */ 820 1206 return FALSE; 1207 + } 1208 + 1209 + /** 1210 + * @brief 1211 + * Empties the driver list and frees all allocated driver nodes in it. 1212 + * 1213 + * @param[in] Hive 1214 + * The SYSTEM hive (used only for the Hive->Free() memory deallocator). 1215 + * 1216 + * @param[in,out] DriverListHead 1217 + * The driver list to free. 1218 + * 1219 + * @return None 1220 + **/ 1221 + CODE_SEG("INIT") 1222 + VOID 1223 + NTAPI 1224 + CmpFreeDriverList( 1225 + _In_ PHHIVE Hive, 1226 + _Inout_ PLIST_ENTRY DriverListHead) 1227 + { 1228 + PLIST_ENTRY Entry; 1229 + PBOOT_DRIVER_NODE DriverNode; 1230 + 1231 + /* Loop through the list and remove each driver node */ 1232 + while (!IsListEmpty(DriverListHead)) 1233 + { 1234 + /* Get the driver node */ 1235 + Entry = RemoveHeadList(DriverListHead); 1236 + DriverNode = CONTAINING_RECORD(Entry, 1237 + BOOT_DRIVER_NODE, 1238 + ListEntry.Link); 1239 + 1240 + /* Free any allocated string buffers, then the node */ 1241 + if (DriverNode->ListEntry.RegistryPath.Buffer) 1242 + { 1243 + Hive->Free(DriverNode->ListEntry.RegistryPath.Buffer, 1244 + DriverNode->ListEntry.RegistryPath.MaximumLength); 1245 + } 1246 + if (DriverNode->ListEntry.FilePath.Buffer) 1247 + { 1248 + Hive->Free(DriverNode->ListEntry.FilePath.Buffer, 1249 + DriverNode->ListEntry.FilePath.MaximumLength); 1250 + } 1251 + if (DriverNode->Name.Buffer) 1252 + { 1253 + Hive->Free(DriverNode->Name.Buffer, 1254 + DriverNode->Name.MaximumLength); 1255 + } 1256 + Hive->Free(DriverNode, sizeof(BOOT_DRIVER_NODE)); 1257 + } 821 1258 } 822 1259 823 1260 /* EOF */
-49
ntoskrnl/config/cmsysini.c
··· 1722 1722 } 1723 1723 1724 1724 CODE_SEG("INIT") 1725 - VOID 1726 - NTAPI 1727 - CmpFreeDriverList(IN PHHIVE Hive, 1728 - IN PLIST_ENTRY DriverList) 1729 - { 1730 - PLIST_ENTRY NextEntry, OldEntry; 1731 - PBOOT_DRIVER_NODE DriverNode; 1732 - PAGED_CODE(); 1733 - 1734 - /* Parse the current list */ 1735 - NextEntry = DriverList->Flink; 1736 - while (NextEntry != DriverList) 1737 - { 1738 - /* Get the driver node */ 1739 - DriverNode = CONTAINING_RECORD(NextEntry, BOOT_DRIVER_NODE, ListEntry.Link); 1740 - 1741 - /* Get the next entry now, since we're going to free it later */ 1742 - OldEntry = NextEntry; 1743 - NextEntry = NextEntry->Flink; 1744 - 1745 - /* Was there a name? */ 1746 - if (DriverNode->Name.Buffer) 1747 - { 1748 - /* Free it */ 1749 - CmpFree(DriverNode->Name.Buffer, DriverNode->Name.Length); 1750 - } 1751 - 1752 - /* Was there a registry path? */ 1753 - if (DriverNode->ListEntry.RegistryPath.Buffer) 1754 - { 1755 - /* Free it */ 1756 - CmpFree(DriverNode->ListEntry.RegistryPath.Buffer, 1757 - DriverNode->ListEntry.RegistryPath.MaximumLength); 1758 - } 1759 - 1760 - /* Was there a file path? */ 1761 - if (DriverNode->ListEntry.FilePath.Buffer) 1762 - { 1763 - /* Free it */ 1764 - CmpFree(DriverNode->ListEntry.FilePath.Buffer, 1765 - DriverNode->ListEntry.FilePath.MaximumLength); 1766 - } 1767 - 1768 - /* Now free the node, and move on */ 1769 - CmpFree(OldEntry, sizeof(BOOT_DRIVER_NODE)); 1770 - } 1771 - } 1772 - 1773 - CODE_SEG("INIT") 1774 1725 PUNICODE_STRING* 1775 1726 NTAPI 1776 1727 CmGetSystemDriverList(VOID)
+5 -47
ntoskrnl/include/internal/cm.h
··· 5 5 * PURPOSE: Internal header for the Configuration Manager 6 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 7 */ 8 - #define _CM_ 9 - #include "cmlib.h" 8 + 9 + #pragma once 10 + 11 + #include <cmlib.h> 10 12 #include <cmreslist.h> 13 + #include "cmboot.h" 11 14 12 15 // 13 16 // Define this if you want debugging support ··· 1169 1172 // Boot Routines 1170 1173 // 1171 1174 CODE_SEG("INIT") 1172 - HCELL_INDEX 1173 - NTAPI 1174 - CmpFindControlSet( 1175 - IN PHHIVE SystemHive, 1176 - IN HCELL_INDEX RootCell, 1177 - IN PUNICODE_STRING SelectKeyName, 1178 - OUT PBOOLEAN AutoSelect 1179 - ); 1180 - 1181 - CODE_SEG("INIT") 1182 1175 VOID 1183 1176 NTAPI 1184 1177 CmGetSystemControlValues( ··· 1452 1445 CmGetSystemDriverList( 1453 1446 VOID 1454 1447 ); 1455 - 1456 - CODE_SEG("INIT") 1457 - BOOLEAN 1458 - NTAPI 1459 - CmpFindDrivers( 1460 - IN PHHIVE Hive, 1461 - IN HCELL_INDEX ControlSet, 1462 - IN SERVICE_LOAD_TYPE LoadType, 1463 - IN PWSTR BootFileSystem OPTIONAL, 1464 - IN PLIST_ENTRY DriverListHead 1465 - ); 1466 - 1467 - CODE_SEG("INIT") 1468 - BOOLEAN 1469 - NTAPI 1470 - CmpSortDriverList( 1471 - IN PHHIVE Hive, 1472 - IN HCELL_INDEX ControlSet, 1473 - IN PLIST_ENTRY DriverListHead 1474 - ); 1475 - 1476 - CODE_SEG("INIT") 1477 - BOOLEAN 1478 - NTAPI 1479 - CmpResolveDriverDependencies( 1480 - IN PLIST_ENTRY DriverListHead 1481 - ); 1482 - 1483 - CODE_SEG("INIT") 1484 - BOOLEAN 1485 - NTAPI 1486 - CmpIsSafe( 1487 - IN PHHIVE Hive, 1488 - IN HCELL_INDEX SafeBootCell, 1489 - IN HCELL_INDEX DriverCell); 1490 1448 1491 1449 // 1492 1450 // Global variables accessible from all of Cm
+80
ntoskrnl/include/internal/cmboot.h
··· 1 + /* 2 + * PROJECT: ReactOS Kernel 3 + * LICENSE: BSD - See COPYING.ARM in the top level directory 4 + * PURPOSE: Configuration Manager - Boot Initialization Internal header 5 + * COPYRIGHT: Copyright 2010 ReactOS Portable Systems Group 6 + * 7 + * NOTE: This module is shared by both the kernel and the bootloader. 8 + */ 9 + 10 + // 11 + // Boot Driver Node 12 + // 13 + typedef struct _BOOT_DRIVER_NODE 14 + { 15 + BOOT_DRIVER_LIST_ENTRY ListEntry; 16 + UNICODE_STRING Group; 17 + UNICODE_STRING Name; 18 + ULONG Tag; 19 + ULONG ErrorControl; 20 + } BOOT_DRIVER_NODE, *PBOOT_DRIVER_NODE; 21 + 22 + 23 + // 24 + // Boot Routines 25 + // 26 + CODE_SEG("INIT") 27 + HCELL_INDEX 28 + NTAPI 29 + CmpFindControlSet( 30 + _In_ PHHIVE SystemHive, 31 + _In_ HCELL_INDEX RootCell, 32 + _In_ PCUNICODE_STRING SelectKeyName, 33 + _Out_ PBOOLEAN AutoSelect); 34 + 35 + 36 + // 37 + // Driver List Routines 38 + // 39 + #ifdef _BLDR_ 40 + 41 + CODE_SEG("INIT") 42 + BOOLEAN 43 + NTAPI 44 + CmpIsDriverInList( 45 + _In_ PLIST_ENTRY DriverListHead, 46 + _In_ PCUNICODE_STRING DriverName, 47 + _Out_opt_ PBOOT_DRIVER_NODE* FoundDriver); 48 + 49 + #endif /* _BLDR_ */ 50 + 51 + CODE_SEG("INIT") 52 + BOOLEAN 53 + NTAPI 54 + CmpFindDrivers( 55 + _In_ PHHIVE Hive, 56 + _In_ HCELL_INDEX ControlSet, 57 + _In_ SERVICE_LOAD_TYPE LoadType, 58 + _In_opt_ PCWSTR BootFileSystem, 59 + _Inout_ PLIST_ENTRY DriverListHead); 60 + 61 + CODE_SEG("INIT") 62 + BOOLEAN 63 + NTAPI 64 + CmpSortDriverList( 65 + _In_ PHHIVE Hive, 66 + _In_ HCELL_INDEX ControlSet, 67 + _Inout_ PLIST_ENTRY DriverListHead); 68 + 69 + CODE_SEG("INIT") 70 + BOOLEAN 71 + NTAPI 72 + CmpResolveDriverDependencies( 73 + _Inout_ PLIST_ENTRY DriverListHead); 74 + 75 + CODE_SEG("INIT") 76 + VOID 77 + NTAPI 78 + CmpFreeDriverList( 79 + _In_ PHHIVE Hive, 80 + _Inout_ PLIST_ENTRY DriverListHead);
+6 -18
ntoskrnl/include/internal/io.h
··· 1 1 /* 2 - * PROJECT: ReactOS Kernel 3 - * LICENSE: GPL - See COPYING in the top level directory 4 - * FILE: ntoskrnl/include/internal/io.h 5 - * PURPOSE: Internal header for the I/O Manager 6 - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 - */ 2 + * PROJECT: ReactOS Kernel 3 + * LICENSE: GPL - See COPYING in the top level directory 4 + * FILE: ntoskrnl/include/internal/io.h 5 + * PURPOSE: Internal header for the I/O Manager 6 + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 + */ 8 8 9 9 #include "ntdddisk.h" 10 10 ··· 409 409 ULONG Processed; 410 410 NTSTATUS Status; 411 411 } DRIVER_INFORMATION, *PDRIVER_INFORMATION; 412 - 413 - // 414 - // Boot Driver Node 415 - // 416 - typedef struct _BOOT_DRIVER_NODE 417 - { 418 - BOOT_DRIVER_LIST_ENTRY ListEntry; 419 - UNICODE_STRING Group; 420 - UNICODE_STRING Name; 421 - ULONG Tag; 422 - ULONG ErrorControl; 423 - } BOOT_DRIVER_NODE, *PBOOT_DRIVER_NODE; 424 412 425 413 // 426 414 // List of Bus Type GUIDs