Filter driver programmers should be very familiar with IoAttachDeviceToDeviceStack that allows a device to attach to (aka filter) the top device of the device stack. This function is defined in WDK headers like thus

IoAttachDeviceToDeviceStack declaration

The returned device object is the one that was just attached to by the IoAttachDeviceToDeviceStack call. Since the returned device is the next (lower) device in chain, this is typically maintained in the device extension and later used to pass IRPs down the chain (used as first parameter to IoCallDriver).1

However there is a problem with this. If, in the time window between attachment to device stack is complete and lower device is populated in the filter device extension, an IRP is seen by the filter device, the filter device dispatch routine will potentially attempt to pass on the IRP to invalid (hopefully NULL) device object stored in extension and end up blue screening the machine.

Let me explain. Let us say a filter driver is calling IoAttachDeviceToDeviceStack like thus -

if(NULL != (pMyDeviceExtension->NextDevice = 
      IoAttachDeviceToDeviceStack(pMyFilterDevice, pDeviceToFilter)))
{   //successfully attached

When IoAttachDeviceToDeviceStack returns but the return value has not been assigned to NextDevice, if an IRP is seen by the filter device, the dispatch routine will end up using previous invalid contents of NextDevice.

The solution is to use IoAttachDeviceToDeviceStackSafe which fills in the pointer to NextDevice in a third OUT parameter to avoid race condition. So the code above would look like the following -

     pDeviceToFilter, &pMyDeviceExtension->NextDevice)))
{   //successfully attached

The documentation for IoAttachDeviceToDeviceStackSafe is a little bit confusing. All references to AttachedToDeviceObject in there correspond to whatever field a driver uses to maintain the lower device object in its device extension structure (in the example above AttachedToDeviceObject is in fact NextDevice). Also it should be noted that the I/O system database lock claimed by IoAttachDeviceToDeviceStackSafe is also claimed in IoAttachDeviceToDeviceStack but what IoAttachDeviceToDeviceStackSafe does additionally is before releasing the lock updates the OUT parameter thereby closing the window for race condition.

When I saw this race condition in a file system filter on XP SP2, it was a surprise since the filter expected no IRPs until DO_DEVICE_INITIALIZING was cleared in DEVICE_OBJECT.Flags. That assumption proved to be wrong since it did get IRPs while DO_DEVICE_INITIALIZING was set.2

So then what does this Microsoft article mean3 when it says

The purpose of DO_DEVICE_INITIALIZING is to prevent other components from sending I/O to a device before the driver has finished initializing the device object.

You be the judge.

1A device can figure out dynamically which is the lower device by calling IoGetLowerDeviceObject, but IoGetLowerDeviceObject takes a reference on the device object returned and therefore needs a call to ObDereferenceObject on the device object returned afterwards.

2This behaviour may be different for plug and play (PnP) device drivers.

3My understanding currently is that since IoCallDriver does not check for DO_DEVICE_INITIALIZING, if a filter device is on device stack (which is as soon as IoAttachDeviceToDeviceStack or IoAttachDeviceToDeviceStackSafe or IoAttachDevice is done attaching), the filter device will start seeing IRPs and therefore should be prepared to do so.

Also close inspection of IO Manager routines and running some tests reveals that there are two operations prevented when DO_DEVICE_INITIALIZING is set on the DEVICE_OBJECT (a) opening the device object itself (someone attempting to get a handle to the filter device object) (b) attaching to the device object (someone attempting to layer on top of the filter device object)

Tagged with →  
Share →

2 Responses to IoAttachDeviceToDeviceStack gotcha

  1. Tom says:

    It’s very useful! We can’t recognize real difference between IoAttachDeviceToDeviceStackSafe and IoAttachDeviceToDeviceStack by reading Windows Driver Kit.

  2. Satya Das says:

    Thanks for dropping by. I am glad you found it useful.

Leave a Reply

Your email address will not be published. Required fields are marked *


Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop us a note so we can take care of it!

Visit our friends!

A few highly recommended friends...

Set your Twitter account name in your settings to use the TwitterBar Section.