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