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