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) ASSERT(FALSE); 1026 1027 /* Allocate the group table */ 1028 IopGroupTable = ExAllocatePoolWithTag(PagedPool, 1029 IopGroupIndex * sizeof(LIST_ENTRY), 1030 TAG_IO); 1031 if (IopGroupTable == NULL) ASSERT(FALSE); 1032 1033 /* Initialize the group table lists */ 1034 for (i = 0; i < IopGroupIndex; i++) InitializeListHead(&IopGroupTable[i]); 1035 1036 /* Loop the boot modules */ 1037 ListHead = &KeLoaderBlock->LoadOrderListHead; 1038 for (NextEntry = ListHead->Flink; 1039 NextEntry != ListHead; 1040 NextEntry = NextEntry->Flink) 1041 { 1042 /* Get the entry */ 1043 LdrEntry = CONTAINING_RECORD(NextEntry, 1044 LDR_DATA_TABLE_ENTRY, 1045 InLoadOrderLinks); 1046 1047 /* Check if the DLL needs to be initialized */ 1048 if (LdrEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL) 1049 { 1050 /* Call its entrypoint */ 1051 MmCallDllInitialize(LdrEntry, NULL); 1052 } 1053 } 1054 1055 /* Loop the boot drivers */ 1056 ListHead = &KeLoaderBlock->BootDriverListHead; 1057 for (NextEntry = ListHead->Flink; 1058 NextEntry != ListHead; 1059 NextEntry = NextEntry->Flink) 1060 { 1061 /* Get the entry */ 1062 BootEntry = CONTAINING_RECORD(NextEntry, 1063 BOOT_DRIVER_LIST_ENTRY, 1064 Link); 1065 1066 // FIXME: TODO: This LdrEntry is to be used in a special handling 1067 // for SETUPLDR (a similar procedure is done on Windows), where 1068 // the loader would, under certain conditions, be loaded in the 1069 // SETUPLDR-specific code block below... 1070 #if 0 1071 /* Get the driver loader entry */ 1072 LdrEntry = BootEntry->LdrEntry; 1073 #endif 1074 1075 /* Allocate our internal accounting structure */ 1076 DriverInfo = ExAllocatePoolWithTag(PagedPool, 1077 sizeof(DRIVER_INFORMATION), 1078 TAG_IO); 1079 if (DriverInfo) 1080 { 1081 /* Zero it and initialize it */ 1082 RtlZeroMemory(DriverInfo, sizeof(DRIVER_INFORMATION)); 1083 InitializeListHead(&DriverInfo->Link); 1084 DriverInfo->DataTableEntry = BootEntry; 1085 1086 /* Open the registry key */ 1087 Status = IopOpenRegistryKeyEx(&KeyHandle, 1088 NULL, 1089 &BootEntry->RegistryPath, 1090 KEY_READ); 1091 DPRINT("IopOpenRegistryKeyEx(%wZ) returned 0x%08lx\n", &BootEntry->RegistryPath, Status); 1092 #if 0 1093 if (NT_SUCCESS(Status)) 1094 #else // Hack still needed... 1095 if ((NT_SUCCESS(Status)) || /* ReactOS HACK for SETUPLDR */ 1096 ((KeLoaderBlock->SetupLdrBlock) && ((KeyHandle = (PVOID)1)))) // yes, it's an assignment! 1097 #endif 1098 { 1099 /* Save the handle */ 1100 DriverInfo->ServiceHandle = KeyHandle; 1101 1102 /* Get the group oder index */ 1103 Index = PpInitGetGroupOrderIndex(KeyHandle); 1104 1105 /* Get the tag position */ 1106 DriverInfo->TagPosition = PipGetDriverTagPriority(KeyHandle); 1107 1108 /* Insert it into the list, at the right place */ 1109 ASSERT(Index < IopGroupIndex); 1110 NextEntry2 = IopGroupTable[Index].Flink; 1111 while (NextEntry2 != &IopGroupTable[Index]) 1112 { 1113 /* Get the driver info */ 1114 DriverInfoTag = CONTAINING_RECORD(NextEntry2, 1115 DRIVER_INFORMATION, 1116 Link); 1117 1118 /* Check if we found the right tag position */ 1119 if (DriverInfoTag->TagPosition > DriverInfo->TagPosition) 1120 { 1121 /* We're done */ 1122 break; 1123 } 1124 1125 /* Next entry */ 1126 NextEntry2 = NextEntry2->Flink; 1127 } 1128 1129 /* Insert us right before the next entry */ 1130 NextEntry2 = NextEntry2->Blink; 1131 InsertHeadList(NextEntry2, &DriverInfo->Link); 1132 } 1133 } 1134 } 1135 1136 /* Loop each group index */ 1137 for (i = 0; i < IopGroupIndex; i++) 1138 { 1139 /* Loop each group table */ 1140 for (NextEntry = IopGroupTable[i].Flink; 1141 NextEntry != &IopGroupTable[i]; 1142 NextEntry = NextEntry->Flink) 1143 { 1144 /* Get the entry */ 1145 DriverInfo = CONTAINING_RECORD(NextEntry, 1146 DRIVER_INFORMATION, 1147 Link); 1148 1149 /* Get the driver loader entry */ 1150 LdrEntry = DriverInfo->DataTableEntry->LdrEntry; 1151 1152 /* Initialize it */ 1153 if (IopInitializeBuiltinDriver(LdrEntry)) 1154 { 1155 // it does not make sense to enumerate the tree if there are no new devices added 1156 PiQueueDeviceAction(IopRootDeviceNode->PhysicalDeviceObject, 1157 PiActionEnumRootDevices, 1158 NULL, 1159 NULL); 1160 } 1161 } 1162 } 1163 1164 /* HAL Root Bus is being initialized before loading the boot drivers so this may cause issues 1165 * when some devices are not being initialized with their drivers. This flag is used to delay 1166 * all actions with devices (except PnP root device) until boot drivers are loaded. 1167 * See PiQueueDeviceAction function 1168 */ 1169 PnPBootDriversLoaded = TRUE; 1170 1171 DbgPrint("BOOT DRIVERS LOADED\n"); 1172 1173 PiQueueDeviceAction(IopRootDeviceNode->PhysicalDeviceObject, 1174 PiActionEnumDeviceTree, 1175 NULL, 1176 NULL); 1177 } 1178 1179 CODE_SEG("INIT") 1180 VOID 1181 FASTCALL 1182 IopInitializeSystemDrivers(VOID) 1183 { 1184 PUNICODE_STRING *DriverList, *SavedList; 1185 1186 PiPerformSyncDeviceAction(IopRootDeviceNode->PhysicalDeviceObject, PiActionEnumDeviceTree); 1187 1188 /* No system drivers on the boot cd */ 1189 if (KeLoaderBlock->SetupLdrBlock) return; // ExpInTextModeSetup 1190 1191 /* Get the driver list */ 1192 SavedList = DriverList = CmGetSystemDriverList(); 1193 ASSERT(DriverList); 1194 1195 /* Loop it */ 1196 while (*DriverList) 1197 { 1198 /* Load the driver */ 1199 ZwLoadDriver(*DriverList); 1200 1201 /* Free the entry */ 1202 RtlFreeUnicodeString(*DriverList); 1203 ExFreePool(*DriverList); 1204 1205 /* Next entry */ 1206 InbvIndicateProgress(); 1207 DriverList++; 1208 } 1209 1210 /* Free the list */ 1211 ExFreePool(SavedList); 1212 1213 PiQueueDeviceAction(IopRootDeviceNode->PhysicalDeviceObject, 1214 PiActionEnumDeviceTree, 1215 NULL, 1216 NULL); 1217 } 1218 1219 /* 1220 * IopUnloadDriver 1221 * 1222 * Unloads a device driver. 1223 * 1224 * Parameters 1225 * DriverServiceName 1226 * Name of the service to unload (registry key). 1227 * 1228 * UnloadPnpDrivers 1229 * Whether to unload Plug & Plug or only legacy drivers. If this 1230 * parameter is set to FALSE, the routine will unload only legacy 1231 * drivers. 1232 * 1233 * Return Value 1234 * Status 1235 * 1236 * To do 1237 * Guard the whole function by SEH. 1238 */ 1239 1240 NTSTATUS NTAPI 1241 IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers) 1242 { 1243 UNICODE_STRING Backslash = RTL_CONSTANT_STRING(L"\\"); 1244 RTL_QUERY_REGISTRY_TABLE QueryTable[2]; 1245 UNICODE_STRING ImagePath; 1246 UNICODE_STRING ServiceName; 1247 UNICODE_STRING ObjectName; 1248 PDRIVER_OBJECT DriverObject; 1249 PDEVICE_OBJECT DeviceObject; 1250 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 1251 NTSTATUS Status; 1252 USHORT LastBackslash; 1253 BOOLEAN SafeToUnload = TRUE; 1254 KPROCESSOR_MODE PreviousMode; 1255 UNICODE_STRING CapturedServiceName; 1256 1257 PAGED_CODE(); 1258 1259 PreviousMode = ExGetPreviousMode(); 1260 1261 /* Need the appropriate priviliege */ 1262 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode)) 1263 { 1264 DPRINT1("No unload privilege!\n"); 1265 return STATUS_PRIVILEGE_NOT_HELD; 1266 } 1267 1268 /* Capture the service name */ 1269 Status = ProbeAndCaptureUnicodeString(&CapturedServiceName, 1270 PreviousMode, 1271 DriverServiceName); 1272 if (!NT_SUCCESS(Status)) 1273 { 1274 return Status; 1275 } 1276 1277 DPRINT("IopUnloadDriver('%wZ', %u)\n", &CapturedServiceName, UnloadPnpDrivers); 1278 1279 /* We need a service name */ 1280 if (CapturedServiceName.Length == 0 || CapturedServiceName.Buffer == NULL) 1281 { 1282 ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode); 1283 return STATUS_INVALID_PARAMETER; 1284 } 1285 1286 /* 1287 * Get the service name from the registry key name 1288 */ 1289 Status = RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END, 1290 &CapturedServiceName, 1291 &Backslash, 1292 &LastBackslash); 1293 if (NT_SUCCESS(Status)) 1294 { 1295 NT_ASSERT(CapturedServiceName.Length >= LastBackslash + sizeof(WCHAR)); 1296 ServiceName.Buffer = &CapturedServiceName.Buffer[LastBackslash / sizeof(WCHAR) + 1]; 1297 ServiceName.Length = CapturedServiceName.Length - LastBackslash - sizeof(WCHAR); 1298 ServiceName.MaximumLength = CapturedServiceName.MaximumLength - LastBackslash - sizeof(WCHAR); 1299 } 1300 else 1301 { 1302 ServiceName = CapturedServiceName; 1303 } 1304 1305 /* 1306 * Construct the driver object name 1307 */ 1308 Status = RtlUShortAdd(sizeof(DRIVER_ROOT_NAME), 1309 ServiceName.Length, 1310 &ObjectName.MaximumLength); 1311 if (!NT_SUCCESS(Status)) 1312 { 1313 ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode); 1314 return Status; 1315 } 1316 ObjectName.Length = 0; 1317 ObjectName.Buffer = ExAllocatePoolWithTag(PagedPool, 1318 ObjectName.MaximumLength, 1319 TAG_IO); 1320 if (!ObjectName.Buffer) 1321 { 1322 ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode); 1323 return STATUS_INSUFFICIENT_RESOURCES; 1324 } 1325 NT_VERIFY(NT_SUCCESS(RtlAppendUnicodeToString(&ObjectName, DRIVER_ROOT_NAME))); 1326 NT_VERIFY(NT_SUCCESS(RtlAppendUnicodeStringToString(&ObjectName, &ServiceName))); 1327 1328 /* 1329 * Find the driver object 1330 */ 1331 Status = ObReferenceObjectByName(&ObjectName, 1332 0, 1333 0, 1334 0, 1335 IoDriverObjectType, 1336 KernelMode, 1337 0, 1338 (PVOID*)&DriverObject); 1339 1340 if (!NT_SUCCESS(Status)) 1341 { 1342 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName); 1343 ExFreePoolWithTag(ObjectName.Buffer, TAG_IO); 1344 ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode); 1345 return Status; 1346 } 1347 1348 /* Free the buffer for driver object name */ 1349 ExFreePoolWithTag(ObjectName.Buffer, TAG_IO); 1350 1351 /* Check that driver is not already unloading */ 1352 if (DriverObject->Flags & DRVO_UNLOAD_INVOKED) 1353 { 1354 DPRINT1("Driver deletion pending\n"); 1355 ObDereferenceObject(DriverObject); 1356 ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode); 1357 return STATUS_DELETE_PENDING; 1358 } 1359 1360 /* 1361 * Get path of service... 1362 */ 1363 RtlZeroMemory(QueryTable, sizeof(QueryTable)); 1364 1365 RtlInitUnicodeString(&ImagePath, NULL); 1366 1367 QueryTable[0].Name = L"ImagePath"; 1368 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; 1369 QueryTable[0].EntryContext = &ImagePath; 1370 1371 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 1372 CapturedServiceName.Buffer, 1373 QueryTable, 1374 NULL, 1375 NULL); 1376 1377 /* We no longer need service name */ 1378 ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode); 1379 1380 if (!NT_SUCCESS(Status)) 1381 { 1382 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status); 1383 ObDereferenceObject(DriverObject); 1384 return Status; 1385 } 1386 1387 /* 1388 * Normalize the image path for all later processing. 1389 */ 1390 Status = IopNormalizeImagePath(&ImagePath, &ServiceName); 1391 1392 if (!NT_SUCCESS(Status)) 1393 { 1394 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status); 1395 ObDereferenceObject(DriverObject); 1396 return Status; 1397 } 1398 1399 /* Free the service path */ 1400 ExFreePool(ImagePath.Buffer); 1401 1402 /* 1403 * Unload the module and release the references to the device object 1404 */ 1405 1406 /* Call the load/unload routine, depending on current process */ 1407 if (DriverObject->DriverUnload && DriverObject->DriverSection && 1408 (UnloadPnpDrivers || (DriverObject->Flags & DRVO_LEGACY_DRIVER))) 1409 { 1410 /* Loop through each device object of the driver 1411 and set DOE_UNLOAD_PENDING flag */ 1412 DeviceObject = DriverObject->DeviceObject; 1413 while (DeviceObject) 1414 { 1415 /* Set the unload pending flag for the device */ 1416 DeviceExtension = IoGetDevObjExtension(DeviceObject); 1417 DeviceExtension->ExtensionFlags |= DOE_UNLOAD_PENDING; 1418 1419 /* Make sure there are no attached devices or no reference counts */ 1420 if ((DeviceObject->ReferenceCount) || (DeviceObject->AttachedDevice)) 1421 { 1422 /* Not safe to unload */ 1423 DPRINT1("Drivers device object is referenced or has attached devices\n"); 1424 1425 SafeToUnload = FALSE; 1426 } 1427 1428 DeviceObject = DeviceObject->NextDevice; 1429 } 1430 1431 /* If not safe to unload, then return success */ 1432 if (!SafeToUnload) 1433 { 1434 ObDereferenceObject(DriverObject); 1435 return STATUS_SUCCESS; 1436 } 1437 1438 DPRINT1("Unloading driver '%wZ' (manual)\n", &DriverObject->DriverName); 1439 1440 /* Set the unload invoked flag and call the unload routine */ 1441 DriverObject->Flags |= DRVO_UNLOAD_INVOKED; 1442 Status = IopDoLoadUnloadDriver(NULL, &DriverObject); 1443 ASSERT(Status == STATUS_SUCCESS); 1444 1445 /* Mark the driver object temporary, so it could be deleted later */ 1446 ObMakeTemporaryObject(DriverObject); 1447 1448 /* Dereference it 2 times */ 1449 ObDereferenceObject(DriverObject); 1450 ObDereferenceObject(DriverObject); 1451 1452 return Status; 1453 } 1454 else 1455 { 1456 DPRINT1("No DriverUnload function! '%wZ' will not be unloaded!\n", &DriverObject->DriverName); 1457 1458 /* Dereference one time (refd inside this function) */ 1459 ObDereferenceObject(DriverObject); 1460 1461 /* Return unloading failure */ 1462 return STATUS_INVALID_DEVICE_REQUEST; 1463 } 1464 } 1465 1466 VOID 1467 NTAPI 1468 IopReinitializeDrivers(VOID) 1469 { 1470 PDRIVER_REINIT_ITEM ReinitItem; 1471 PLIST_ENTRY Entry; 1472 1473 /* Get the first entry and start looping */ 1474 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead, 1475 &DriverReinitListLock); 1476 while (Entry) 1477 { 1478 /* Get the item */ 1479 ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry); 1480 1481 /* Increment reinitialization counter */ 1482 ReinitItem->DriverObject->DriverExtension->Count++; 1483 1484 /* Remove the device object flag */ 1485 ReinitItem->DriverObject->Flags &= ~DRVO_REINIT_REGISTERED; 1486 1487 /* Call the routine */ 1488 ReinitItem->ReinitRoutine(ReinitItem->DriverObject, 1489 ReinitItem->Context, 1490 ReinitItem->DriverObject-> 1491 DriverExtension->Count); 1492 1493 /* Free the entry */ 1494 ExFreePool(Entry); 1495 1496 /* Move to the next one */ 1497 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead, 1498 &DriverReinitListLock); 1499 } 1500 } 1501 1502 VOID 1503 NTAPI 1504 IopReinitializeBootDrivers(VOID) 1505 { 1506 PDRIVER_REINIT_ITEM ReinitItem; 1507 PLIST_ENTRY Entry; 1508 1509 /* Get the first entry and start looping */ 1510 Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead, 1511 &DriverBootReinitListLock); 1512 while (Entry) 1513 { 1514 /* Get the item */ 1515 ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry); 1516 1517 /* Increment reinitialization counter */ 1518 ReinitItem->DriverObject->DriverExtension->Count++; 1519 1520 /* Remove the device object flag */ 1521 ReinitItem->DriverObject->Flags &= ~DRVO_BOOTREINIT_REGISTERED; 1522 1523 /* Call the routine */ 1524 ReinitItem->ReinitRoutine(ReinitItem->DriverObject, 1525 ReinitItem->Context, 1526 ReinitItem->DriverObject-> 1527 DriverExtension->Count); 1528 1529 /* Free the entry */ 1530 ExFreePool(Entry); 1531 1532 /* Move to the next one */ 1533 Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead, 1534 &DriverBootReinitListLock); 1535 } 1536 1537 /* Wait for all device actions being finished*/ 1538 KeWaitForSingleObject(&PiEnumerationFinished, Executive, KernelMode, FALSE, NULL); 1539 } 1540 1541 /* PUBLIC FUNCTIONS ***********************************************************/ 1542 1543 /* 1544 * @implemented 1545 */ 1546 NTSTATUS 1547 NTAPI 1548 IoCreateDriver( 1549 _In_opt_ PUNICODE_STRING DriverName, 1550 _In_ PDRIVER_INITIALIZE InitializationFunction) 1551 { 1552 WCHAR NameBuffer[100]; 1553 USHORT NameLength; 1554 UNICODE_STRING LocalDriverName; 1555 NTSTATUS Status; 1556 OBJECT_ATTRIBUTES ObjectAttributes; 1557 ULONG ObjectSize; 1558 PDRIVER_OBJECT DriverObject; 1559 UNICODE_STRING ServiceKeyName; 1560 HANDLE hDriver; 1561 ULONG i, RetryCount = 0; 1562 1563 try_again: 1564 /* First, create a unique name for the driver if we don't have one */ 1565 if (!DriverName) 1566 { 1567 /* Create a random name and set up the string */ 1568 NameLength = (USHORT)swprintf(NameBuffer, 1569 DRIVER_ROOT_NAME L"%08u", 1570 KeTickCount.LowPart); 1571 LocalDriverName.Length = NameLength * sizeof(WCHAR); 1572 LocalDriverName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL); 1573 LocalDriverName.Buffer = NameBuffer; 1574 } 1575 else 1576 { 1577 /* So we can avoid another code path, use a local var */ 1578 LocalDriverName = *DriverName; 1579 } 1580 1581 /* Initialize the Attributes */ 1582 ObjectSize = sizeof(DRIVER_OBJECT) + sizeof(EXTENDED_DRIVER_EXTENSION); 1583 InitializeObjectAttributes(&ObjectAttributes, 1584 &LocalDriverName, 1585 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 1586 NULL, 1587 NULL); 1588 1589 /* Create the Object */ 1590 Status = ObCreateObject(KernelMode, 1591 IoDriverObjectType, 1592 &ObjectAttributes, 1593 KernelMode, 1594 NULL, 1595 ObjectSize, 1596 0, 1597 0, 1598 (PVOID*)&DriverObject); 1599 if (!NT_SUCCESS(Status)) return Status; 1600 1601 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject); 1602 1603 /* Set up the Object */ 1604 RtlZeroMemory(DriverObject, ObjectSize); 1605 DriverObject->Type = IO_TYPE_DRIVER; 1606 DriverObject->Size = sizeof(DRIVER_OBJECT); 1607 DriverObject->Flags = DRVO_BUILTIN_DRIVER; 1608 DriverObject->DriverExtension = (PDRIVER_EXTENSION)(DriverObject + 1); 1609 DriverObject->DriverExtension->DriverObject = DriverObject; 1610 DriverObject->DriverInit = InitializationFunction; 1611 /* Loop all Major Functions */ 1612 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) 1613 { 1614 /* Invalidate each function */ 1615 DriverObject->MajorFunction[i] = IopInvalidDeviceRequest; 1616 } 1617 1618 /* Set up the service key name buffer */ 1619 ServiceKeyName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL); 1620 ServiceKeyName.Buffer = ExAllocatePoolWithTag(PagedPool, LocalDriverName.MaximumLength, TAG_IO); 1621 if (!ServiceKeyName.Buffer) 1622 { 1623 /* Fail */ 1624 ObMakeTemporaryObject(DriverObject); 1625 ObDereferenceObject(DriverObject); 1626 return STATUS_INSUFFICIENT_RESOURCES; 1627 } 1628 1629 /* For builtin drivers, the ServiceKeyName is equal to DriverName */ 1630 RtlCopyUnicodeString(&ServiceKeyName, &LocalDriverName); 1631 ServiceKeyName.Buffer[ServiceKeyName.Length / sizeof(WCHAR)] = UNICODE_NULL; 1632 DriverObject->DriverExtension->ServiceKeyName = ServiceKeyName; 1633 1634 /* Make a copy of the driver name to store in the driver object */ 1635 DriverObject->DriverName.MaximumLength = LocalDriverName.Length; 1636 DriverObject->DriverName.Buffer = ExAllocatePoolWithTag(PagedPool, 1637 DriverObject->DriverName.MaximumLength, 1638 TAG_IO); 1639 if (!DriverObject->DriverName.Buffer) 1640 { 1641 /* Fail */ 1642 ObMakeTemporaryObject(DriverObject); 1643 ObDereferenceObject(DriverObject); 1644 return STATUS_INSUFFICIENT_RESOURCES; 1645 } 1646 1647 RtlCopyUnicodeString(&DriverObject->DriverName, &LocalDriverName); 1648 1649 /* Add the Object and get its handle */ 1650 Status = ObInsertObject(DriverObject, 1651 NULL, 1652 FILE_READ_DATA, 1653 0, 1654 NULL, 1655 &hDriver); 1656 1657 /* Eliminate small possibility when this function is called more than 1658 once in a row, and KeTickCount doesn't get enough time to change */ 1659 if (!DriverName && (Status == STATUS_OBJECT_NAME_COLLISION) && (RetryCount < 100)) 1660 { 1661 RetryCount++; 1662 goto try_again; 1663 } 1664 1665 if (!NT_SUCCESS(Status)) return Status; 1666 1667 /* Now reference it */ 1668 Status = ObReferenceObjectByHandle(hDriver, 1669 0, 1670 IoDriverObjectType, 1671 KernelMode, 1672 (PVOID*)&DriverObject, 1673 NULL); 1674 1675 /* Close the extra handle */ 1676 ZwClose(hDriver); 1677 1678 if (!NT_SUCCESS(Status)) 1679 { 1680 /* Fail */ 1681 ObMakeTemporaryObject(DriverObject); 1682 ObDereferenceObject(DriverObject); 1683 return Status; 1684 } 1685 1686 /* Finally, call its init function */ 1687 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction); 1688 Status = InitializationFunction(DriverObject, NULL); 1689 if (!NT_SUCCESS(Status)) 1690 { 1691 /* If it didn't work, then kill the object */ 1692 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName, Status); 1693 ObMakeTemporaryObject(DriverObject); 1694 ObDereferenceObject(DriverObject); 1695 return Status; 1696 } 1697 1698 // Windows does this fixup - keep it for compatibility 1699 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) 1700 { 1701 /* 1702 * Make sure the driver didn't set any dispatch entry point to NULL! 1703 * Doing so is illegal; drivers shouldn't touch entry points they 1704 * do not implement. 1705 */ 1706 1707 /* Check if it did so anyway */ 1708 if (!DriverObject->MajorFunction[i]) 1709 { 1710 /* Print a warning in the debug log */ 1711 DPRINT1("Driver <%wZ> set DriverObject->MajorFunction[%lu] to NULL!\n", 1712 &DriverObject->DriverName, i); 1713 1714 /* Fix it up */ 1715 DriverObject->MajorFunction[i] = IopInvalidDeviceRequest; 1716 } 1717 } 1718 1719 /* Return the Status */ 1720 return Status; 1721 } 1722 1723 /* 1724 * @implemented 1725 */ 1726 VOID 1727 NTAPI 1728 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject) 1729 { 1730 /* Simply dereference the Object */ 1731 ObDereferenceObject(DriverObject); 1732 } 1733 1734 /* 1735 * @implemented 1736 */ 1737 VOID 1738 NTAPI 1739 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject, 1740 IN PDRIVER_REINITIALIZE ReinitRoutine, 1741 IN PVOID Context) 1742 { 1743 PDRIVER_REINIT_ITEM ReinitItem; 1744 1745 /* Allocate the entry */ 1746 ReinitItem = ExAllocatePoolWithTag(NonPagedPool, 1747 sizeof(DRIVER_REINIT_ITEM), 1748 TAG_REINIT); 1749 if (!ReinitItem) return; 1750 1751 /* Fill it out */ 1752 ReinitItem->DriverObject = DriverObject; 1753 ReinitItem->ReinitRoutine = ReinitRoutine; 1754 ReinitItem->Context = Context; 1755 1756 /* Set the Driver Object flag and insert the entry into the list */ 1757 DriverObject->Flags |= DRVO_BOOTREINIT_REGISTERED; 1758 ExInterlockedInsertTailList(&DriverBootReinitListHead, 1759 &ReinitItem->ItemEntry, 1760 &DriverBootReinitListLock); 1761 } 1762 1763 /* 1764 * @implemented 1765 */ 1766 VOID 1767 NTAPI 1768 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject, 1769 IN PDRIVER_REINITIALIZE ReinitRoutine, 1770 IN PVOID Context) 1771 { 1772 PDRIVER_REINIT_ITEM ReinitItem; 1773 1774 /* Allocate the entry */ 1775 ReinitItem = ExAllocatePoolWithTag(NonPagedPool, 1776 sizeof(DRIVER_REINIT_ITEM), 1777 TAG_REINIT); 1778 if (!ReinitItem) return; 1779 1780 /* Fill it out */ 1781 ReinitItem->DriverObject = DriverObject; 1782 ReinitItem->ReinitRoutine = ReinitRoutine; 1783 ReinitItem->Context = Context; 1784 1785 /* Set the Driver Object flag and insert the entry into the list */ 1786 DriverObject->Flags |= DRVO_REINIT_REGISTERED; 1787 ExInterlockedInsertTailList(&DriverReinitListHead, 1788 &ReinitItem->ItemEntry, 1789 &DriverReinitListLock); 1790 } 1791 1792 /* 1793 * @implemented 1794 */ 1795 NTSTATUS 1796 NTAPI 1797 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject, 1798 IN PVOID ClientIdentificationAddress, 1799 IN ULONG DriverObjectExtensionSize, 1800 OUT PVOID *DriverObjectExtension) 1801 { 1802 KIRQL OldIrql; 1803 PIO_CLIENT_EXTENSION DriverExtensions, NewDriverExtension; 1804 BOOLEAN Inserted = FALSE; 1805 1806 /* Assume failure */ 1807 *DriverObjectExtension = NULL; 1808 1809 /* Allocate the extension */ 1810 NewDriverExtension = ExAllocatePoolWithTag(NonPagedPool, 1811 sizeof(IO_CLIENT_EXTENSION) + 1812 DriverObjectExtensionSize, 1813 TAG_DRIVER_EXTENSION); 1814 if (!NewDriverExtension) return STATUS_INSUFFICIENT_RESOURCES; 1815 1816 /* Clear the extension for teh caller */ 1817 RtlZeroMemory(NewDriverExtension, 1818 sizeof(IO_CLIENT_EXTENSION) + DriverObjectExtensionSize); 1819 1820 /* Acqure lock */ 1821 OldIrql = KeRaiseIrqlToDpcLevel(); 1822 1823 /* Fill out the extension */ 1824 NewDriverExtension->ClientIdentificationAddress = ClientIdentificationAddress; 1825 1826 /* Loop the current extensions */ 1827 DriverExtensions = IoGetDrvObjExtension(DriverObject)-> 1828 ClientDriverExtension; 1829 while (DriverExtensions) 1830 { 1831 /* Check if the identifier matches */ 1832 if (DriverExtensions->ClientIdentificationAddress == 1833 ClientIdentificationAddress) 1834 { 1835 /* We have a collision, break out */ 1836 break; 1837 } 1838 1839 /* Go to the next one */ 1840 DriverExtensions = DriverExtensions->NextExtension; 1841 } 1842 1843 /* Check if we didn't collide */ 1844 if (!DriverExtensions) 1845 { 1846 /* Link this one in */ 1847 NewDriverExtension->NextExtension = 1848 IoGetDrvObjExtension(DriverObject)->ClientDriverExtension; 1849 IoGetDrvObjExtension(DriverObject)->ClientDriverExtension = 1850 NewDriverExtension; 1851 Inserted = TRUE; 1852 } 1853 1854 /* Release the lock */ 1855 KeLowerIrql(OldIrql); 1856 1857 /* Check if insertion failed */ 1858 if (!Inserted) 1859 { 1860 /* Free the entry and fail */ 1861 ExFreePoolWithTag(NewDriverExtension, TAG_DRIVER_EXTENSION); 1862 return STATUS_OBJECT_NAME_COLLISION; 1863 } 1864 1865 /* Otherwise, return the pointer */ 1866 *DriverObjectExtension = NewDriverExtension + 1; 1867 return STATUS_SUCCESS; 1868 } 1869 1870 /* 1871 * @implemented 1872 */ 1873 PVOID 1874 NTAPI 1875 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject, 1876 IN PVOID ClientIdentificationAddress) 1877 { 1878 KIRQL OldIrql; 1879 PIO_CLIENT_EXTENSION DriverExtensions; 1880 1881 /* Acquire lock */ 1882 OldIrql = KeRaiseIrqlToDpcLevel(); 1883 1884 /* Loop the list until we find the right one */ 1885 DriverExtensions = IoGetDrvObjExtension(DriverObject)->ClientDriverExtension; 1886 while (DriverExtensions) 1887 { 1888 /* Check for a match */ 1889 if (DriverExtensions->ClientIdentificationAddress == 1890 ClientIdentificationAddress) 1891 { 1892 /* Break out */ 1893 break; 1894 } 1895 1896 /* Keep looping */ 1897 DriverExtensions = DriverExtensions->NextExtension; 1898 } 1899 1900 /* Release lock */ 1901 KeLowerIrql(OldIrql); 1902 1903 /* Return nothing or the extension */ 1904 if (!DriverExtensions) return NULL; 1905 return DriverExtensions + 1; 1906 } 1907 1908 NTSTATUS 1909 IopLoadDriver( 1910 _In_ HANDLE ServiceHandle, 1911 _Out_ PDRIVER_OBJECT *DriverObject) 1912 { 1913 UNICODE_STRING ImagePath; 1914 NTSTATUS Status; 1915 PLDR_DATA_TABLE_ENTRY ModuleObject; 1916 PVOID BaseAddress; 1917 1918 PKEY_VALUE_FULL_INFORMATION kvInfo; 1919 Status = IopGetRegistryValue(ServiceHandle, L"ImagePath", &kvInfo); 1920 if (NT_SUCCESS(Status)) 1921 { 1922 if (kvInfo->Type != REG_EXPAND_SZ || kvInfo->DataLength == 0) 1923 { 1924 ExFreePool(kvInfo); 1925 return STATUS_ILL_FORMED_SERVICE_ENTRY; 1926 } 1927 1928 ImagePath.Length = kvInfo->DataLength - sizeof(UNICODE_NULL); 1929 ImagePath.MaximumLength = kvInfo->DataLength; 1930 ImagePath.Buffer = ExAllocatePoolWithTag(PagedPool, ImagePath.MaximumLength, TAG_RTLREGISTRY); 1931 if (!ImagePath.Buffer) 1932 { 1933 ExFreePool(kvInfo); 1934 return STATUS_INSUFFICIENT_RESOURCES; 1935 } 1936 1937 RtlMoveMemory(ImagePath.Buffer, 1938 (PVOID)((ULONG_PTR)kvInfo + kvInfo->DataOffset), 1939 ImagePath.Length); 1940 ImagePath.Buffer[ImagePath.Length / sizeof(WCHAR)] = UNICODE_NULL; 1941 ExFreePool(kvInfo); 1942 } 1943 else 1944 { 1945 return Status; 1946 } 1947 1948 /* 1949 * Normalize the image path for all later processing. 1950 */ 1951 Status = IopNormalizeImagePath(&ImagePath, NULL); 1952 if (!NT_SUCCESS(Status)) 1953 { 1954 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status); 1955 return Status; 1956 } 1957 1958 DPRINT("FullImagePath: '%wZ'\n", &ImagePath); 1959 1960 KeEnterCriticalRegion(); 1961 ExAcquireResourceExclusiveLite(&IopDriverLoadResource, TRUE); 1962 1963 /* 1964 * Load the driver module 1965 */ 1966 DPRINT("Loading module from %wZ\n", &ImagePath); 1967 Status = MmLoadSystemImage(&ImagePath, NULL, NULL, 0, (PVOID)&ModuleObject, &BaseAddress); 1968 RtlFreeUnicodeString(&ImagePath); 1969 1970 if (!NT_SUCCESS(Status)) 1971 { 1972 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status); 1973 ExReleaseResourceLite(&IopDriverLoadResource); 1974 KeLeaveCriticalRegion(); 1975 return Status; 1976 } 1977 1978 // Display the loading message 1979 ULONG infoLength; 1980 Status = ZwQueryKey(ServiceHandle, KeyBasicInformation, NULL, 0, &infoLength); 1981 if (Status == STATUS_BUFFER_TOO_SMALL) 1982 { 1983 PKEY_BASIC_INFORMATION servName = ExAllocatePoolWithTag(PagedPool, infoLength, TAG_IO); 1984 if (servName) 1985 { 1986 Status = ZwQueryKey(ServiceHandle, 1987 KeyBasicInformation, 1988 servName, 1989 infoLength, 1990 &infoLength); 1991 if (NT_SUCCESS(Status)) 1992 { 1993 UNICODE_STRING serviceName = { 1994 .Length = servName->NameLength, 1995 .MaximumLength = servName->NameLength, 1996 .Buffer = servName->Name 1997 }; 1998 1999 IopDisplayLoadingMessage(&serviceName); 2000 } 2001 ExFreePoolWithTag(servName, TAG_IO); 2002 } 2003 } 2004 2005 NTSTATUS driverEntryStatus; 2006 Status = IopInitializeDriverModule(ModuleObject, 2007 ServiceHandle, 2008 DriverObject, 2009 &driverEntryStatus); 2010 if (!NT_SUCCESS(Status)) 2011 { 2012 DPRINT1("IopInitializeDriverModule() failed (Status %lx)\n", Status); 2013 } 2014 2015 ExReleaseResourceLite(&IopDriverLoadResource); 2016 KeLeaveCriticalRegion(); 2017 2018 return Status; 2019 } 2020 2021 static 2022 VOID 2023 NTAPI 2024 IopLoadUnloadDriverWorker( 2025 _Inout_ PVOID Parameter) 2026 { 2027 PLOAD_UNLOAD_PARAMS LoadParams = Parameter; 2028 2029 ASSERT(PsGetCurrentProcess() == PsInitialSystemProcess); 2030 2031 if (LoadParams->DriverObject) 2032 { 2033 // unload request 2034 LoadParams->DriverObject->DriverUnload(LoadParams->DriverObject); 2035 LoadParams->Status = STATUS_SUCCESS; 2036 } 2037 else 2038 { 2039 // load request 2040 HANDLE serviceHandle; 2041 NTSTATUS status; 2042 status = IopOpenRegistryKeyEx(&serviceHandle, NULL, LoadParams->RegistryPath, KEY_READ); 2043 if (!NT_SUCCESS(status)) 2044 { 2045 LoadParams->Status = status; 2046 } 2047 else 2048 { 2049 LoadParams->Status = IopLoadDriver(serviceHandle, &LoadParams->DriverObject); 2050 ZwClose(serviceHandle); 2051 } 2052 } 2053 2054 if (LoadParams->SetEvent) 2055 { 2056 KeSetEvent(&LoadParams->Event, 0, FALSE); 2057 } 2058 } 2059 2060 /** 2061 * @brief Process load and unload driver operations. This is mostly for NtLoadDriver 2062 * and NtUnloadDriver, because their code should run inside PsInitialSystemProcess 2063 * 2064 * @param[in] RegistryPath The registry path 2065 * @param DriverObject The driver object 2066 * 2067 * @return Status of the operation 2068 */ 2069 NTSTATUS 2070 IopDoLoadUnloadDriver( 2071 _In_opt_ PUNICODE_STRING RegistryPath, 2072 _Inout_ PDRIVER_OBJECT *DriverObject) 2073 { 2074 LOAD_UNLOAD_PARAMS LoadParams; 2075 2076 /* Prepare parameters block */ 2077 LoadParams.RegistryPath = RegistryPath; 2078 LoadParams.DriverObject = *DriverObject; 2079 2080 if (PsGetCurrentProcess() != PsInitialSystemProcess) 2081 { 2082 LoadParams.SetEvent = TRUE; 2083 KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE); 2084 2085 /* Initialize and queue a work item */ 2086 ExInitializeWorkItem(&LoadParams.WorkItem, IopLoadUnloadDriverWorker, &LoadParams); 2087 ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue); 2088 2089 /* And wait till it completes */ 2090 KeWaitForSingleObject(&LoadParams.Event, UserRequest, KernelMode, FALSE, NULL); 2091 } 2092 else 2093 { 2094 /* If we're already in a system process, call it right here */ 2095 LoadParams.SetEvent = FALSE; 2096 IopLoadUnloadDriverWorker(&LoadParams); 2097 } 2098 2099 return LoadParams.Status; 2100 } 2101 2102 /* 2103 * NtLoadDriver 2104 * 2105 * Loads a device driver. 2106 * 2107 * Parameters 2108 * DriverServiceName 2109 * Name of the service to load (registry key). 2110 * 2111 * Return Value 2112 * Status 2113 * 2114 * Status 2115 * implemented 2116 */ 2117 NTSTATUS NTAPI 2118 NtLoadDriver(IN PUNICODE_STRING DriverServiceName) 2119 { 2120 UNICODE_STRING CapturedServiceName = { 0, 0, NULL }; 2121 KPROCESSOR_MODE PreviousMode; 2122 PDRIVER_OBJECT DriverObject; 2123 NTSTATUS Status; 2124 2125 PAGED_CODE(); 2126 2127 PreviousMode = KeGetPreviousMode(); 2128 2129 /* Need the appropriate priviliege */ 2130 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode)) 2131 { 2132 DPRINT1("No load privilege!\n"); 2133 return STATUS_PRIVILEGE_NOT_HELD; 2134 } 2135 2136 /* Capture the service name */ 2137 Status = ProbeAndCaptureUnicodeString(&CapturedServiceName, 2138 PreviousMode, 2139 DriverServiceName); 2140 if (!NT_SUCCESS(Status)) 2141 { 2142 return Status; 2143 } 2144 2145 DPRINT("NtLoadDriver('%wZ')\n", &CapturedServiceName); 2146 2147 /* We need a service name */ 2148 if (CapturedServiceName.Length == 0 || CapturedServiceName.Buffer == NULL) 2149 { 2150 ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode); 2151 return STATUS_INVALID_PARAMETER; 2152 } 2153 2154 /* Load driver and call its entry point */ 2155 DriverObject = NULL; 2156 Status = IopDoLoadUnloadDriver(&CapturedServiceName, &DriverObject); 2157 2158 ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode); 2159 return Status; 2160 } 2161 2162 /* 2163 * NtUnloadDriver 2164 * 2165 * Unloads a legacy device driver. 2166 * 2167 * Parameters 2168 * DriverServiceName 2169 * Name of the service to unload (registry key). 2170 * 2171 * Return Value 2172 * Status 2173 * 2174 * Status 2175 * implemented 2176 */ 2177 2178 NTSTATUS NTAPI 2179 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName) 2180 { 2181 return IopUnloadDriver(DriverServiceName, FALSE); 2182 } 2183 2184 /* EOF */ 2185