From 0fed07b7e4c70e5be3068aeae224d69b39ee7046 Mon Sep 17 00:00:00 2001 From: Victor Perevertkin Date: Fri, 19 Mar 2021 07:57:41 +0300 Subject: [PATCH] [NTOS:PNP] Initialize DeviceDesc and LocationInformation registry fields for manually reported devices, as it is required by the newdev.dll for installing drivers from INF files CORE-17212 CORE-17398 Co-authored-by: Stanislav Motylkov --- ntoskrnl/include/internal/io.h | 12 ++ ntoskrnl/io/pnpmgr/devaction.c | 199 +++++++++++++++++---------------- ntoskrnl/io/pnpmgr/pnpirp.c | 31 +++++ ntoskrnl/io/pnpmgr/pnpreport.c | 3 + 4 files changed, 151 insertions(+), 94 deletions(-) diff --git a/ntoskrnl/include/internal/io.h b/ntoskrnl/include/internal/io.h index 5e84f8e120f..e43f4769c94 100644 --- a/ntoskrnl/include/internal/io.h +++ b/ntoskrnl/include/internal/io.h @@ -753,6 +753,11 @@ PnpRegSzToString( OUT PUSHORT StringLength OPTIONAL ); +VOID +PiSetDevNodeText( + _In_ PDEVICE_NODE DeviceNode, + _In_ HANDLE InstanceKey); + // // Initialization Routines // @@ -1381,6 +1386,13 @@ PiIrpQueryDeviceRelations( _In_ PDEVICE_NODE DeviceNode, _In_ DEVICE_RELATION_TYPE Type); +NTSTATUS +PiIrpQueryDeviceText( + _In_ PDEVICE_NODE DeviceNode, + _In_ LCID POINTER_ALIGNMENT LocaleId, + _In_ DEVICE_TEXT_TYPE Type, + _Out_ PWSTR *DeviceText); + NTSTATUS PiIrpQueryPnPDeviceState( _In_ PDEVICE_NODE DeviceNode, diff --git a/ntoskrnl/io/pnpmgr/devaction.c b/ntoskrnl/io/pnpmgr/devaction.c index aa1ac12f6c2..1cf30fa8575 100644 --- a/ntoskrnl/io/pnpmgr/devaction.c +++ b/ntoskrnl/io/pnpmgr/devaction.c @@ -1081,34 +1081,123 @@ IopQueryCompatibleIds(PDEVICE_NODE DeviceNode, return Status; } +/** + * @brief Sets the DeviceNode's DeviceDesc and LocationInformation registry values + */ +VOID +PiSetDevNodeText( + _In_ PDEVICE_NODE DeviceNode, + _In_ HANDLE InstanceKey) +{ + PAGED_CODE(); + + LCID localeId; + + // Get the Locale ID + NTSTATUS status = ZwQueryDefaultLocale(FALSE, &localeId); + if (!NT_SUCCESS(status)) + { + DPRINT1("ZwQueryDefaultLocale() failed with status %x\n", status); + return; + } + + // Step 1: write DeviceDesc key if not exists + + UNICODE_STRING valDeviceDesc = RTL_CONSTANT_STRING(L"DeviceDesc"); + ULONG len; + + status = ZwQueryValueKey(InstanceKey, &valDeviceDesc, KeyValueBasicInformation, NULL, 0, &len); + if (!NT_SUCCESS(status)) + { + PWSTR deviceDesc = NULL; + status = PiIrpQueryDeviceText(DeviceNode, localeId, DeviceTextDescription, &deviceDesc); + + if (deviceDesc && deviceDesc[0] != UNICODE_NULL) + { + status = ZwSetValueKey(InstanceKey, + &valDeviceDesc, + 0, + REG_SZ, + deviceDesc, + ((ULONG)wcslen(deviceDesc) + 1) * sizeof(WCHAR)); + + if (!NT_SUCCESS(status)) + { + DPRINT1("ZwSetValueKey() failed (Status %x)\n", status); + } + } + else + { + // This key is mandatory, so even if the Irp fails, we still write it + UNICODE_STRING unknownDeviceDesc = RTL_CONSTANT_STRING(L"Unknown device"); + DPRINT("Driver didn't return DeviceDesc (status %x)\n", status); + + status = ZwSetValueKey(InstanceKey, + &valDeviceDesc, + 0, + REG_SZ, + unknownDeviceDesc.Buffer, + unknownDeviceDesc.MaximumLength); + if (!NT_SUCCESS(status)) + { + DPRINT1("ZwSetValueKey() failed (Status %x)\n", status); + } + } + + if (deviceDesc) + { + ExFreePoolWithTag(deviceDesc, 0); + } + } + + // Step 2: LocaltionInformation is overwritten unconditionally + + PWSTR deviceLocationInfo = NULL; + status = PiIrpQueryDeviceText(DeviceNode, + localeId, + DeviceTextLocationInformation, + &deviceLocationInfo); + + if (deviceLocationInfo && deviceLocationInfo[0] != UNICODE_NULL) + { + UNICODE_STRING valLocationInfo = RTL_CONSTANT_STRING(L"LocationInformation"); + + status = ZwSetValueKey(InstanceKey, + &valLocationInfo, + 0, + REG_SZ, + deviceLocationInfo, + ((ULONG)wcslen(deviceLocationInfo) + 1) * sizeof(WCHAR)); + if (!NT_SUCCESS(status)) + { + DPRINT1("ZwSetValueKey() failed (Status %x)\n", status); + } + } + + if (deviceLocationInfo) + { + ExFreePoolWithTag(deviceLocationInfo, 0); + } + else + { + DPRINT("Driver didn't return LocationInformation (status %x)\n", status); + } +} + static NTSTATUS PiInitializeDevNode( _In_ PDEVICE_NODE DeviceNode) { IO_STATUS_BLOCK IoStatusBlock; - PWSTR DeviceDescription; - PWSTR LocationInformation; - IO_STACK_LOCATION Stack; NTSTATUS Status; - ULONG RequiredLength; - LCID LocaleId; HANDLE InstanceKey = NULL; - UNICODE_STRING ValueName; UNICODE_STRING InstancePathU; PDEVICE_OBJECT OldDeviceObject; DPRINT("PiProcessNewDevNode(%p)\n", DeviceNode); DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject); - /* Get Locale ID */ - Status = ZwQueryDefaultLocale(FALSE, &LocaleId); - if (!NT_SUCCESS(Status)) - { - DPRINT1("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status); - return Status; - } - /* * FIXME: For critical errors, cleanup and disable device, but always * return STATUS_SUCCESS. @@ -1163,86 +1252,8 @@ PiInitializeDevNode( DeviceNode->Flags |= DNF_IDS_QUERIED; - DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n"); - - Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription; - Stack.Parameters.QueryDeviceText.LocaleId = LocaleId; - Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, - &IoStatusBlock, - IRP_MN_QUERY_DEVICE_TEXT, - &Stack); - DeviceDescription = NT_SUCCESS(Status) ? (PWSTR)IoStatusBlock.Information - : NULL; - /* This key is mandatory, so even if the Irp fails, we still write it */ - RtlInitUnicodeString(&ValueName, L"DeviceDesc"); - if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND) - { - if (DeviceDescription && - *DeviceDescription != UNICODE_NULL) - { - /* This key is overriden when a driver is installed. Don't write the - * new description if another one already exists */ - Status = ZwSetValueKey(InstanceKey, - &ValueName, - 0, - REG_SZ, - DeviceDescription, - ((ULONG)wcslen(DeviceDescription) + 1) * sizeof(WCHAR)); - } - else - { - UNICODE_STRING DeviceDesc = RTL_CONSTANT_STRING(L"Unknown device"); - DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status); - - Status = ZwSetValueKey(InstanceKey, - &ValueName, - 0, - REG_SZ, - DeviceDesc.Buffer, - DeviceDesc.MaximumLength); - if (!NT_SUCCESS(Status)) - { - DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status); - } - - } - } - - if (DeviceDescription) - { - ExFreePoolWithTag(DeviceDescription, 0); - } - - DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n"); - - Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation; - Stack.Parameters.QueryDeviceText.LocaleId = LocaleId; - Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, - &IoStatusBlock, - IRP_MN_QUERY_DEVICE_TEXT, - &Stack); - if (NT_SUCCESS(Status) && IoStatusBlock.Information) - { - LocationInformation = (PWSTR)IoStatusBlock.Information; - DPRINT("LocationInformation: %S\n", LocationInformation); - RtlInitUnicodeString(&ValueName, L"LocationInformation"); - Status = ZwSetValueKey(InstanceKey, - &ValueName, - 0, - REG_SZ, - LocationInformation, - ((ULONG)wcslen(LocationInformation) + 1) * sizeof(WCHAR)); - if (!NT_SUCCESS(Status)) - { - DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status); - } - - ExFreePoolWithTag(LocationInformation, 0); - } - else - { - DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status); - } + // Set the device's DeviceDesc and LocationInformation fields + PiSetDevNodeText(DeviceNode, InstanceKey); DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n"); diff --git a/ntoskrnl/io/pnpmgr/pnpirp.c b/ntoskrnl/io/pnpmgr/pnpirp.c index 03fc0d1aafc..48d924d6c7c 100644 --- a/ntoskrnl/io/pnpmgr/pnpirp.c +++ b/ntoskrnl/io/pnpmgr/pnpirp.c @@ -196,6 +196,37 @@ PiIrpQueryDeviceRelations( return status; } +// IRP_MN_QUERY_DEVICE_TEXT (0x0C) +NTSTATUS +PiIrpQueryDeviceText( + _In_ PDEVICE_NODE DeviceNode, + _In_ LCID POINTER_ALIGNMENT LocaleId, + _In_ DEVICE_TEXT_TYPE Type, + _Out_ PWSTR *DeviceText) +{ + PAGED_CODE(); + + ASSERT(DeviceNode); + ASSERT(DeviceNode->State == DeviceNodeUninitialized); + + ULONG_PTR longText; + IO_STACK_LOCATION stack = { + .MajorFunction = IRP_MJ_PNP, + .MinorFunction = IRP_MN_QUERY_DEVICE_TEXT, + .Parameters.QueryDeviceText.DeviceTextType = Type, + .Parameters.QueryDeviceText.LocaleId = LocaleId + }; + + NTSTATUS status; + status = IopSynchronousCall(DeviceNode->PhysicalDeviceObject, &stack, (PVOID)&longText); + if (NT_SUCCESS(status)) + { + *DeviceText = (PVOID)longText; + } + + return status; +} + // IRP_MN_QUERY_PNP_DEVICE_STATE (0x14) NTSTATUS PiIrpQueryPnPDeviceState( diff --git a/ntoskrnl/io/pnpmgr/pnpreport.c b/ntoskrnl/io/pnpmgr/pnpreport.c index 8104a8f178b..65e256075da 100644 --- a/ntoskrnl/io/pnpmgr/pnpreport.c +++ b/ntoskrnl/io/pnpmgr/pnpreport.c @@ -294,6 +294,9 @@ IoReportDetectedDevice( return Status; } + // Set the device's DeviceDesc and LocationInformation fields + PiSetDevNodeText(DeviceNode, InstanceKey); + /* Assign the resources to the device node */ DeviceNode->BootResources = ResourceList; DeviceNode->ResourceRequirements = ResourceRequirements;