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