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