1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/driver.c
5 * PURPOSE: Driver Object Management
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Filip Navara (navaraf@reactos.org)
8 * Herv� Poussineau (hpoussin@reactos.org)
9 */
10
11 /* INCLUDES *******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16 #include <mm/ARM3/miarm.h>
17
18 /* GLOBALS ********************************************************************/
19
20 ERESOURCE IopDriverLoadResource;
21
22 LIST_ENTRY DriverReinitListHead;
23 KSPIN_LOCK DriverReinitListLock;
24 PLIST_ENTRY DriverReinitTailEntry;
25
26 PLIST_ENTRY DriverBootReinitTailEntry;
27 LIST_ENTRY DriverBootReinitListHead;
28 KSPIN_LOCK DriverBootReinitListLock;
29
30 UNICODE_STRING IopHardwareDatabaseKey =
31 RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM");
32 static const WCHAR ServicesKeyName[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
33
34 POBJECT_TYPE IoDriverObjectType = NULL;
35
36 extern BOOLEAN PnpSystemInit;
37 extern BOOLEAN PnPBootDriversLoaded;
38 extern KEVENT PiEnumerationFinished;
39
40 USHORT IopGroupIndex;
41 PLIST_ENTRY IopGroupTable;
42
43 /* TYPES *********************************************************************/
44
45 // Parameters packet for Load/Unload work item's context
46 typedef struct _LOAD_UNLOAD_PARAMS
47 {
48 NTSTATUS Status;
49 PUNICODE_STRING RegistryPath;
50 WORK_QUEUE_ITEM WorkItem;
51 KEVENT Event;
52 PDRIVER_OBJECT DriverObject;
53 BOOLEAN SetEvent;
54 } LOAD_UNLOAD_PARAMS, *PLOAD_UNLOAD_PARAMS;
55
56 NTSTATUS
57 IopDoLoadUnloadDriver(
58 _In_opt_ PUNICODE_STRING RegistryPath,
59 _Inout_ PDRIVER_OBJECT *DriverObject);
60
61 /* PRIVATE FUNCTIONS **********************************************************/
62
63 NTSTATUS
64 NTAPI
IopInvalidDeviceRequest(PDEVICE_OBJECT DeviceObject,PIRP Irp)65 IopInvalidDeviceRequest(
66 PDEVICE_OBJECT DeviceObject,
67 PIRP Irp)
68 {
69 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
70 Irp->IoStatus.Information = 0;
71 IoCompleteRequest(Irp, IO_NO_INCREMENT);
72 return STATUS_INVALID_DEVICE_REQUEST;
73 }
74
75 VOID
76 NTAPI
IopDeleteDriver(IN PVOID ObjectBody)77 IopDeleteDriver(IN PVOID ObjectBody)
78 {
79 PDRIVER_OBJECT DriverObject = ObjectBody;
80 PIO_CLIENT_EXTENSION DriverExtension, NextDriverExtension;
81 PAGED_CODE();
82
83 DPRINT1("Deleting driver object '%wZ'\n", &DriverObject->DriverName);
84
85 /* There must be no device objects remaining at this point */
86 ASSERT(!DriverObject->DeviceObject);
87
88 /* Get the extension and loop them */
89 DriverExtension = IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
90 while (DriverExtension)
91 {
92 /* Get the next one */
93 NextDriverExtension = DriverExtension->NextExtension;
94 ExFreePoolWithTag(DriverExtension, TAG_DRIVER_EXTENSION);
95
96 /* Move on */
97 DriverExtension = NextDriverExtension;
98 }
99
100 /* Check if the driver image is still loaded */
101 if (DriverObject->DriverSection)
102 {
103 /* Unload it */
104 MmUnloadSystemImage(DriverObject->DriverSection);
105 }
106
107 /* Check if it has a name */
108 if (DriverObject->DriverName.Buffer)
109 {
110 /* Free it */
111 ExFreePool(DriverObject->DriverName.Buffer);
112 }
113
114 /* Check if it has a service key name */
115 if (DriverObject->DriverExtension->ServiceKeyName.Buffer)
116 {
117 /* Free it */
118 ExFreePool(DriverObject->DriverExtension->ServiceKeyName.Buffer);
119 }
120 }
121
122 NTSTATUS
IopGetDriverNames(_In_ HANDLE ServiceHandle,_Out_ PUNICODE_STRING DriverName,_Out_opt_ PUNICODE_STRING ServiceName)123 IopGetDriverNames(
124 _In_ HANDLE ServiceHandle,
125 _Out_ PUNICODE_STRING DriverName,
126 _Out_opt_ PUNICODE_STRING ServiceName)
127 {
128 UNICODE_STRING driverName = {.Buffer = NULL}, serviceName;
129 PKEY_VALUE_FULL_INFORMATION kvInfo;
130 NTSTATUS status;
131
132 PAGED_CODE();
133
134 /* 1. Check the "ObjectName" field in the driver's registry key (it has priority) */
135 status = IopGetRegistryValue(ServiceHandle, L"ObjectName", &kvInfo);
136 if (NT_SUCCESS(status))
137 {
138 /* We've got the ObjectName, use it as the driver name */
139 if (kvInfo->Type != REG_SZ || kvInfo->DataLength == 0)
140 {
141 ExFreePool(kvInfo);
142 return STATUS_ILL_FORMED_SERVICE_ENTRY;
143 }
144
145 driverName.Length = kvInfo->DataLength - sizeof(UNICODE_NULL);
146 driverName.MaximumLength = kvInfo->DataLength;
147 driverName.Buffer = ExAllocatePoolWithTag(NonPagedPool, driverName.MaximumLength, TAG_IO);
148 if (!driverName.Buffer)
149 {
150 ExFreePool(kvInfo);
151 return STATUS_INSUFFICIENT_RESOURCES;
152 }
153
154 RtlMoveMemory(driverName.Buffer,
155 (PVOID)((ULONG_PTR)kvInfo + kvInfo->DataOffset),
156 driverName.Length);
157 driverName.Buffer[driverName.Length / sizeof(WCHAR)] = UNICODE_NULL;
158 ExFreePool(kvInfo);
159 }
160
161 /* Check whether we need to get ServiceName as well, either to construct
162 * the driver name (because we could not use "ObjectName"), or because
163 * it is requested by the caller. */
164 PKEY_BASIC_INFORMATION basicInfo = NULL;
165 if (!NT_SUCCESS(status) || ServiceName != NULL)
166 {
167 /* Retrieve the necessary buffer size */
168 ULONG infoLength;
169 status = ZwQueryKey(ServiceHandle, KeyBasicInformation, NULL, 0, &infoLength);
170 if (status != STATUS_BUFFER_TOO_SMALL)
171 {
172 status = (NT_SUCCESS(status) ? STATUS_UNSUCCESSFUL : status);
173 goto Cleanup;
174 }
175
176 /* Allocate the buffer and retrieve the data */
177 basicInfo = ExAllocatePoolWithTag(PagedPool, infoLength, TAG_IO);
178 if (!basicInfo)
179 {
180 status = STATUS_INSUFFICIENT_RESOURCES;
181 goto Cleanup;
182 }
183
184 status = ZwQueryKey(ServiceHandle, KeyBasicInformation, basicInfo, infoLength, &infoLength);
185 if (!NT_SUCCESS(status))
186 {
187 goto Cleanup;
188 }
189
190 serviceName.Length = basicInfo->NameLength;
191 serviceName.MaximumLength = basicInfo->NameLength;
192 serviceName.Buffer = basicInfo->Name;
193 }
194
195 /* 2. There is no "ObjectName" - construct it ourselves. Depending on the driver type,
196 * it will be either "\Driver\<ServiceName>" or "\FileSystem\<ServiceName>" */
197 if (driverName.Buffer == NULL)
198 {
199 ASSERT(basicInfo); // Container for serviceName
200
201 /* Retrieve the driver type */
202 ULONG driverType;
203 status = IopGetRegistryValue(ServiceHandle, L"Type", &kvInfo);
204 if (!NT_SUCCESS(status))
205 {
206 goto Cleanup;
207 }
208 if (kvInfo->Type != REG_DWORD || kvInfo->DataLength != sizeof(ULONG))
209 {
210 ExFreePool(kvInfo);
211 status = STATUS_ILL_FORMED_SERVICE_ENTRY;
212 goto Cleanup;
213 }
214
215 RtlMoveMemory(&driverType,
216 (PVOID)((ULONG_PTR)kvInfo + kvInfo->DataOffset),
217 sizeof(ULONG));
218 ExFreePool(kvInfo);
219
220 /* Compute the necessary driver name string size */
221 if (driverType == SERVICE_RECOGNIZER_DRIVER || driverType == SERVICE_FILE_SYSTEM_DRIVER)
222 driverName.MaximumLength = sizeof(FILESYSTEM_ROOT_NAME);
223 else
224 driverName.MaximumLength = sizeof(DRIVER_ROOT_NAME);
225
226 driverName.MaximumLength += serviceName.Length;
227 driverName.Length = 0;
228
229 /* Allocate and build it */
230 driverName.Buffer = ExAllocatePoolWithTag(NonPagedPool, driverName.MaximumLength, TAG_IO);
231 if (!driverName.Buffer)
232 {
233 status = STATUS_INSUFFICIENT_RESOURCES;
234 goto Cleanup;
235 }
236
237 if (driverType == SERVICE_RECOGNIZER_DRIVER || driverType == SERVICE_FILE_SYSTEM_DRIVER)
238 RtlAppendUnicodeToString(&driverName, FILESYSTEM_ROOT_NAME);
239 else
240 RtlAppendUnicodeToString(&driverName, DRIVER_ROOT_NAME);
241
242 RtlAppendUnicodeStringToString(&driverName, &serviceName);
243 }
244
245 if (ServiceName != NULL)
246 {
247 ASSERT(basicInfo); // Container for serviceName
248
249 /* Allocate a copy for the caller */
250 PWCHAR buf = ExAllocatePoolWithTag(PagedPool, serviceName.Length, TAG_IO);
251 if (!buf)
252 {
253 status = STATUS_INSUFFICIENT_RESOURCES;
254 goto Cleanup;
255 }
256 RtlMoveMemory(buf, serviceName.Buffer, serviceName.Length);
257 ServiceName->MaximumLength = serviceName.Length;
258 ServiceName->Length = serviceName.Length;
259 ServiceName->Buffer = buf;
260 }
261
262 *DriverName = driverName;
263 status = STATUS_SUCCESS;
264
265 Cleanup:
266 if (basicInfo)
267 ExFreePoolWithTag(basicInfo, TAG_IO);
268
269 if (!NT_SUCCESS(status) && driverName.Buffer)
270 ExFreePoolWithTag(driverName.Buffer, TAG_IO);
271
272 return status;
273 }
274
275 /**
276 * @brief Determines whether String1 may be a suffix of String2.
277 * @return TRUE if String2 contains String1 as a suffix.
278 **/
279 static BOOLEAN
IopSuffixUnicodeString(_In_ PCUNICODE_STRING String1,_In_ PCUNICODE_STRING String2,_In_ BOOLEAN CaseInSensitive)280 IopSuffixUnicodeString(
281 _In_ PCUNICODE_STRING String1,
282 _In_ PCUNICODE_STRING String2,
283 _In_ BOOLEAN CaseInSensitive)
284 {
285 PWCHAR pc1, pc2;
286 ULONG NumChars;
287
288 if (String2->Length < String1->Length)
289 return FALSE;
290
291 NumChars = String1->Length / sizeof(WCHAR);
292 pc1 = String1->Buffer;
293 pc2 = &String2->Buffer[String2->Length / sizeof(WCHAR) - NumChars];
294
295 if (pc1 && pc2)
296 {
297 if (CaseInSensitive)
298 {
299 while (NumChars--)
300 {
301 if (RtlUpcaseUnicodeChar(*pc1++) !=
302 RtlUpcaseUnicodeChar(*pc2++))
303 {
304 return FALSE;
305 }
306 }
307 }
308 else
309 {
310 while (NumChars--)
311 {
312 if (*pc1++ != *pc2++)
313 return FALSE;
314 }
315 }
316
317 return TRUE;
318 }
319
320 return FALSE;
321 }
322
323 /**
324 * @brief Displays a driver-loading message in SOS mode.
325 **/
326 static VOID
327 FASTCALL
IopDisplayLoadingMessage(_In_ PCUNICODE_STRING ServiceName)328 IopDisplayLoadingMessage(
329 _In_ PCUNICODE_STRING ServiceName)
330 {
331 extern BOOLEAN SosEnabled; // See ex/init.c
332 static const UNICODE_STRING DotSys = RTL_CONSTANT_STRING(L".SYS");
333 CHAR TextBuffer[256];
334
335 if (!SosEnabled) return;
336 if (!KeLoaderBlock) return;
337 RtlStringCbPrintfA(TextBuffer, sizeof(TextBuffer),
338 "%s%sSystem32\\Drivers\\%wZ%s\r\n",
339 KeLoaderBlock->ArcBootDeviceName,
340 KeLoaderBlock->NtBootPathName,
341 ServiceName,
342 IopSuffixUnicodeString(&DotSys, ServiceName, TRUE)
343 ? "" : ".SYS");
344 HalDisplayString(TextBuffer);
345 }
346
347 /*
348 * IopNormalizeImagePath
349 *
350 * Normalize an image path to contain complete path.
351 *
352 * Parameters
353 * ImagePath
354 * The input path and on exit the result path. ImagePath.Buffer
355 * must be allocated by ExAllocatePool on input. Caller is responsible
356 * for freeing the buffer when it's no longer needed.
357 *
358 * ServiceName
359 * Name of the service that ImagePath belongs to.
360 *
361 * Return Value
362 * Status
363 *
364 * Remarks
365 * The input image path isn't freed on error.
366 */
367 NTSTATUS
368 FASTCALL
369 IopNormalizeImagePath(
370 _Inout_ _When_(return>=0, _At_(ImagePath->Buffer, _Post_notnull_ __drv_allocatesMem(Mem)))
371 PUNICODE_STRING ImagePath,
372 _In_ PUNICODE_STRING ServiceName)
373 {
374 UNICODE_STRING SystemRootString = RTL_CONSTANT_STRING(L"\\SystemRoot\\");
375 UNICODE_STRING DriversPathString = RTL_CONSTANT_STRING(L"\\SystemRoot\\System32\\drivers\\");
376 UNICODE_STRING DotSysString = RTL_CONSTANT_STRING(L".sys");
377 UNICODE_STRING InputImagePath;
378
379 DPRINT("Normalizing image path '%wZ' for service '%wZ'\n", ImagePath, ServiceName);
380
381 InputImagePath = *ImagePath;
382 if (InputImagePath.Length == 0)
383 {
384 ImagePath->Length = 0;
385 ImagePath->MaximumLength = DriversPathString.Length +
386 ServiceName->Length +
387 DotSysString.Length +
388 sizeof(UNICODE_NULL);
389 ImagePath->Buffer = ExAllocatePoolWithTag(NonPagedPool,
390 ImagePath->MaximumLength,
391 TAG_IO);
392 if (ImagePath->Buffer == NULL)
393 return STATUS_NO_MEMORY;
394
395 RtlCopyUnicodeString(ImagePath, &DriversPathString);
396 RtlAppendUnicodeStringToString(ImagePath, ServiceName);
397 RtlAppendUnicodeStringToString(ImagePath, &DotSysString);
398 }
399 else if (InputImagePath.Buffer[0] != L'\\')
400 {
401 ImagePath->Length = 0;
402 ImagePath->MaximumLength = SystemRootString.Length +
403 InputImagePath.Length +
404 sizeof(UNICODE_NULL);
405 ImagePath->Buffer = ExAllocatePoolWithTag(NonPagedPool,
406 ImagePath->MaximumLength,
407 TAG_IO);
408 if (ImagePath->Buffer == NULL)
409 return STATUS_NO_MEMORY;
410
411 RtlCopyUnicodeString(ImagePath, &SystemRootString);
412 RtlAppendUnicodeStringToString(ImagePath, &InputImagePath);
413
414 /* Free caller's string */
415 ExFreePoolWithTag(InputImagePath.Buffer, TAG_RTLREGISTRY);
416 }
417
418 DPRINT("Normalized image path is '%wZ' for service '%wZ'\n", ImagePath, ServiceName);
419
420 return STATUS_SUCCESS;
421 }
422
423 /**
424 * @brief Initialize a loaded driver
425 *
426 * @param[in] ModuleObject
427 * Module object representing the driver. It can be retrieved by IopLoadServiceModule.
428 * Freed on failure, so in a such case this should not be accessed anymore
429 *
430 * @param[in] ServiceHandle
431 * Handle to a driver's CCS/Services/<ServiceName> key
432 *
433 * @param[out] DriverObject
434 * This contains the driver object if it was created (even with unsuccessfull result)
435 *
436 * @param[out] DriverEntryStatus
437 * This contains the status value returned by the driver's DriverEntry routine
438 * (will not be valid of the return value is not STATUS_SUCCESS or STATUS_FAILED_DRIVER_ENTRY)
439 *
440 * @return Status of the operation
441 */
442 NTSTATUS
IopInitializeDriverModule(_In_ PLDR_DATA_TABLE_ENTRY ModuleObject,_In_ HANDLE ServiceHandle,_Out_ PDRIVER_OBJECT * OutDriverObject,_Out_ NTSTATUS * DriverEntryStatus)443 IopInitializeDriverModule(
444 _In_ PLDR_DATA_TABLE_ENTRY ModuleObject,
445 _In_ HANDLE ServiceHandle,
446 _Out_ PDRIVER_OBJECT *OutDriverObject,
447 _Out_ NTSTATUS *DriverEntryStatus)
448 {
449 UNICODE_STRING DriverName, RegistryPath, ServiceName;
450 NTSTATUS Status;
451
452 PAGED_CODE();
453
454 Status = IopGetDriverNames(ServiceHandle, &DriverName, &ServiceName);
455 if (!NT_SUCCESS(Status))
456 {
457 MmUnloadSystemImage(ModuleObject);
458 return Status;
459 }
460
461 DPRINT("Driver name: '%wZ'\n", &DriverName);
462
463 /*
464 * Retrieve the driver's PE image NT header and perform some sanity checks.
465 * NOTE: We suppose that since the driver has been successfully loaded,
466 * its NT and optional headers are all valid and have expected sizes.
467 */
468 PIMAGE_NT_HEADERS NtHeaders = RtlImageNtHeader(ModuleObject->DllBase);
469 ASSERT(NtHeaders);
470 // NOTE: ModuleObject->SizeOfImage is actually (number of PTEs)*PAGE_SIZE.
471 ASSERT(ModuleObject->SizeOfImage == ROUND_TO_PAGES(NtHeaders->OptionalHeader.SizeOfImage));
472 ASSERT(ModuleObject->EntryPoint == RVA(ModuleObject->DllBase, NtHeaders->OptionalHeader.AddressOfEntryPoint));
473
474 /* Obtain the registry path for the DriverInit routine */
475 PKEY_NAME_INFORMATION nameInfo;
476 ULONG infoLength;
477 Status = ZwQueryKey(ServiceHandle, KeyNameInformation, NULL, 0, &infoLength);
478 if (Status == STATUS_BUFFER_TOO_SMALL)
479 {
480 nameInfo = ExAllocatePoolWithTag(NonPagedPool, infoLength, TAG_IO);
481 if (nameInfo)
482 {
483 Status = ZwQueryKey(ServiceHandle,
484 KeyNameInformation,
485 nameInfo,
486 infoLength,
487 &infoLength);
488 if (NT_SUCCESS(Status))
489 {
490 RegistryPath.Length = nameInfo->NameLength;
491 RegistryPath.MaximumLength = nameInfo->NameLength;
492 RegistryPath.Buffer = nameInfo->Name;
493 }
494 else
495 {
496 ExFreePoolWithTag(nameInfo, TAG_IO);
497 }
498 }
499 else
500 {
501 Status = STATUS_INSUFFICIENT_RESOURCES;
502 }
503 }
504 else
505 {
506 Status = NT_SUCCESS(Status) ? STATUS_UNSUCCESSFUL : Status;
507 }
508
509 if (!NT_SUCCESS(Status))
510 {
511 RtlFreeUnicodeString(&ServiceName);
512 RtlFreeUnicodeString(&DriverName);
513 MmUnloadSystemImage(ModuleObject);
514 return Status;
515 }
516
517 /* Create the driver object */
518 ULONG ObjectSize = sizeof(DRIVER_OBJECT) + sizeof(EXTENDED_DRIVER_EXTENSION);
519 OBJECT_ATTRIBUTES objAttrs;
520 PDRIVER_OBJECT driverObject;
521 InitializeObjectAttributes(&objAttrs,
522 &DriverName,
523 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
524 NULL,
525 NULL);
526
527 Status = ObCreateObject(KernelMode,
528 IoDriverObjectType,
529 &objAttrs,
530 KernelMode,
531 NULL,
532 ObjectSize,
533 0,
534 0,
535 (PVOID*)&driverObject);
536 if (!NT_SUCCESS(Status))
537 {
538 ExFreePoolWithTag(nameInfo, TAG_IO); // container for RegistryPath
539 RtlFreeUnicodeString(&ServiceName);
540 RtlFreeUnicodeString(&DriverName);
541 MmUnloadSystemImage(ModuleObject);
542 DPRINT1("Error while creating driver object \"%wZ\" status %x\n", &DriverName, Status);
543 return Status;
544 }
545
546 DPRINT("Created driver object 0x%p for \"%wZ\"\n", driverObject, &DriverName);
547
548 RtlZeroMemory(driverObject, ObjectSize);
549 driverObject->Type = IO_TYPE_DRIVER;
550 driverObject->Size = sizeof(DRIVER_OBJECT);
551
552 /* Set the legacy flag if this is not a WDM driver */
553 if (!(NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_WDM_DRIVER))
554 driverObject->Flags |= DRVO_LEGACY_DRIVER;
555
556 driverObject->DriverSection = ModuleObject;
557 driverObject->DriverStart = ModuleObject->DllBase;
558 driverObject->DriverSize = ModuleObject->SizeOfImage;
559 driverObject->DriverInit = ModuleObject->EntryPoint;
560 driverObject->HardwareDatabase = &IopHardwareDatabaseKey;
561 driverObject->DriverExtension = (PDRIVER_EXTENSION)(driverObject + 1);
562 driverObject->DriverExtension->DriverObject = driverObject;
563
564 /* Loop all Major Functions */
565 for (INT i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
566 {
567 /* Invalidate each function */
568 driverObject->MajorFunction[i] = IopInvalidDeviceRequest;
569 }
570
571 /* Add the Object and get its handle */
572 HANDLE hDriver;
573 Status = ObInsertObject(driverObject, NULL, FILE_READ_DATA, 0, NULL, &hDriver);
574 if (!NT_SUCCESS(Status))
575 {
576 ExFreePoolWithTag(nameInfo, TAG_IO);
577 RtlFreeUnicodeString(&ServiceName);
578 RtlFreeUnicodeString(&DriverName);
579 return Status;
580 }
581
582 /* Now reference it */
583 Status = ObReferenceObjectByHandle(hDriver,
584 0,
585 IoDriverObjectType,
586 KernelMode,
587 (PVOID*)&driverObject,
588 NULL);
589
590 /* Close the extra handle */
591 ZwClose(hDriver);
592
593 if (!NT_SUCCESS(Status))
594 {
595 ExFreePoolWithTag(nameInfo, TAG_IO); // container for RegistryPath
596 RtlFreeUnicodeString(&ServiceName);
597 RtlFreeUnicodeString(&DriverName);
598 return Status;
599 }
600
601 /* Set up the service key name buffer */
602 UNICODE_STRING serviceKeyName;
603 serviceKeyName.Length = 0;
604 // NULL-terminate for Windows compatibility
605 serviceKeyName.MaximumLength = ServiceName.MaximumLength + sizeof(UNICODE_NULL);
606 serviceKeyName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
607 serviceKeyName.MaximumLength,
608 TAG_IO);
609 if (!serviceKeyName.Buffer)
610 {
611 ObMakeTemporaryObject(driverObject);
612 ObDereferenceObject(driverObject);
613 ExFreePoolWithTag(nameInfo, TAG_IO); // container for RegistryPath
614 RtlFreeUnicodeString(&ServiceName);
615 RtlFreeUnicodeString(&DriverName);
616 return STATUS_INSUFFICIENT_RESOURCES;
617 }
618
619 /* Copy the name and set it in the driver extension */
620 RtlCopyUnicodeString(&serviceKeyName, &ServiceName);
621 RtlFreeUnicodeString(&ServiceName);
622 driverObject->DriverExtension->ServiceKeyName = serviceKeyName;
623
624 /* Make a copy of the driver name to store in the driver object */
625 UNICODE_STRING driverNamePaged;
626 driverNamePaged.Length = 0;
627 // NULL-terminate for Windows compatibility
628 driverNamePaged.MaximumLength = DriverName.MaximumLength + sizeof(UNICODE_NULL);
629 driverNamePaged.Buffer = ExAllocatePoolWithTag(PagedPool,
630 driverNamePaged.MaximumLength,
631 TAG_IO);
632 if (!driverNamePaged.Buffer)
633 {
634 ObMakeTemporaryObject(driverObject);
635 ObDereferenceObject(driverObject);
636 ExFreePoolWithTag(nameInfo, TAG_IO); // container for RegistryPath
637 RtlFreeUnicodeString(&DriverName);
638 return STATUS_INSUFFICIENT_RESOURCES;
639 }
640
641 RtlCopyUnicodeString(&driverNamePaged, &DriverName);
642 driverObject->DriverName = driverNamePaged;
643
644 /* Finally, call its init function */
645 Status = driverObject->DriverInit(driverObject, &RegistryPath);
646 *DriverEntryStatus = Status;
647 if (!NT_SUCCESS(Status))
648 {
649 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", &DriverName, Status);
650 // return a special status value in case of failure
651 Status = STATUS_FAILED_DRIVER_ENTRY;
652 }
653
654 /* HACK: We're going to say if we don't have any DOs from DriverEntry, then we're not legacy.
655 * Other parts of the I/O manager depend on this behavior */
656 if (!driverObject->DeviceObject)
657 {
658 driverObject->Flags &= ~DRVO_LEGACY_DRIVER;
659 }
660
661 /* Windows does this fixup, keep it for compatibility */
662 for (INT i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
663 {
664 /*
665 * Make sure the driver didn't set any dispatch entry point to NULL!
666 * Doing so is illegal; drivers shouldn't touch entry points they
667 * do not implement.
668 */
669
670 /* Check if it did so anyway */
671 if (!driverObject->MajorFunction[i])
672 {
673 /* Print a warning in the debug log */
674 DPRINT1("Driver <%wZ> set DriverObject->MajorFunction[%lu] to NULL!\n",
675 &driverObject->DriverName, i);
676
677 /* Fix it up */
678 driverObject->MajorFunction[i] = IopInvalidDeviceRequest;
679 }
680 }
681
682 // TODO: for legacy drivers, unload the driver if it didn't create any DO
683
684 ExFreePoolWithTag(nameInfo, TAG_IO); // container for RegistryPath
685 RtlFreeUnicodeString(&DriverName);
686
687 if (!NT_SUCCESS(Status))
688 {
689 // if the driver entry has been failed, clear the object
690 ObMakeTemporaryObject(driverObject);
691 ObDereferenceObject(driverObject);
692 return Status;
693 }
694
695 *OutDriverObject = driverObject;
696
697 MmFreeDriverInitialization((PLDR_DATA_TABLE_ENTRY)driverObject->DriverSection);
698
699 /* Set the driver as initialized */
700 IopReadyDeviceObjects(driverObject);
701
702 if (PnpSystemInit) IopReinitializeDrivers();
703
704 return STATUS_SUCCESS;
705 }
706
707 NTSTATUS
708 NTAPI
709 MiResolveImageReferences(IN PVOID ImageBase,
710 IN PUNICODE_STRING ImageFileDirectory,
711 IN PUNICODE_STRING NamePrefix OPTIONAL,
712 OUT PCHAR *MissingApi,
713 OUT PWCHAR *MissingDriver,
714 OUT PLOAD_IMPORTS *LoadImports);
715
716 //
717 // Used for images already loaded (boot drivers)
718 //
719 CODE_SEG("INIT")
720 NTSTATUS
721 NTAPI
LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry,PUNICODE_STRING FileName,PLDR_DATA_TABLE_ENTRY * ModuleObject)722 LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry,
723 PUNICODE_STRING FileName,
724 PLDR_DATA_TABLE_ENTRY *ModuleObject)
725 {
726 NTSTATUS Status;
727 UNICODE_STRING BaseName, BaseDirectory;
728 PLOAD_IMPORTS LoadedImports = MM_SYSLDR_NO_IMPORTS;
729 PCHAR MissingApiName, Buffer;
730 PWCHAR MissingDriverName;
731 PVOID DriverBase = LdrEntry->DllBase;
732
733 /* Allocate a buffer we'll use for names */
734 Buffer = ExAllocatePoolWithTag(NonPagedPool,
735 MAXIMUM_FILENAME_LENGTH,
736 TAG_LDR_WSTR);
737 if (!Buffer)
738 {
739 /* Fail */
740 return STATUS_INSUFFICIENT_RESOURCES;
741 }
742
743 /* Check for a separator */
744 if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
745 {
746 PWCHAR p;
747 ULONG BaseLength;
748
749 /* Loop the path until we get to the base name */
750 p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)];
751 while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--;
752
753 /* Get the length */
754 BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p);
755 BaseLength *= sizeof(WCHAR);
756
757 /* Setup the string */
758 BaseName.Length = (USHORT)BaseLength;
759 BaseName.Buffer = p;
760 }
761 else
762 {
763 /* Otherwise, we already have a base name */
764 BaseName.Length = FileName->Length;
765 BaseName.Buffer = FileName->Buffer;
766 }
767
768 /* Setup the maximum length */
769 BaseName.MaximumLength = BaseName.Length;
770
771 /* Now compute the base directory */
772 BaseDirectory = *FileName;
773 BaseDirectory.Length -= BaseName.Length;
774 BaseDirectory.MaximumLength = BaseDirectory.Length;
775
776 /* Resolve imports */
777 MissingApiName = Buffer;
778 Status = MiResolveImageReferences(DriverBase,
779 &BaseDirectory,
780 NULL,
781 &MissingApiName,
782 &MissingDriverName,
783 &LoadedImports);
784
785 /* Free the temporary buffer */
786 ExFreePoolWithTag(Buffer, TAG_LDR_WSTR);
787
788 /* Check the result of the imports resolution */
789 if (!NT_SUCCESS(Status)) return Status;
790
791 /* Return */
792 *ModuleObject = LdrEntry;
793 return STATUS_SUCCESS;
794 }
795
796 PDEVICE_OBJECT
797 IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance);
798
799 /*
800 * IopInitializeBuiltinDriver
801 *
802 * Initialize a driver that is already loaded in memory.
803 */
804 CODE_SEG("INIT")
805 static
806 BOOLEAN
IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY BootLdrEntry)807 IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY BootLdrEntry)
808 {
809 PDRIVER_OBJECT DriverObject;
810 NTSTATUS Status;
811 PWCHAR Buffer, FileNameWithoutPath;
812 PWSTR FileExtension;
813 PUNICODE_STRING ModuleName = &BootLdrEntry->BaseDllName;
814 PLDR_DATA_TABLE_ENTRY LdrEntry;
815 PLIST_ENTRY NextEntry;
816 UNICODE_STRING ServiceName;
817 BOOLEAN Success;
818
819 /*
820 * Display 'Loading XXX...' message
821 */
822 IopDisplayLoadingMessage(ModuleName);
823 InbvIndicateProgress();
824
825 Buffer = ExAllocatePoolWithTag(PagedPool,
826 ModuleName->Length + sizeof(UNICODE_NULL),
827 TAG_IO);
828 if (Buffer == NULL)
829 {
830 return FALSE;
831 }
832
833 RtlCopyMemory(Buffer, ModuleName->Buffer, ModuleName->Length);
834 Buffer[ModuleName->Length / sizeof(WCHAR)] = UNICODE_NULL;
835
836 /*
837 * Generate filename without path (not needed by freeldr)
838 */
839 FileNameWithoutPath = wcsrchr(Buffer, L'\\');
840 if (FileNameWithoutPath == NULL)
841 {
842 FileNameWithoutPath = Buffer;
843 }
844 else
845 {
846 FileNameWithoutPath++;
847 }
848
849 /*
850 * Strip the file extension from ServiceName
851 */
852 Success = RtlCreateUnicodeString(&ServiceName, FileNameWithoutPath);
853 ExFreePoolWithTag(Buffer, TAG_IO);
854 if (!Success)
855 {
856 return FALSE;
857 }
858
859 FileExtension = wcsrchr(ServiceName.Buffer, L'.');
860 if (FileExtension != NULL)
861 {
862 ServiceName.Length -= (USHORT)wcslen(FileExtension) * sizeof(WCHAR);
863 FileExtension[0] = UNICODE_NULL;
864 }
865
866 UNICODE_STRING RegistryPath;
867
868 // Make the registry path for the driver
869 RegistryPath.Length = 0;
870 RegistryPath.MaximumLength = sizeof(ServicesKeyName) + ServiceName.Length;
871 RegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool, RegistryPath.MaximumLength, TAG_IO);
872 if (RegistryPath.Buffer == NULL)
873 {
874 return FALSE;
875 }
876 RtlAppendUnicodeToString(&RegistryPath, ServicesKeyName);
877 RtlAppendUnicodeStringToString(&RegistryPath, &ServiceName);
878 RtlFreeUnicodeString(&ServiceName);
879
880 HANDLE serviceHandle;
881 Status = IopOpenRegistryKeyEx(&serviceHandle, NULL, &RegistryPath, KEY_READ);
882 RtlFreeUnicodeString(&RegistryPath);
883 if (!NT_SUCCESS(Status))
884 {
885 return FALSE;
886 }
887
888 /* Lookup the new Ldr entry in PsLoadedModuleList */
889 for (NextEntry = PsLoadedModuleList.Flink;
890 NextEntry != &PsLoadedModuleList;
891 NextEntry = NextEntry->Flink)
892 {
893 LdrEntry = CONTAINING_RECORD(NextEntry,
894 LDR_DATA_TABLE_ENTRY,
895 InLoadOrderLinks);
896 if (RtlEqualUnicodeString(ModuleName, &LdrEntry->BaseDllName, TRUE))
897 {
898 break;
899 }
900 }
901 ASSERT(NextEntry != &PsLoadedModuleList);
902
903 /*
904 * Initialize the driver
905 */
906 NTSTATUS driverEntryStatus;
907 Status = IopInitializeDriverModule(LdrEntry,
908 serviceHandle,
909 &DriverObject,
910 &driverEntryStatus);
911
912 if (!NT_SUCCESS(Status))
913 {
914 DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName, Status);
915 return FALSE;
916 }
917
918 // The driver has been loaded, now check if where are any PDOs
919 // for that driver, and queue AddDevice call for them.
920 // The check is possible because HKLM/SYSTEM/CCS/Services/<ServiceName>/Enum directory
921 // is populated upon a new device arrival based on a (critical) device database
922
923 // Legacy drivers may add devices inside DriverEntry.
924 // We're lazy and always assume that they are doing so
925 BOOLEAN deviceAdded = !!(DriverObject->Flags & DRVO_LEGACY_DRIVER);
926
927 HANDLE enumServiceHandle;
928 UNICODE_STRING enumName = RTL_CONSTANT_STRING(L"Enum");
929
930 Status = IopOpenRegistryKeyEx(&enumServiceHandle, serviceHandle, &enumName, KEY_READ);
931 ZwClose(serviceHandle);
932
933 if (NT_SUCCESS(Status))
934 {
935 ULONG instanceCount = 0;
936 PKEY_VALUE_FULL_INFORMATION kvInfo;
937 Status = IopGetRegistryValue(enumServiceHandle, L"Count", &kvInfo);
938 if (!NT_SUCCESS(Status))
939 {
940 goto Cleanup;
941 }
942 if (kvInfo->Type != REG_DWORD || kvInfo->DataLength != sizeof(ULONG))
943 {
944 ExFreePool(kvInfo);
945 goto Cleanup;
946 }
947
948 RtlMoveMemory(&instanceCount,
949 (PVOID)((ULONG_PTR)kvInfo + kvInfo->DataOffset),
950 sizeof(ULONG));
951 ExFreePool(kvInfo);
952
953 DPRINT("Processing %u instances for %wZ module\n", instanceCount, ModuleName);
954
955 for (ULONG i = 0; i < instanceCount; i++)
956 {
957 WCHAR num[11];
958 UNICODE_STRING instancePath;
959 RtlStringCbPrintfW(num, sizeof(num), L"%u", i);
960
961 Status = IopGetRegistryValue(enumServiceHandle, num, &kvInfo);
962 if (!NT_SUCCESS(Status))
963 {
964 continue;
965 }
966 if (kvInfo->Type != REG_SZ || kvInfo->DataLength == 0)
967 {
968 ExFreePool(kvInfo);
969 continue;
970 }
971
972 instancePath.Length = kvInfo->DataLength - sizeof(UNICODE_NULL);
973 instancePath.MaximumLength = kvInfo->DataLength;
974 instancePath.Buffer = ExAllocatePoolWithTag(NonPagedPool,
975 instancePath.MaximumLength,
976 TAG_IO);
977 if (instancePath.Buffer)
978 {
979 RtlMoveMemory(instancePath.Buffer,
980 (PVOID)((ULONG_PTR)kvInfo + kvInfo->DataOffset),
981 instancePath.Length);
982 instancePath.Buffer[instancePath.Length / sizeof(WCHAR)] = UNICODE_NULL;
983
984 PDEVICE_OBJECT pdo = IopGetDeviceObjectFromDeviceInstance(&instancePath);
985 if (pdo != NULL)
986 {
987 PiQueueDeviceAction(pdo, PiActionAddBootDevices, NULL, NULL);
988 ObDereferenceObject(pdo);
989 deviceAdded = TRUE;
990 }
991 else
992 {
993 DPRINT1("No device node found matching instance path '%wZ'\n", &instancePath);
994 }
995 }
996
997 ExFreePool(kvInfo);
998 }
999
1000 ZwClose(enumServiceHandle);
1001 }
1002 Cleanup:
1003 /* Remove extra reference from IopInitializeDriverModule */
1004 ObDereferenceObject(DriverObject);
1005
1006 return deviceAdded;
1007 }
1008
1009 /*
1010 * IopInitializeBootDrivers
1011 *
1012 * Initialize boot drivers and free memory for boot files.
1013 *
1014 * Parameters
1015 * None
1016 *
1017 * Return Value
1018 * None
1019 */
1020 CODE_SEG("INIT")
1021 VOID
1022 FASTCALL
IopInitializeBootDrivers(VOID)1023 IopInitializeBootDrivers(VOID)
1024 {
1025 PLIST_ENTRY ListHead, NextEntry, NextEntry2;
1026 PLDR_DATA_TABLE_ENTRY LdrEntry;
1027 NTSTATUS Status;
1028 UNICODE_STRING DriverName;
1029 ULONG i, Index;
1030 PDRIVER_INFORMATION DriverInfo, DriverInfoTag;
1031 HANDLE KeyHandle;
1032 PBOOT_DRIVER_LIST_ENTRY BootEntry;
1033 DPRINT("IopInitializeBootDrivers()\n");
1034
1035 /* Create the RAW FS built-in driver */
1036 RtlInitUnicodeString(&DriverName, L"\\FileSystem\\RAW");
1037
1038 Status = IoCreateDriver(&DriverName, RawFsDriverEntry);
1039 if (!NT_SUCCESS(Status))
1040 {
1041 /* Fail */
1042 return;
1043 }
1044
1045 /* Get highest group order index */
1046 IopGroupIndex = PpInitGetGroupOrderIndex(NULL);
1047 if (IopGroupIndex == 0xFFFF)
1048 {
1049 UNIMPLEMENTED_DBGBREAK();
1050 }
1051
1052 /* Allocate the group table */
1053 IopGroupTable = ExAllocatePoolWithTag(PagedPool,
1054 IopGroupIndex * sizeof(LIST_ENTRY),
1055 TAG_IO);
1056 if (IopGroupTable == NULL)
1057 {
1058 UNIMPLEMENTED_DBGBREAK();
1059 }
1060
1061 /* Initialize the group table lists */
1062 for (i = 0; i < IopGroupIndex; i++) InitializeListHead(&IopGroupTable[i]);
1063
1064 /* Loop the boot modules */
1065 ListHead = &KeLoaderBlock->LoadOrderListHead;
1066 for (NextEntry = ListHead->Flink;
1067 NextEntry != ListHead;
1068 NextEntry = NextEntry->Flink)
1069 {
1070 /* Get the entry */
1071 LdrEntry = CONTAINING_RECORD(NextEntry,
1072 LDR_DATA_TABLE_ENTRY,
1073 InLoadOrderLinks);
1074
1075 /* Check if the DLL needs to be initialized */
1076 if (LdrEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL)
1077 {
1078 /* Call its entrypoint */
1079 MmCallDllInitialize(LdrEntry, NULL);
1080 }
1081 }
1082
1083 /* Loop the boot drivers */
1084 ListHead = &KeLoaderBlock->BootDriverListHead;
1085 for (NextEntry = ListHead->Flink;
1086 NextEntry != ListHead;
1087 NextEntry = NextEntry->Flink)
1088 {
1089 /* Get the entry */
1090 BootEntry = CONTAINING_RECORD(NextEntry,
1091 BOOT_DRIVER_LIST_ENTRY,
1092 Link);
1093
1094 // FIXME: TODO: This LdrEntry is to be used in a special handling
1095 // for SETUPLDR (a similar procedure is done on Windows), where
1096 // the loader would, under certain conditions, be loaded in the
1097 // SETUPLDR-specific code block below...
1098 #if 0
1099 /* Get the driver loader entry */
1100 LdrEntry = BootEntry->LdrEntry;
1101 #endif
1102
1103 /* Allocate our internal accounting structure */
1104 DriverInfo = ExAllocatePoolWithTag(PagedPool,
1105 sizeof(DRIVER_INFORMATION),
1106 TAG_IO);
1107 if (DriverInfo)
1108 {
1109 /* Zero it and initialize it */
1110 RtlZeroMemory(DriverInfo, sizeof(DRIVER_INFORMATION));
1111 InitializeListHead(&DriverInfo->Link);
1112 DriverInfo->DataTableEntry = BootEntry;
1113
1114 /* Open the registry key */
1115 Status = IopOpenRegistryKeyEx(&KeyHandle,
1116 NULL,
1117 &BootEntry->RegistryPath,
1118 KEY_READ);
1119 DPRINT("IopOpenRegistryKeyEx(%wZ) returned 0x%08lx\n", &BootEntry->RegistryPath, Status);
1120 #if 0
1121 if (NT_SUCCESS(Status))
1122 #else // Hack still needed...
1123 if ((NT_SUCCESS(Status)) || /* ReactOS HACK for SETUPLDR */
1124 ((KeLoaderBlock->SetupLdrBlock) && ((KeyHandle = (PVOID)1)))) // yes, it's an assignment!
1125 #endif
1126 {
1127 /* Save the handle */
1128 DriverInfo->ServiceHandle = KeyHandle;
1129
1130 /* Get the group oder index */
1131 Index = PpInitGetGroupOrderIndex(KeyHandle);
1132
1133 /* Get the tag position */
1134 DriverInfo->TagPosition = PipGetDriverTagPriority(KeyHandle);
1135
1136 /* Insert it into the list, at the right place */
1137 ASSERT(Index < IopGroupIndex);
1138 NextEntry2 = IopGroupTable[Index].Flink;
1139 while (NextEntry2 != &IopGroupTable[Index])
1140 {
1141 /* Get the driver info */
1142 DriverInfoTag = CONTAINING_RECORD(NextEntry2,
1143 DRIVER_INFORMATION,
1144 Link);
1145
1146 /* Check if we found the right tag position */
1147 if (DriverInfoTag->TagPosition > DriverInfo->TagPosition)
1148 {
1149 /* We're done */
1150 break;
1151 }
1152
1153 /* Next entry */
1154 NextEntry2 = NextEntry2->Flink;
1155 }
1156
1157 /* Insert us right before the next entry */
1158 NextEntry2 = NextEntry2->Blink;
1159 InsertHeadList(NextEntry2, &DriverInfo->Link);
1160 }
1161 }
1162 }
1163
1164 /* Loop each group index */
1165 for (i = 0; i < IopGroupIndex; i++)
1166 {
1167 /* Loop each group table */
1168 for (NextEntry = IopGroupTable[i].Flink;
1169 NextEntry != &IopGroupTable[i];
1170 NextEntry = NextEntry->Flink)
1171 {
1172 /* Get the entry */
1173 DriverInfo = CONTAINING_RECORD(NextEntry,
1174 DRIVER_INFORMATION,
1175 Link);
1176
1177 /* Get the driver loader entry */
1178 LdrEntry = DriverInfo->DataTableEntry->LdrEntry;
1179
1180 /* Initialize it */
1181 if (IopInitializeBuiltinDriver(LdrEntry))
1182 {
1183 // it does not make sense to enumerate the tree if there are no new devices added
1184 PiQueueDeviceAction(IopRootDeviceNode->PhysicalDeviceObject,
1185 PiActionEnumRootDevices,
1186 NULL,
1187 NULL);
1188 }
1189 }
1190 }
1191
1192 /* HAL Root Bus is being initialized before loading the boot drivers so this may cause issues
1193 * when some devices are not being initialized with their drivers. This flag is used to delay
1194 * all actions with devices (except PnP root device) until boot drivers are loaded.
1195 * See PiQueueDeviceAction function
1196 */
1197 PnPBootDriversLoaded = TRUE;
1198
1199 DbgPrint("BOOT DRIVERS LOADED\n");
1200
1201 PiQueueDeviceAction(IopRootDeviceNode->PhysicalDeviceObject,
1202 PiActionEnumDeviceTree,
1203 NULL,
1204 NULL);
1205 }
1206
1207 CODE_SEG("INIT")
1208 VOID
1209 FASTCALL
IopInitializeSystemDrivers(VOID)1210 IopInitializeSystemDrivers(VOID)
1211 {
1212 PUNICODE_STRING *DriverList, *SavedList;
1213
1214 PiPerformSyncDeviceAction(IopRootDeviceNode->PhysicalDeviceObject, PiActionEnumDeviceTree);
1215
1216 /* HACK: No system drivers on the BootCD */
1217 if (KeLoaderBlock->SetupLdrBlock) return;
1218
1219 /* Get the driver list */
1220 SavedList = DriverList = CmGetSystemDriverList();
1221 ASSERT(DriverList);
1222
1223 /* Loop it */
1224 while (*DriverList)
1225 {
1226 /* Load the driver */
1227 ZwLoadDriver(*DriverList);
1228
1229 /* Free the entry */
1230 RtlFreeUnicodeString(*DriverList);
1231 ExFreePool(*DriverList);
1232
1233 /* Next entry */
1234 InbvIndicateProgress();
1235 DriverList++;
1236 }
1237
1238 /* Free the list */
1239 ExFreePool(SavedList);
1240
1241 PiQueueDeviceAction(IopRootDeviceNode->PhysicalDeviceObject,
1242 PiActionEnumDeviceTree,
1243 NULL,
1244 NULL);
1245 }
1246
1247 /*
1248 * IopUnloadDriver
1249 *
1250 * Unloads a device driver.
1251 *
1252 * Parameters
1253 * DriverServiceName
1254 * Name of the service to unload (registry key).
1255 *
1256 * UnloadPnpDrivers
1257 * Whether to unload Plug & Plug or only legacy drivers. If this
1258 * parameter is set to FALSE, the routine will unload only legacy
1259 * drivers.
1260 *
1261 * Return Value
1262 * Status
1263 *
1264 * To do
1265 * Guard the whole function by SEH.
1266 */
1267
1268 NTSTATUS NTAPI
IopUnloadDriver(PUNICODE_STRING DriverServiceName,BOOLEAN UnloadPnpDrivers)1269 IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
1270 {
1271 UNICODE_STRING Backslash = RTL_CONSTANT_STRING(L"\\");
1272 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
1273 UNICODE_STRING ImagePath;
1274 UNICODE_STRING ServiceName;
1275 UNICODE_STRING ObjectName;
1276 PDRIVER_OBJECT DriverObject;
1277 PDEVICE_OBJECT DeviceObject;
1278 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1279 NTSTATUS Status;
1280 USHORT LastBackslash;
1281 BOOLEAN SafeToUnload = TRUE;
1282 KPROCESSOR_MODE PreviousMode;
1283 UNICODE_STRING CapturedServiceName;
1284
1285 PAGED_CODE();
1286
1287 PreviousMode = ExGetPreviousMode();
1288
1289 /* Need the appropriate priviliege */
1290 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
1291 {
1292 DPRINT1("No unload privilege!\n");
1293 return STATUS_PRIVILEGE_NOT_HELD;
1294 }
1295
1296 /* Capture the service name */
1297 Status = ProbeAndCaptureUnicodeString(&CapturedServiceName,
1298 PreviousMode,
1299 DriverServiceName);
1300 if (!NT_SUCCESS(Status))
1301 {
1302 return Status;
1303 }
1304
1305 DPRINT("IopUnloadDriver('%wZ', %u)\n", &CapturedServiceName, UnloadPnpDrivers);
1306
1307 /* We need a service name */
1308 if (CapturedServiceName.Length == 0 || CapturedServiceName.Buffer == NULL)
1309 {
1310 ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
1311 return STATUS_INVALID_PARAMETER;
1312 }
1313
1314 /*
1315 * Get the service name from the registry key name
1316 */
1317 Status = RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END,
1318 &CapturedServiceName,
1319 &Backslash,
1320 &LastBackslash);
1321 if (NT_SUCCESS(Status))
1322 {
1323 NT_ASSERT(CapturedServiceName.Length >= LastBackslash + sizeof(WCHAR));
1324 ServiceName.Buffer = &CapturedServiceName.Buffer[LastBackslash / sizeof(WCHAR) + 1];
1325 ServiceName.Length = CapturedServiceName.Length - LastBackslash - sizeof(WCHAR);
1326 ServiceName.MaximumLength = CapturedServiceName.MaximumLength - LastBackslash - sizeof(WCHAR);
1327 }
1328 else
1329 {
1330 ServiceName = CapturedServiceName;
1331 }
1332
1333 /*
1334 * Construct the driver object name
1335 */
1336 Status = RtlUShortAdd(sizeof(DRIVER_ROOT_NAME),
1337 ServiceName.Length,
1338 &ObjectName.MaximumLength);
1339 if (!NT_SUCCESS(Status))
1340 {
1341 ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
1342 return Status;
1343 }
1344 ObjectName.Length = 0;
1345 ObjectName.Buffer = ExAllocatePoolWithTag(PagedPool,
1346 ObjectName.MaximumLength,
1347 TAG_IO);
1348 if (!ObjectName.Buffer)
1349 {
1350 ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
1351 return STATUS_INSUFFICIENT_RESOURCES;
1352 }
1353 NT_VERIFY(NT_SUCCESS(RtlAppendUnicodeToString(&ObjectName, DRIVER_ROOT_NAME)));
1354 NT_VERIFY(NT_SUCCESS(RtlAppendUnicodeStringToString(&ObjectName, &ServiceName)));
1355
1356 /*
1357 * Find the driver object
1358 */
1359 Status = ObReferenceObjectByName(&ObjectName,
1360 0,
1361 0,
1362 0,
1363 IoDriverObjectType,
1364 KernelMode,
1365 0,
1366 (PVOID*)&DriverObject);
1367
1368 if (!NT_SUCCESS(Status))
1369 {
1370 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName);
1371 ExFreePoolWithTag(ObjectName.Buffer, TAG_IO);
1372 ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
1373 return Status;
1374 }
1375
1376 /* Free the buffer for driver object name */
1377 ExFreePoolWithTag(ObjectName.Buffer, TAG_IO);
1378
1379 /* Check that driver is not already unloading */
1380 if (DriverObject->Flags & DRVO_UNLOAD_INVOKED)
1381 {
1382 DPRINT1("Driver deletion pending\n");
1383 ObDereferenceObject(DriverObject);
1384 ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
1385 return STATUS_DELETE_PENDING;
1386 }
1387
1388 /*
1389 * Get path of service...
1390 */
1391 RtlZeroMemory(QueryTable, sizeof(QueryTable));
1392
1393 RtlInitUnicodeString(&ImagePath, NULL);
1394
1395 QueryTable[0].Name = L"ImagePath";
1396 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
1397 QueryTable[0].EntryContext = &ImagePath;
1398
1399 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1400 CapturedServiceName.Buffer,
1401 QueryTable,
1402 NULL,
1403 NULL);
1404
1405 /* We no longer need service name */
1406 ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
1407
1408 if (!NT_SUCCESS(Status))
1409 {
1410 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);
1411 ObDereferenceObject(DriverObject);
1412 return Status;
1413 }
1414
1415 /*
1416 * Normalize the image path for all later processing.
1417 */
1418 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1419
1420 if (!NT_SUCCESS(Status))
1421 {
1422 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status);
1423 ObDereferenceObject(DriverObject);
1424 return Status;
1425 }
1426
1427 /* Free the service path */
1428 ExFreePool(ImagePath.Buffer);
1429
1430 /*
1431 * Unload the module and release the references to the device object
1432 */
1433
1434 /* Call the load/unload routine, depending on current process */
1435 if (DriverObject->DriverUnload && DriverObject->DriverSection &&
1436 (UnloadPnpDrivers || (DriverObject->Flags & DRVO_LEGACY_DRIVER)))
1437 {
1438 /* Loop through each device object of the driver
1439 and set DOE_UNLOAD_PENDING flag */
1440 DeviceObject = DriverObject->DeviceObject;
1441 while (DeviceObject)
1442 {
1443 /* Set the unload pending flag for the device */
1444 DeviceExtension = IoGetDevObjExtension(DeviceObject);
1445 DeviceExtension->ExtensionFlags |= DOE_UNLOAD_PENDING;
1446
1447 /* Make sure there are no attached devices or no reference counts */
1448 if ((DeviceObject->ReferenceCount) || (DeviceObject->AttachedDevice))
1449 {
1450 /* Not safe to unload */
1451 DPRINT1("Drivers device object is referenced or has attached devices\n");
1452
1453 SafeToUnload = FALSE;
1454 }
1455
1456 DeviceObject = DeviceObject->NextDevice;
1457 }
1458
1459 /* If not safe to unload, then return success */
1460 if (!SafeToUnload)
1461 {
1462 ObDereferenceObject(DriverObject);
1463 return STATUS_SUCCESS;
1464 }
1465
1466 DPRINT1("Unloading driver '%wZ' (manual)\n", &DriverObject->DriverName);
1467
1468 /* Set the unload invoked flag and call the unload routine */
1469 DriverObject->Flags |= DRVO_UNLOAD_INVOKED;
1470 Status = IopDoLoadUnloadDriver(NULL, &DriverObject);
1471 ASSERT(Status == STATUS_SUCCESS);
1472
1473 /* Mark the driver object temporary, so it could be deleted later */
1474 ObMakeTemporaryObject(DriverObject);
1475
1476 /* Dereference it 2 times */
1477 ObDereferenceObject(DriverObject);
1478 ObDereferenceObject(DriverObject);
1479
1480 return Status;
1481 }
1482 else
1483 {
1484 DPRINT1("No DriverUnload function! '%wZ' will not be unloaded!\n", &DriverObject->DriverName);
1485
1486 /* Dereference one time (refd inside this function) */
1487 ObDereferenceObject(DriverObject);
1488
1489 /* Return unloading failure */
1490 return STATUS_INVALID_DEVICE_REQUEST;
1491 }
1492 }
1493
1494 VOID
1495 NTAPI
IopReinitializeDrivers(VOID)1496 IopReinitializeDrivers(VOID)
1497 {
1498 PDRIVER_REINIT_ITEM ReinitItem;
1499 PLIST_ENTRY Entry;
1500
1501 /* Get the first entry and start looping */
1502 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1503 &DriverReinitListLock);
1504 while (Entry)
1505 {
1506 /* Get the item */
1507 ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1508
1509 /* Increment reinitialization counter */
1510 ReinitItem->DriverObject->DriverExtension->Count++;
1511
1512 /* Remove the device object flag */
1513 ReinitItem->DriverObject->Flags &= ~DRVO_REINIT_REGISTERED;
1514
1515 /* Call the routine */
1516 ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1517 ReinitItem->Context,
1518 ReinitItem->DriverObject->
1519 DriverExtension->Count);
1520
1521 /* Free the entry */
1522 ExFreePool(Entry);
1523
1524 /* Move to the next one */
1525 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1526 &DriverReinitListLock);
1527 }
1528 }
1529
1530 VOID
1531 NTAPI
IopReinitializeBootDrivers(VOID)1532 IopReinitializeBootDrivers(VOID)
1533 {
1534 PDRIVER_REINIT_ITEM ReinitItem;
1535 PLIST_ENTRY Entry;
1536
1537 /* Get the first entry and start looping */
1538 Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
1539 &DriverBootReinitListLock);
1540 while (Entry)
1541 {
1542 /* Get the item */
1543 ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1544
1545 /* Increment reinitialization counter */
1546 ReinitItem->DriverObject->DriverExtension->Count++;
1547
1548 /* Remove the device object flag */
1549 ReinitItem->DriverObject->Flags &= ~DRVO_BOOTREINIT_REGISTERED;
1550
1551 /* Call the routine */
1552 ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1553 ReinitItem->Context,
1554 ReinitItem->DriverObject->
1555 DriverExtension->Count);
1556
1557 /* Free the entry */
1558 ExFreePool(Entry);
1559
1560 /* Move to the next one */
1561 Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
1562 &DriverBootReinitListLock);
1563 }
1564
1565 /* Wait for all device actions being finished*/
1566 KeWaitForSingleObject(&PiEnumerationFinished, Executive, KernelMode, FALSE, NULL);
1567 }
1568
1569 /* PUBLIC FUNCTIONS ***********************************************************/
1570
1571 /*
1572 * @implemented
1573 */
1574 NTSTATUS
1575 NTAPI
IoCreateDriver(_In_opt_ PUNICODE_STRING DriverName,_In_ PDRIVER_INITIALIZE InitializationFunction)1576 IoCreateDriver(
1577 _In_opt_ PUNICODE_STRING DriverName,
1578 _In_ PDRIVER_INITIALIZE InitializationFunction)
1579 {
1580 WCHAR NameBuffer[100];
1581 USHORT NameLength;
1582 UNICODE_STRING LocalDriverName;
1583 NTSTATUS Status;
1584 OBJECT_ATTRIBUTES ObjectAttributes;
1585 ULONG ObjectSize;
1586 PDRIVER_OBJECT DriverObject;
1587 UNICODE_STRING ServiceKeyName;
1588 HANDLE hDriver;
1589 ULONG i, RetryCount = 0;
1590
1591 try_again:
1592 /* First, create a unique name for the driver if we don't have one */
1593 if (!DriverName)
1594 {
1595 /* Create a random name and set up the string */
1596 NameLength = (USHORT)swprintf(NameBuffer,
1597 DRIVER_ROOT_NAME L"%08u",
1598 KeTickCount.LowPart);
1599 LocalDriverName.Length = NameLength * sizeof(WCHAR);
1600 LocalDriverName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL);
1601 LocalDriverName.Buffer = NameBuffer;
1602 }
1603 else
1604 {
1605 /* So we can avoid another code path, use a local var */
1606 LocalDriverName = *DriverName;
1607 }
1608
1609 /* Initialize the Attributes */
1610 ObjectSize = sizeof(DRIVER_OBJECT) + sizeof(EXTENDED_DRIVER_EXTENSION);
1611 InitializeObjectAttributes(&ObjectAttributes,
1612 &LocalDriverName,
1613 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1614 NULL,
1615 NULL);
1616
1617 /* Create the Object */
1618 Status = ObCreateObject(KernelMode,
1619 IoDriverObjectType,
1620 &ObjectAttributes,
1621 KernelMode,
1622 NULL,
1623 ObjectSize,
1624 0,
1625 0,
1626 (PVOID*)&DriverObject);
1627 if (!NT_SUCCESS(Status)) return Status;
1628
1629 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject);
1630
1631 /* Set up the Object */
1632 RtlZeroMemory(DriverObject, ObjectSize);
1633 DriverObject->Type = IO_TYPE_DRIVER;
1634 DriverObject->Size = sizeof(DRIVER_OBJECT);
1635 DriverObject->Flags = DRVO_BUILTIN_DRIVER;
1636 DriverObject->DriverExtension = (PDRIVER_EXTENSION)(DriverObject + 1);
1637 DriverObject->DriverExtension->DriverObject = DriverObject;
1638 DriverObject->DriverInit = InitializationFunction;
1639 /* Loop all Major Functions */
1640 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1641 {
1642 /* Invalidate each function */
1643 DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1644 }
1645
1646 /* Set up the service key name buffer */
1647 ServiceKeyName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL);
1648 ServiceKeyName.Buffer = ExAllocatePoolWithTag(PagedPool, LocalDriverName.MaximumLength, TAG_IO);
1649 if (!ServiceKeyName.Buffer)
1650 {
1651 /* Fail */
1652 ObMakeTemporaryObject(DriverObject);
1653 ObDereferenceObject(DriverObject);
1654 return STATUS_INSUFFICIENT_RESOURCES;
1655 }
1656
1657 /* For builtin drivers, the ServiceKeyName is equal to DriverName */
1658 RtlCopyUnicodeString(&ServiceKeyName, &LocalDriverName);
1659 ServiceKeyName.Buffer[ServiceKeyName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1660 DriverObject->DriverExtension->ServiceKeyName = ServiceKeyName;
1661
1662 /* Make a copy of the driver name to store in the driver object */
1663 DriverObject->DriverName.MaximumLength = LocalDriverName.Length;
1664 DriverObject->DriverName.Buffer = ExAllocatePoolWithTag(PagedPool,
1665 DriverObject->DriverName.MaximumLength,
1666 TAG_IO);
1667 if (!DriverObject->DriverName.Buffer)
1668 {
1669 /* Fail */
1670 ObMakeTemporaryObject(DriverObject);
1671 ObDereferenceObject(DriverObject);
1672 return STATUS_INSUFFICIENT_RESOURCES;
1673 }
1674
1675 RtlCopyUnicodeString(&DriverObject->DriverName, &LocalDriverName);
1676
1677 /* Add the Object and get its handle */
1678 Status = ObInsertObject(DriverObject,
1679 NULL,
1680 FILE_READ_DATA,
1681 0,
1682 NULL,
1683 &hDriver);
1684
1685 /* Eliminate small possibility when this function is called more than
1686 once in a row, and KeTickCount doesn't get enough time to change */
1687 if (!DriverName && (Status == STATUS_OBJECT_NAME_COLLISION) && (RetryCount < 100))
1688 {
1689 RetryCount++;
1690 goto try_again;
1691 }
1692
1693 if (!NT_SUCCESS(Status)) return Status;
1694
1695 /* Now reference it */
1696 Status = ObReferenceObjectByHandle(hDriver,
1697 0,
1698 IoDriverObjectType,
1699 KernelMode,
1700 (PVOID*)&DriverObject,
1701 NULL);
1702
1703 /* Close the extra handle */
1704 ZwClose(hDriver);
1705
1706 if (!NT_SUCCESS(Status))
1707 {
1708 /* Fail */
1709 ObMakeTemporaryObject(DriverObject);
1710 ObDereferenceObject(DriverObject);
1711 return Status;
1712 }
1713
1714 /* Finally, call its init function */
1715 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction);
1716 Status = InitializationFunction(DriverObject, NULL);
1717 if (!NT_SUCCESS(Status))
1718 {
1719 /* If it didn't work, then kill the object */
1720 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", &LocalDriverName, Status);
1721 ObMakeTemporaryObject(DriverObject);
1722 ObDereferenceObject(DriverObject);
1723 return Status;
1724 }
1725
1726 /* Windows does this fixup, keep it for compatibility */
1727 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1728 {
1729 /*
1730 * Make sure the driver didn't set any dispatch entry point to NULL!
1731 * Doing so is illegal; drivers shouldn't touch entry points they
1732 * do not implement.
1733 */
1734
1735 /* Check if it did so anyway */
1736 if (!DriverObject->MajorFunction[i])
1737 {
1738 /* Print a warning in the debug log */
1739 DPRINT1("Driver <%wZ> set DriverObject->MajorFunction[%lu] to NULL!\n",
1740 &DriverObject->DriverName, i);
1741
1742 /* Fix it up */
1743 DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1744 }
1745 }
1746
1747 /* Return the Status */
1748 return Status;
1749 }
1750
1751 /*
1752 * @implemented
1753 */
1754 VOID
1755 NTAPI
IoDeleteDriver(_In_ PDRIVER_OBJECT DriverObject)1756 IoDeleteDriver(
1757 _In_ PDRIVER_OBJECT DriverObject)
1758 {
1759 /* Simply dereference the Object */
1760 ObDereferenceObject(DriverObject);
1761 }
1762
1763 /*
1764 * @implemented
1765 */
1766 VOID
1767 NTAPI
IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject,IN PDRIVER_REINITIALIZE ReinitRoutine,IN PVOID Context)1768 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
1769 IN PDRIVER_REINITIALIZE ReinitRoutine,
1770 IN PVOID Context)
1771 {
1772 PDRIVER_REINIT_ITEM ReinitItem;
1773
1774 /* Allocate the entry */
1775 ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
1776 sizeof(DRIVER_REINIT_ITEM),
1777 TAG_REINIT);
1778 if (!ReinitItem) return;
1779
1780 /* Fill it out */
1781 ReinitItem->DriverObject = DriverObject;
1782 ReinitItem->ReinitRoutine = ReinitRoutine;
1783 ReinitItem->Context = Context;
1784
1785 /* Set the Driver Object flag and insert the entry into the list */
1786 DriverObject->Flags |= DRVO_BOOTREINIT_REGISTERED;
1787 ExInterlockedInsertTailList(&DriverBootReinitListHead,
1788 &ReinitItem->ItemEntry,
1789 &DriverBootReinitListLock);
1790 }
1791
1792 /*
1793 * @implemented
1794 */
1795 VOID
1796 NTAPI
IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject,IN PDRIVER_REINITIALIZE ReinitRoutine,IN PVOID Context)1797 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
1798 IN PDRIVER_REINITIALIZE ReinitRoutine,
1799 IN PVOID Context)
1800 {
1801 PDRIVER_REINIT_ITEM ReinitItem;
1802
1803 /* Allocate the entry */
1804 ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
1805 sizeof(DRIVER_REINIT_ITEM),
1806 TAG_REINIT);
1807 if (!ReinitItem) return;
1808
1809 /* Fill it out */
1810 ReinitItem->DriverObject = DriverObject;
1811 ReinitItem->ReinitRoutine = ReinitRoutine;
1812 ReinitItem->Context = Context;
1813
1814 /* Set the Driver Object flag and insert the entry into the list */
1815 DriverObject->Flags |= DRVO_REINIT_REGISTERED;
1816 ExInterlockedInsertTailList(&DriverReinitListHead,
1817 &ReinitItem->ItemEntry,
1818 &DriverReinitListLock);
1819 }
1820
1821 /*
1822 * @implemented
1823 */
1824 NTSTATUS
1825 NTAPI
IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,IN PVOID ClientIdentificationAddress,IN ULONG DriverObjectExtensionSize,OUT PVOID * DriverObjectExtension)1826 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
1827 IN PVOID ClientIdentificationAddress,
1828 IN ULONG DriverObjectExtensionSize,
1829 OUT PVOID *DriverObjectExtension)
1830 {
1831 KIRQL OldIrql;
1832 PIO_CLIENT_EXTENSION DriverExtensions, NewDriverExtension;
1833 BOOLEAN Inserted = FALSE;
1834
1835 /* Assume failure */
1836 *DriverObjectExtension = NULL;
1837
1838 /* Allocate the extension */
1839 NewDriverExtension = ExAllocatePoolWithTag(NonPagedPool,
1840 sizeof(IO_CLIENT_EXTENSION) +
1841 DriverObjectExtensionSize,
1842 TAG_DRIVER_EXTENSION);
1843 if (!NewDriverExtension) return STATUS_INSUFFICIENT_RESOURCES;
1844
1845 /* Clear the extension for teh caller */
1846 RtlZeroMemory(NewDriverExtension,
1847 sizeof(IO_CLIENT_EXTENSION) + DriverObjectExtensionSize);
1848
1849 /* Acqure lock */
1850 OldIrql = KeRaiseIrqlToDpcLevel();
1851
1852 /* Fill out the extension */
1853 NewDriverExtension->ClientIdentificationAddress = ClientIdentificationAddress;
1854
1855 /* Loop the current extensions */
1856 DriverExtensions = IoGetDrvObjExtension(DriverObject)->
1857 ClientDriverExtension;
1858 while (DriverExtensions)
1859 {
1860 /* Check if the identifier matches */
1861 if (DriverExtensions->ClientIdentificationAddress ==
1862 ClientIdentificationAddress)
1863 {
1864 /* We have a collision, break out */
1865 break;
1866 }
1867
1868 /* Go to the next one */
1869 DriverExtensions = DriverExtensions->NextExtension;
1870 }
1871
1872 /* Check if we didn't collide */
1873 if (!DriverExtensions)
1874 {
1875 /* Link this one in */
1876 NewDriverExtension->NextExtension =
1877 IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
1878 IoGetDrvObjExtension(DriverObject)->ClientDriverExtension =
1879 NewDriverExtension;
1880 Inserted = TRUE;
1881 }
1882
1883 /* Release the lock */
1884 KeLowerIrql(OldIrql);
1885
1886 /* Check if insertion failed */
1887 if (!Inserted)
1888 {
1889 /* Free the entry and fail */
1890 ExFreePoolWithTag(NewDriverExtension, TAG_DRIVER_EXTENSION);
1891 return STATUS_OBJECT_NAME_COLLISION;
1892 }
1893
1894 /* Otherwise, return the pointer */
1895 *DriverObjectExtension = NewDriverExtension + 1;
1896 return STATUS_SUCCESS;
1897 }
1898
1899 /*
1900 * @implemented
1901 */
1902 PVOID
1903 NTAPI
IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,IN PVOID ClientIdentificationAddress)1904 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
1905 IN PVOID ClientIdentificationAddress)
1906 {
1907 KIRQL OldIrql;
1908 PIO_CLIENT_EXTENSION DriverExtensions;
1909
1910 /* Acquire lock */
1911 OldIrql = KeRaiseIrqlToDpcLevel();
1912
1913 /* Loop the list until we find the right one */
1914 DriverExtensions = IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
1915 while (DriverExtensions)
1916 {
1917 /* Check for a match */
1918 if (DriverExtensions->ClientIdentificationAddress ==
1919 ClientIdentificationAddress)
1920 {
1921 /* Break out */
1922 break;
1923 }
1924
1925 /* Keep looping */
1926 DriverExtensions = DriverExtensions->NextExtension;
1927 }
1928
1929 /* Release lock */
1930 KeLowerIrql(OldIrql);
1931
1932 /* Return nothing or the extension */
1933 if (!DriverExtensions) return NULL;
1934 return DriverExtensions + 1;
1935 }
1936
1937 NTSTATUS
IopLoadDriver(_In_ HANDLE ServiceHandle,_Out_ PDRIVER_OBJECT * DriverObject)1938 IopLoadDriver(
1939 _In_ HANDLE ServiceHandle,
1940 _Out_ PDRIVER_OBJECT *DriverObject)
1941 {
1942 UNICODE_STRING ImagePath;
1943 NTSTATUS Status;
1944 PLDR_DATA_TABLE_ENTRY ModuleObject;
1945 PVOID BaseAddress;
1946
1947 PKEY_VALUE_FULL_INFORMATION kvInfo;
1948 Status = IopGetRegistryValue(ServiceHandle, L"ImagePath", &kvInfo);
1949 if (NT_SUCCESS(Status))
1950 {
1951 if ((kvInfo->Type != REG_EXPAND_SZ && kvInfo->Type != REG_SZ) || kvInfo->DataLength == 0)
1952 {
1953 ExFreePool(kvInfo);
1954 return STATUS_ILL_FORMED_SERVICE_ENTRY;
1955 }
1956
1957 ImagePath.Length = kvInfo->DataLength - sizeof(UNICODE_NULL);
1958 ImagePath.MaximumLength = kvInfo->DataLength;
1959 ImagePath.Buffer = ExAllocatePoolWithTag(PagedPool, ImagePath.MaximumLength, TAG_RTLREGISTRY);
1960 if (!ImagePath.Buffer)
1961 {
1962 ExFreePool(kvInfo);
1963 return STATUS_INSUFFICIENT_RESOURCES;
1964 }
1965
1966 RtlMoveMemory(ImagePath.Buffer,
1967 (PVOID)((ULONG_PTR)kvInfo + kvInfo->DataOffset),
1968 ImagePath.Length);
1969 ImagePath.Buffer[ImagePath.Length / sizeof(WCHAR)] = UNICODE_NULL;
1970 ExFreePool(kvInfo);
1971 }
1972 else
1973 {
1974 return Status;
1975 }
1976
1977 /*
1978 * Normalize the image path for all later processing.
1979 */
1980 Status = IopNormalizeImagePath(&ImagePath, NULL);
1981 if (!NT_SUCCESS(Status))
1982 {
1983 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
1984 return Status;
1985 }
1986
1987 DPRINT("FullImagePath: '%wZ'\n", &ImagePath);
1988
1989 KeEnterCriticalRegion();
1990 ExAcquireResourceExclusiveLite(&IopDriverLoadResource, TRUE);
1991
1992 /*
1993 * Load the driver module
1994 */
1995 DPRINT("Loading module from %wZ\n", &ImagePath);
1996 Status = MmLoadSystemImage(&ImagePath, NULL, NULL, 0, (PVOID)&ModuleObject, &BaseAddress);
1997 RtlFreeUnicodeString(&ImagePath);
1998
1999 if (!NT_SUCCESS(Status))
2000 {
2001 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status);
2002 ExReleaseResourceLite(&IopDriverLoadResource);
2003 KeLeaveCriticalRegion();
2004 return Status;
2005 }
2006
2007 // Display the loading message
2008 ULONG infoLength;
2009 Status = ZwQueryKey(ServiceHandle, KeyBasicInformation, NULL, 0, &infoLength);
2010 if (Status == STATUS_BUFFER_TOO_SMALL)
2011 {
2012 PKEY_BASIC_INFORMATION servName = ExAllocatePoolWithTag(PagedPool, infoLength, TAG_IO);
2013 if (servName)
2014 {
2015 Status = ZwQueryKey(ServiceHandle,
2016 KeyBasicInformation,
2017 servName,
2018 infoLength,
2019 &infoLength);
2020 if (NT_SUCCESS(Status))
2021 {
2022 UNICODE_STRING serviceName = {
2023 .Length = servName->NameLength,
2024 .MaximumLength = servName->NameLength,
2025 .Buffer = servName->Name
2026 };
2027
2028 IopDisplayLoadingMessage(&serviceName);
2029 }
2030 ExFreePoolWithTag(servName, TAG_IO);
2031 }
2032 }
2033
2034 NTSTATUS driverEntryStatus;
2035 Status = IopInitializeDriverModule(ModuleObject,
2036 ServiceHandle,
2037 DriverObject,
2038 &driverEntryStatus);
2039 if (!NT_SUCCESS(Status))
2040 {
2041 DPRINT1("IopInitializeDriverModule() failed (Status %lx)\n", Status);
2042 }
2043
2044 ExReleaseResourceLite(&IopDriverLoadResource);
2045 KeLeaveCriticalRegion();
2046
2047 return Status;
2048 }
2049
2050 static
2051 VOID
2052 NTAPI
IopLoadUnloadDriverWorker(_Inout_ PVOID Parameter)2053 IopLoadUnloadDriverWorker(
2054 _Inout_ PVOID Parameter)
2055 {
2056 PLOAD_UNLOAD_PARAMS LoadParams = Parameter;
2057
2058 ASSERT(PsGetCurrentProcess() == PsInitialSystemProcess);
2059
2060 if (LoadParams->DriverObject)
2061 {
2062 // unload request
2063 LoadParams->DriverObject->DriverUnload(LoadParams->DriverObject);
2064 LoadParams->Status = STATUS_SUCCESS;
2065 }
2066 else
2067 {
2068 // load request
2069 HANDLE serviceHandle;
2070 NTSTATUS status;
2071 status = IopOpenRegistryKeyEx(&serviceHandle, NULL, LoadParams->RegistryPath, KEY_READ);
2072 if (!NT_SUCCESS(status))
2073 {
2074 LoadParams->Status = status;
2075 }
2076 else
2077 {
2078 LoadParams->Status = IopLoadDriver(serviceHandle, &LoadParams->DriverObject);
2079 ZwClose(serviceHandle);
2080 }
2081 }
2082
2083 if (LoadParams->SetEvent)
2084 {
2085 KeSetEvent(&LoadParams->Event, 0, FALSE);
2086 }
2087 }
2088
2089 /**
2090 * @brief Process load and unload driver operations. This is mostly for NtLoadDriver
2091 * and NtUnloadDriver, because their code should run inside PsInitialSystemProcess
2092 *
2093 * @param[in] RegistryPath The registry path
2094 * @param DriverObject The driver object
2095 *
2096 * @return Status of the operation
2097 */
2098 NTSTATUS
IopDoLoadUnloadDriver(_In_opt_ PUNICODE_STRING RegistryPath,_Inout_ PDRIVER_OBJECT * DriverObject)2099 IopDoLoadUnloadDriver(
2100 _In_opt_ PUNICODE_STRING RegistryPath,
2101 _Inout_ PDRIVER_OBJECT *DriverObject)
2102 {
2103 LOAD_UNLOAD_PARAMS LoadParams;
2104
2105 /* Prepare parameters block */
2106 LoadParams.RegistryPath = RegistryPath;
2107 LoadParams.DriverObject = *DriverObject;
2108
2109 if (PsGetCurrentProcess() != PsInitialSystemProcess)
2110 {
2111 LoadParams.SetEvent = TRUE;
2112 KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE);
2113
2114 /* Initialize and queue a work item */
2115 ExInitializeWorkItem(&LoadParams.WorkItem, IopLoadUnloadDriverWorker, &LoadParams);
2116 ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue);
2117
2118 /* And wait till it completes */
2119 KeWaitForSingleObject(&LoadParams.Event, UserRequest, KernelMode, FALSE, NULL);
2120 }
2121 else
2122 {
2123 /* If we're already in a system process, call it right here */
2124 LoadParams.SetEvent = FALSE;
2125 IopLoadUnloadDriverWorker(&LoadParams);
2126 }
2127
2128 return LoadParams.Status;
2129 }
2130
2131 /*
2132 * NtLoadDriver
2133 *
2134 * Loads a device driver.
2135 *
2136 * Parameters
2137 * DriverServiceName
2138 * Name of the service to load (registry key).
2139 *
2140 * Return Value
2141 * Status
2142 *
2143 * Status
2144 * implemented
2145 */
2146 NTSTATUS NTAPI
NtLoadDriver(IN PUNICODE_STRING DriverServiceName)2147 NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
2148 {
2149 UNICODE_STRING CapturedServiceName = { 0, 0, NULL };
2150 KPROCESSOR_MODE PreviousMode;
2151 PDRIVER_OBJECT DriverObject;
2152 NTSTATUS Status;
2153
2154 PAGED_CODE();
2155
2156 PreviousMode = KeGetPreviousMode();
2157
2158 /* Need the appropriate priviliege */
2159 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
2160 {
2161 DPRINT1("No load privilege!\n");
2162 return STATUS_PRIVILEGE_NOT_HELD;
2163 }
2164
2165 /* Capture the service name */
2166 Status = ProbeAndCaptureUnicodeString(&CapturedServiceName,
2167 PreviousMode,
2168 DriverServiceName);
2169 if (!NT_SUCCESS(Status))
2170 {
2171 return Status;
2172 }
2173
2174 DPRINT("NtLoadDriver('%wZ')\n", &CapturedServiceName);
2175
2176 /* We need a service name */
2177 if (CapturedServiceName.Length == 0 || CapturedServiceName.Buffer == NULL)
2178 {
2179 ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
2180 return STATUS_INVALID_PARAMETER;
2181 }
2182
2183 /* Load driver and call its entry point */
2184 DriverObject = NULL;
2185 Status = IopDoLoadUnloadDriver(&CapturedServiceName, &DriverObject);
2186
2187 ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
2188 return Status;
2189 }
2190
2191 /*
2192 * NtUnloadDriver
2193 *
2194 * Unloads a legacy device driver.
2195 *
2196 * Parameters
2197 * DriverServiceName
2198 * Name of the service to unload (registry key).
2199 *
2200 * Return Value
2201 * Status
2202 *
2203 * Status
2204 * implemented
2205 */
2206
2207 NTSTATUS NTAPI
NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)2208 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)
2209 {
2210 return IopUnloadDriver(DriverServiceName, FALSE);
2211 }
2212
2213 /* EOF */
2214