January 2008 - Posts

Bug in MSDN: TDI_EVENT_RECEIVE_DATAGRAM & it's handler

If you ever wanted to handle TDI_EVENT_RECEIVE_DATAGRAM (http://msdn2.microsoft.com/en-us/library/ms801156.aspx) event handler in TDI, you would notice that it's declaration is a bit strange(http://msdn2.microsoft.com/en-us/library/ms801622.aspx):

NTSTATUS
  ClientEventReceive(
    IN PVOID  TdiEventContext,
    IN CONNECTION_CONTEXT  ConnectionContext,
    IN ULONG  ReceiveFlags,
    IN ULONG  BytesIndicated,
    IN ULONG  BytesAvailable,
    OUT ULONG  *BytesTaken,
    IN PVOID  Tsdu,
    OUT PIRP  *IoRequestPacket
    );

Guess what? It's declaration is the same as to a handler of TDI_EVENT_RECEIVE which sets event handlers for TCP protocol and not for UDP! If you want to handle UDP incoming data at TDI level, you most likely will need to find a correct declaration of handler function, because using declaration from MSDN will give your driver one more chance to blue screen :)

Thanks to www.osronline.com, I found a correct declaration: http://www.osronline.com/ddkx/w98ddk/vxdtdi_9lt9.htm which should have the following form:

NTSTATUS ClientEventReceiveDatagram(
    IN PVOID TdiEventContext,
    IN LONG SourceAddressLength,
    IN PVOID SourceAddress,
    IN LONG OptionsLength,
    IN PVOID Options,
    IN ULONG ReceiveDatagramFlags,
    IN ULONG BytesIndicated,
    IN ULONG BytesAvailable,
    OUT ULONG *BytesTaken,
    IN PVOID Tsdu,
    OUT PIRP *IoRequestPacket);

The most interesting thing, is that I spent 30 minutes trying to figure out what's wrong in my code, until I noticed the presence of ConnectionContext param in the declaration of handler, so I asked myself: why would I recieve a connection context when handling connectionless protocol data ... ? So I started googling.

Seems like this issue touches both local documentation for WDK and online documentation at http://msdn2.microsoft.com

DRIVER_VERIFIER_IOMANAGER_VIOLATION in Windows Server 2003 SP2 with latest updates ON

Recently, I've received following error when trying to test my TDI filter driver on Server 2003 SP2 with latest updates ON:

DRIVER_VERIFIER_IOMANAGER_VIOLATION (c9)
Arguments: Arg1: 00000208, (Fatal error) This IRP is about to run out of stack locations. Someone may have forwarded this IRP from another stack. (IRP specified.)

This violation message appeared, when I run applications, which make network connections from network drives. Attaching debugger to debugging session gives more information:

***********************************************************************
* THIS VALIDATION BUG IS FATAL AND WILL CAUSE THE VERIFIER TO HALT    *
* WINDOWS (BUGCHECK) WHEN THE MACHINE IS NOT UNDER A KERNEL DEBUGGER! *
***********************************************************************

WDM DRIVER ERROR: [2k03sp2bug.sys @ 0xF77E00C5] This IRP is about to run out
                  of stack locations. Someone may have forwarded this IRP
                  from another stack (Irp = 859E8F48 ).
IRP_MJ_INTERNAL_DEVICE_CONTROL
[ DevObj=849C3E18, FileObject=849A93D0, Parameters=00006C36 00000020 00000000 00000000 ]
http://www.microsoft.com/hwdq/bc/default.asp?os=5.2.3790&major=0xc9&minor=0x208&lang=0x9
Break, Ignore, Zap, Remove, Disable all (bizrd)?

If I choose Ignore, everything goes fine, and there are no fatal errors, however, I don't think this is a normal behavior, so I decided to create a small TDI filter driver, which layers over \Device\TCP & \Device\UDP providers, and works in pass through mode to demonstrate the problem. I hope this small example will help to eliminate the problem.

The driver is really simple, it calls IoAttachDevice, and set's IO function for handling IRP_MJ controls codes. The DeviceIO function is implemented as:

NTSTATUS Test2k03SP2Bug_DispatchIO(IN PDEVICE_OBJECT pDeviceObject, IN PIRP Irp)

 /// simply dispatch the IRP down to stack and nothing else
 NTSTATUS   ntStatusOfDispatch = STATUS_SUCCESS;
 PIO_STACK_LOCATION pIRPs    = IoGetCurrentIrpStackLocation(Irp);

 if (pDeviceObject == g_TCPOBJ)
 {
  IoSkipCurrentIrpStackLocation(Irp);

  ntStatusOfDispatch = IoCallDriver(g_TCPOLDOBJ, Irp);
 }
 else if (pDeviceObject == g_UDPOBJ)
 {
  IoSkipCurrentIrpStackLocation(Irp);

  ntStatusOfDispatch = IoCallDriver(g_UDPOLDOBJ, Irp);
 }
 else /// unknown DO, do complete IRP
 {
  Irp->IoStatus.Status = ntStatusOfDispatch;
  IoCompleteRequest(Irp, IO_NO_INCREMENT);
 }

 return ntStatusOfDispatch;
}

As you can see, it simply forwards IRP's to stack, no more processing is done in IO function. Complete sources for driver are attached in this post. Compile them, configure verifier to verify driver with all possible verification tests:

verifier.exe /all /driver 2k03sp2bug.sys

Load the driver. Reboot machine (to allow verifier start checks). Find any network share, run application (from share) which makes intensive network traffic (UDP & TCP) and catch BSOD (if you boot with /DEBUG system will halt, so you can attach debugger, otherwise, you will see BSOD with DRIVER_VERIFIER_IOMANAGER_VIOLATION.