From 029accdcf7ccf25b7cb0d875fe065913ddc4d50f Mon Sep 17 00:00:00 2001 From: Victor Perevertkin Date: Tue, 23 Feb 2021 04:24:41 +0300 Subject: [PATCH 1/3] [NDK] Change the data structure for PlugPlayControlResetDevice control class PlugPlayControlResetDevice shares the input structure with several other control classes. Source: ProcessHacker sources https://github.com/processhacker/phnt/blob/e9c8121f41b00cd24e31eb466c9795785096b764/ntpnpapi.h --- base/services/umpnpmgr/rpcserver.c | 4 ++-- base/setup/usetup/devinst.c | 4 ++-- ntoskrnl/io/pnpmgr/plugplay.c | 6 ++--- sdk/include/ndk/cmtypes.h | 38 +++++++++++++++++------------- 4 files changed, 29 insertions(+), 23 deletions(-) diff --git a/base/services/umpnpmgr/rpcserver.c b/base/services/umpnpmgr/rpcserver.c index 1d14d978ab043..cf9ba100f1b76 100644 --- a/base/services/umpnpmgr/rpcserver.c +++ b/base/services/umpnpmgr/rpcserver.c @@ -3081,7 +3081,7 @@ static CONFIGRET EnableDeviceInstance( _In_ LPWSTR pszDeviceInstance) { - PLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData; + PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ResetDeviceData; CONFIGRET ret = CR_SUCCESS; NTSTATUS Status; @@ -3091,7 +3091,7 @@ EnableDeviceInstance( pszDeviceInstance); Status = NtPlugPlayControl(PlugPlayControlResetDevice, &ResetDeviceData, - sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA)); + sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)); if (!NT_SUCCESS(Status)) ret = NtStatusToCrError(Status); diff --git a/base/setup/usetup/devinst.c b/base/setup/usetup/devinst.c index 81eb382f5fb52..80d93ce1d519d 100644 --- a/base/setup/usetup/devinst.c +++ b/base/setup/usetup/devinst.c @@ -42,11 +42,11 @@ static BOOLEAN ResetDevice( IN LPCWSTR DeviceId) { - PLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData; + PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ResetDeviceData; NTSTATUS Status; RtlInitUnicodeString(&ResetDeviceData.DeviceInstance, DeviceId); - Status = NtPlugPlayControl(PlugPlayControlResetDevice, &ResetDeviceData, sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA)); + Status = NtPlugPlayControl(PlugPlayControlResetDevice, &ResetDeviceData, sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)); if (!NT_SUCCESS(Status)) { DPRINT1("NtPlugPlayControl() failed with status 0x%08x\n", Status); diff --git a/ntoskrnl/io/pnpmgr/plugplay.c b/ntoskrnl/io/pnpmgr/plugplay.c index 66c1da7fde148..6c0e84fdb9297 100644 --- a/ntoskrnl/io/pnpmgr/plugplay.c +++ b/ntoskrnl/io/pnpmgr/plugplay.c @@ -1044,7 +1044,7 @@ IopGetDeviceDepth(PPLUGPLAY_CONTROL_DEPTH_DATA DepthData) static NTSTATUS -IopResetDevice(PPLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData) +IopResetDevice(PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ResetDeviceData) { PDEVICE_OBJECT DeviceObject; NTSTATUS Status; @@ -1364,9 +1364,9 @@ NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass, // case PlugPlayControlRetrieveDock: case PlugPlayControlResetDevice: - if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA)) + if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)) return STATUS_INVALID_PARAMETER; - return IopResetDevice((PPLUGPLAY_CONTROL_RESET_DEVICE_DATA)Buffer); + return IopResetDevice((PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)Buffer); // case PlugPlayControlHaltDevice: // case PlugPlayControlGetBlockedDriverList: diff --git a/sdk/include/ndk/cmtypes.h b/sdk/include/ndk/cmtypes.h index d5cbced0aeaad..7448c7d19be7e 100644 --- a/sdk/include/ndk/cmtypes.h +++ b/sdk/include/ndk/cmtypes.h @@ -453,14 +453,26 @@ typedef struct _PLUGPLAY_EVENT_BLOCK // Plug and Play Control Classes // -// Class 0x00 +// PlugPlayControlEnumerateDevice (0x00) typedef struct _PLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA { UNICODE_STRING DeviceInstance; ULONG Flags; } PLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA, *PPLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA; -// Class 0x06 +// PlugPlayControlRegisterNewDevice (0x1) +// PlugPlayControlDeregisterDevice (0x2) +// PlugPlayControlInitializeDevice (0x3) +// PlugPlayControlStartDevice (0x4) +// PlugPlayControlUnlockDevice (0x5) +// PlugPlayControlResetDevice (0x14) +// PlugPlayControlHaltDevice (0x15) +typedef struct _PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA +{ + UNICODE_STRING DeviceInstance; +} PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA, *PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA; + +// PlugPlayControlQueryAndRemoveDevice (0x06) typedef struct _PLUGPLAY_CONTROL_QUERY_REMOVE_DATA { UNICODE_STRING DeviceInstance; @@ -470,7 +482,7 @@ typedef struct _PLUGPLAY_CONTROL_QUERY_REMOVE_DATA ULONG NameLength; } PLUGPLAY_CONTROL_QUERY_REMOVE_DATA, *PPLUGPLAY_CONTROL_QUERY_REMOVE_DATA; -// Class 0x07 +// PlugPlayControlUserResponse (0x07) typedef struct _PLUGPLAY_CONTROL_USER_RESPONSE_DATA { ULONG Unknown1; @@ -479,7 +491,7 @@ typedef struct _PLUGPLAY_CONTROL_USER_RESPONSE_DATA ULONG Unknown4; } PLUGPLAY_CONTROL_USER_RESPONSE_DATA, *PPLUGPLAY_CONTROL_USER_RESPONSE_DATA; -// Class 0x09 +// PlugPlayControlGetInterfaceDeviceList (0x09) typedef struct _PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA { UNICODE_STRING DeviceInstance; @@ -489,7 +501,7 @@ typedef struct _PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA ULONG BufferSize; } PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA, *PPLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA; -//Class 0x0A +// PlugPlayControlProperty (0x0A) typedef struct _PLUGPLAY_CONTROL_PROPERTY_DATA { UNICODE_STRING DeviceInstance; @@ -498,7 +510,7 @@ typedef struct _PLUGPLAY_CONTROL_PROPERTY_DATA ULONG BufferSize; } PLUGPLAY_CONTROL_PROPERTY_DATA, *PPLUGPLAY_CONTROL_PROPERTY_DATA; -// Class 0x0C +// PlugPlayControlGetRelatedDevice (0x0C) typedef struct _PLUGPLAY_CONTROL_RELATED_DEVICE_DATA { UNICODE_STRING TargetDeviceInstance; @@ -507,7 +519,7 @@ typedef struct _PLUGPLAY_CONTROL_RELATED_DEVICE_DATA ULONG RelatedDeviceInstanceLength; } PLUGPLAY_CONTROL_RELATED_DEVICE_DATA, *PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA; -// Class 0x0E +// PlugPlayControlDeviceStatus (0x0E) typedef struct _PLUGPLAY_CONTOL_STATUS_DATA { UNICODE_STRING DeviceInstance; @@ -516,14 +528,14 @@ typedef struct _PLUGPLAY_CONTOL_STATUS_DATA ULONG DeviceProblem; } PLUGPLAY_CONTROL_STATUS_DATA, *PPLUGPLAY_CONTROL_STATUS_DATA; -// Class 0x0F +// PlugPlayControlGetDeviceDepth (0x0F) typedef struct _PLUGPLAY_CONTROL_DEPTH_DATA { UNICODE_STRING DeviceInstance; ULONG Depth; } PLUGPLAY_CONTROL_DEPTH_DATA, *PPLUGPLAY_CONTROL_DEPTH_DATA; -// Class 0x10 +// PlugPlayControlQueryDeviceRelations (0x10) typedef struct _PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA { UNICODE_STRING DeviceInstance; @@ -532,19 +544,13 @@ typedef struct _PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA PWCHAR Buffer; } PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA, *PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA; -// Class 0x13 +// PlugPlayControlRetrieveDock (0x13) typedef struct _PLUGPLAY_CONTROL_RETRIEVE_DOCK_DATA { ULONG DeviceInstanceLength; PWSTR DeviceInstance; } PLUGPLAY_CONTROL_RETRIEVE_DOCK_DATA, *PPLUGPLAY_CONTROL_RETRIEVE_DOCK_DATA; -// Class 0x14 -typedef struct _PLUGPLAY_CONTROL_RESET_DEVICE_DATA -{ - UNICODE_STRING DeviceInstance; -} PLUGPLAY_CONTROL_RESET_DEVICE_DATA, *PPLUGPLAY_CONTROL_RESET_DEVICE_DATA; - // // Plug and Play Bus Type Definition // From 59a5dba443eaafd7b34d7a7920912b3e18b1b2eb Mon Sep 17 00:00:00 2001 From: Victor Perevertkin Date: Tue, 16 Mar 2021 02:17:14 +0300 Subject: [PATCH 2/3] [NTOS:PNP] Implement PlugPlayControlStartDevice control class This control class is triggered when a driver is being installed for a non-critical device. The driver info should already be in the registry so we just need to push the device through the state graph Meanwhile, combine the code for similar control classes into PiControlSyncDeviceAction routine CORE-17463 CORE-17490 --- ntoskrnl/include/internal/io.h | 3 +- ntoskrnl/io/pnpmgr/devaction.c | 18 +++++++ ntoskrnl/io/pnpmgr/plugplay.c | 90 +++++++++++++++------------------- 3 files changed, 60 insertions(+), 51 deletions(-) diff --git a/ntoskrnl/include/internal/io.h b/ntoskrnl/include/internal/io.h index 269264b9e2788..5e84f8e120f22 100644 --- a/ntoskrnl/include/internal/io.h +++ b/ntoskrnl/include/internal/io.h @@ -534,7 +534,8 @@ typedef enum _DEVICE_ACTION PiActionEnumDeviceTree, PiActionEnumRootDevices, PiActionResetDevice, - PiActionAddBootDevices + PiActionAddBootDevices, + PiActionStartDevice } DEVICE_ACTION; // diff --git a/ntoskrnl/io/pnpmgr/devaction.c b/ntoskrnl/io/pnpmgr/devaction.c index 7bf77afae3efa..5d354ddc62c9d 100644 --- a/ntoskrnl/io/pnpmgr/devaction.c +++ b/ntoskrnl/io/pnpmgr/devaction.c @@ -2482,6 +2482,8 @@ ActionToStr( return "PiActionResetDevice"; case PiActionAddBootDevices: return "PiActionAddBootDevices"; + case PiActionStartDevice: + return "PiActionStartDevice"; default: return "(request unknown)"; } @@ -2540,6 +2542,22 @@ PipDeviceActionWorker( status = STATUS_SUCCESS; break; + case PiActionStartDevice: + // This action is triggered from usermode, when a driver is installed + // for a non-critical PDO + if (deviceNode->State == DeviceNodeInitialized && + !(deviceNode->Flags & DNF_HAS_PROBLEM)) + { + PiDevNodeStateMachine(deviceNode); + } + else + { + DPRINT1("NOTE: attempt to start an already started/uninitialized device %wZ\n", + &deviceNode->InstancePath); + status = STATUS_UNSUCCESSFUL; + } + break; + default: DPRINT1("Unimplemented device action %u\n", Request->Action); status = STATUS_NOT_IMPLEMENTED; diff --git a/ntoskrnl/io/pnpmgr/plugplay.c b/ntoskrnl/io/pnpmgr/plugplay.c index 6c0e84fdb9297..28e243dcd7996 100644 --- a/ntoskrnl/io/pnpmgr/plugplay.c +++ b/ntoskrnl/io/pnpmgr/plugplay.c @@ -186,40 +186,6 @@ IopCaptureUnicodeString(PUNICODE_STRING DstName, PUNICODE_STRING SrcName) return Status; } -static NTSTATUS -IopPnpEnumerateDevice(PPLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA DeviceData) -{ - PDEVICE_OBJECT DeviceObject; - UNICODE_STRING DeviceInstance; - NTSTATUS Status = STATUS_SUCCESS; - - Status = IopCaptureUnicodeString(&DeviceInstance, &DeviceData->DeviceInstance); - if (!NT_SUCCESS(Status)) - { - return Status; - } - - DPRINT("IopPnpEnumerateDevice(%wZ)\n", &DeviceInstance); - - /* Get the device object */ - DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance); - if (DeviceInstance.Buffer != NULL) - { - ExFreePool(DeviceInstance.Buffer); - } - if (DeviceObject == NULL) - { - return STATUS_NO_SUCH_DEVICE; - } - - Status = PiPerformSyncDeviceAction(DeviceObject, PiActionEnumDeviceTree); - - ObDereferenceObject(DeviceObject); - - return Status; -} - - /* * Remove the current PnP event from the tail of the event queue * and signal IopPnpNotifyEvent if there is yet another event in the queue. @@ -1042,23 +1008,26 @@ IopGetDeviceDepth(PPLUGPLAY_CONTROL_DEPTH_DATA DepthData) return Status; } - -static NTSTATUS -IopResetDevice(PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ResetDeviceData) +static +NTSTATUS +PiControlSyncDeviceAction( + _In_ PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA DeviceData, + _In_ PLUGPLAY_CONTROL_CLASS ControlClass) { PDEVICE_OBJECT DeviceObject; NTSTATUS Status; UNICODE_STRING DeviceInstance; - Status = IopCaptureUnicodeString(&DeviceInstance, &ResetDeviceData->DeviceInstance); + ASSERT(ControlClass == PlugPlayControlEnumerateDevice || + ControlClass == PlugPlayControlStartDevice || + ControlClass == PlugPlayControlResetDevice); + + Status = IopCaptureUnicodeString(&DeviceInstance, &DeviceData->DeviceInstance); if (!NT_SUCCESS(Status)) { return Status; } - DPRINT("IopResetDevice(%wZ)\n", &DeviceInstance); - - /* Get the device object */ DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance); if (DeviceInstance.Buffer != NULL) { @@ -1069,7 +1038,25 @@ IopResetDevice(PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ResetDeviceData) return STATUS_NO_SUCH_DEVICE; } - Status = PiPerformSyncDeviceAction(DeviceObject, PiActionResetDevice); + DEVICE_ACTION Action; + + switch (ControlClass) + { + case PlugPlayControlEnumerateDevice: + Action = PiActionEnumDeviceTree; + break; + case PlugPlayControlStartDevice: + Action = PiActionStartDevice; + break; + case PlugPlayControlResetDevice: + Action = PiActionResetDevice; + break; + default: + UNREACHABLE; + break; + } + + Status = PiPerformSyncDeviceAction(DeviceObject, Action); ObDereferenceObject(DeviceObject); @@ -1309,12 +1296,21 @@ NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass, case PlugPlayControlEnumerateDevice: if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA)) return STATUS_INVALID_PARAMETER; - return IopPnpEnumerateDevice((PPLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA)Buffer); + // the Flags field is not used anyway + return PiControlSyncDeviceAction((PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)Buffer, + PlugPlayControlClass); // case PlugPlayControlRegisterNewDevice: // case PlugPlayControlDeregisterDevice: // case PlugPlayControlInitializeDevice: -// case PlugPlayControlStartDevice: + + case PlugPlayControlStartDevice: + case PlugPlayControlResetDevice: + if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)) + return STATUS_INVALID_PARAMETER; + return PiControlSyncDeviceAction((PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)Buffer, + PlugPlayControlClass); + // case PlugPlayControlUnlockDevice: // case PlugPlayControlQueryAndRemoveDevice: @@ -1362,12 +1358,6 @@ NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass, // case PlugPlayControlTargetDeviceRelation: // case PlugPlayControlQueryConflictList: // case PlugPlayControlRetrieveDock: - - case PlugPlayControlResetDevice: - if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)) - return STATUS_INVALID_PARAMETER; - return IopResetDevice((PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)Buffer); - // case PlugPlayControlHaltDevice: // case PlugPlayControlGetBlockedDriverList: From abbc5ba45a2072e4e3e56fd6596955be1c579fdb Mon Sep 17 00:00:00 2001 From: Victor Perevertkin Date: Tue, 16 Mar 2021 02:25:09 +0300 Subject: [PATCH 3/3] [UMPNPMGR][USETUP] Use PlugPlayControlStartDevice in usetup and umpnpmgr Instead of PlugPlayControlResetDevice, PlugPlayControlStartDevice should be used for a newly installed device. For usetup, add a device status check before starting attempt, so we're not touching devices which are already started. CORE-17463 CORE-17490 --- base/services/umpnpmgr/rpcserver.c | 9 +++---- base/setup/usetup/devinst.c | 38 ++++++++++++++++++++++-------- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/base/services/umpnpmgr/rpcserver.c b/base/services/umpnpmgr/rpcserver.c index cf9ba100f1b76..cf49713061a1a 100644 --- a/base/services/umpnpmgr/rpcserver.c +++ b/base/services/umpnpmgr/rpcserver.c @@ -3081,17 +3081,14 @@ static CONFIGRET EnableDeviceInstance( _In_ LPWSTR pszDeviceInstance) { - PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ResetDeviceData; + PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ControlData; CONFIGRET ret = CR_SUCCESS; NTSTATUS Status; DPRINT("Enable device instance %S\n", pszDeviceInstance); - RtlInitUnicodeString(&ResetDeviceData.DeviceInstance, - pszDeviceInstance); - Status = NtPlugPlayControl(PlugPlayControlResetDevice, - &ResetDeviceData, - sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)); + RtlInitUnicodeString(&ControlData.DeviceInstance, pszDeviceInstance); + Status = NtPlugPlayControl(PlugPlayControlStartDevice, &ControlData, sizeof(ControlData)); if (!NT_SUCCESS(Status)) ret = NtStatusToCrError(Status); diff --git a/base/setup/usetup/devinst.c b/base/setup/usetup/devinst.c index 80d93ce1d519d..eee7c25b4ecb8 100644 --- a/base/setup/usetup/devinst.c +++ b/base/setup/usetup/devinst.c @@ -39,20 +39,25 @@ typedef struct /* FUNCTIONS ****************************************************************/ static BOOLEAN -ResetDevice( - IN LPCWSTR DeviceId) +AreDriversLoaded( + IN PCWSTR DeviceId) { - PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ResetDeviceData; + PLUGPLAY_CONTROL_STATUS_DATA PlugPlayData; NTSTATUS Status; - RtlInitUnicodeString(&ResetDeviceData.DeviceInstance, DeviceId); - Status = NtPlugPlayControl(PlugPlayControlResetDevice, &ResetDeviceData, sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)); - if (!NT_SUCCESS(Status)) + RtlInitUnicodeString(&PlugPlayData.DeviceInstance, DeviceId); + PlugPlayData.Operation = PNP_GET_DEVICE_STATUS; + + Status = NtPlugPlayControl(PlugPlayControlDeviceStatus, &PlugPlayData, sizeof(PlugPlayData)); + if (NT_SUCCESS(Status)) + { + return (_Bool)((PlugPlayData.DeviceStatus & DN_DRIVER_LOADED) && + !(PlugPlayData.DeviceStatus & DN_HAS_PROBLEM)); + } + else { - DPRINT1("NtPlugPlayControl() failed with status 0x%08x\n", Status); return FALSE; } - return TRUE; } static BOOLEAN @@ -81,6 +86,10 @@ InstallDriver( NTSTATUS Status; BOOLEAN deviceInstalled = FALSE; + /* First check if the driver needs any action at all */ + if (AreDriversLoaded(DeviceId)) + return TRUE; + /* Check if we know the hardware */ if (!SpInfFindFirstLine(hInf, L"HardwareIdsDatabase", HardwareId, &Context)) return FALSE; @@ -190,8 +199,17 @@ InstallDriver( (wcslen(Driver) + 1) * sizeof(WCHAR)); if (NT_SUCCESS(Status)) { - /* Restart the device, so it will use the driver we registered */ - deviceInstalled = ResetDevice(DeviceId); + /* We've registered the driver, time to start a device */ + PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ControlData; + RtlInitUnicodeString(&ControlData.DeviceInstance, DeviceId); + + Status = NtPlugPlayControl(PlugPlayControlStartDevice, &ControlData, sizeof(ControlData)); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtPlugPlayControl() failed with status 0x%08x\n", Status); + } + + deviceInstalled = NT_SUCCESS(Status); } INF_FreeData(Driver);