Skip to content

Commit

Permalink
HiderStrategy: Do not allow hidden device removal right after creation
Browse files Browse the repository at this point in the history
See commit diff for explanation.

Signed-off-by: Dmitry Fleytman <[email protected]>
  • Loading branch information
Dmitry Fleytman committed Feb 19, 2017
1 parent 6dd93fb commit 6f383cb
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 0 deletions.
53 changes: 53 additions & 0 deletions UsbDk/HiderStrategy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,54 @@ NTSTATUS CUsbDkHiderStrategy::PatchDeviceText(PIRP Irp)
return Irp->IoStatus.Status;
}

bool CUsbDkHiderStrategy::ShouldDenyRemoval() const
{
// There is a phenomena reported for Windows 7 32/64 bits related
// to hidden UsbDk devices that do not have cached driver information.
//
// Upon such a device appearance Windows correctly decides to assign
// the NULL driver to this device, creates correct cached driver information
// and right after that, for some reason, destructs driver stack for this
// device PDO and UsbDk filter gets removed.
//
// Having driver stack destroyed, Windows, apparently, queries device IDs
// again without UsbDk filter attached and gets unmodified information
// as supplied by bus driver.
//
// After that Windows builds driver stack again, including attachment of
// UsbDk filter and loads device driver according to IDs obtained on
// previous step when UsbDk filter was not loaded.
//
// This sequence effectively cancels all UsbDk efforts
// and renders the device visible.
//
// Our experiments show, that in case hidden device turns down Windows
// request for unload right after driver stack creation, Windows gives up
// do not try to rebuild driver stack for this device.
//
// Experiments also show that Windows may request device unload more than
// once, so just failing the first request is not enough, therefore this
// function implements a timer-based logic for turning down early
// unload requests.

static const ULONG REMOVAL_DENIAL_TIMEOUT_MS = 3000;
auto TimePassedSinceCreation = m_RemovalStopWatch.TimeMs();

if (TimePassedSinceCreation <= REMOVAL_DENIAL_TIMEOUT_MS)
{
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_HIDER,
"%!FUNC! Denying removal because %llu ms only passed since creation",
TimePassedSinceCreation);
return true;
}
else
{
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_HIDER,
"%!FUNC! Allowing removal because %llu ms already passed since creation",
TimePassedSinceCreation);
return false;
}
}

NTSTATUS CUsbDkHiderStrategy::PNPPreProcess(PIRP Irp)
{
Expand Down Expand Up @@ -170,6 +218,11 @@ NTSTATUS CUsbDkHiderStrategy::PNPPreProcess(PIRP Irp)
UNREFERENCED_PARAMETER(Status);
return PatchDeviceText(Irp);
});

case IRP_MN_QUERY_REMOVE_DEVICE:
return ShouldDenyRemoval() ? CompleteWithStatus(Irp, STATUS_DEVICE_BUSY)
: CUsbDkNullFilterStrategy::PNPPreProcess(Irp);

default:
return CUsbDkNullFilterStrategy::PNPPreProcess(Irp);
}
Expand Down
8 changes: 8 additions & 0 deletions UsbDk/HiderStrategy.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,16 @@ class CUsbDkHiderStrategy : public CUsbDkNullFilterStrategy
{
public:
virtual NTSTATUS PNPPreProcess(PIRP Irp) override;
virtual NTSTATUS MakeAvailable() override
{
m_RemovalStopWatch.Start();
return STATUS_SUCCESS;
}

private:
void PatchDeviceID(PIRP Irp);
NTSTATUS PatchDeviceText(PIRP Irp);
bool ShouldDenyRemoval() const;

CStopWatch m_RemovalStopWatch;
};

0 comments on commit 6f383cb

Please sign in to comment.