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