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