Help!!! Crash due read request to the underlayered driver on IRP_MJ_CREATE!

Hello, all!

We are writing a filter driver and are having problems (like many before by
the looks of it ;)) We are trying to read from file in a completion routine when we receive IRP_MJ_CREATE requests, so that we can identify files we need to decrypt. (we have a header on our files)
In the completion routine for the create we queue a work item to try and do
the read from and return STATUS_MORE_PROCESSING_REQUIRED.
In the worker function we use IoBuildSynchronousFsdRequest to create an IRP
for the read and send it on.

This all should works fine in almost every circumstance, but in my case I’m always crashed! Help!!! Does anyone have any ideas?
We have pasted the offending chunk of code below.

Thanks for any assitance…

//Here we hook all file I/O IRPs
NTSTATUS EfsHookRoutine( PDEVICE_OBJECT HookDevice, IN PIRP Irp )
{
PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
PFILE_OBJECT FileObject;
PHOOK_EXTENSION hookExt;
//
// Extract the file object from the IRP
//
FileObject = currentIrpStack->FileObject;
//
// Point at the device extension, which contains information on which
// file system this IRP is headed for
//
hookExt = HookDevice->DeviceExtension;
//IRP_MJ_CREATE request: let’s try to read file after completion of it
if (currentIrpStack->MajorFunction==IRP_MJ_CREATE &&
!(currentIrpStack->Parameters.Create.Options & FILE_DIRECTORY_FILE))
{
IoSetCompletionRoutine(Irp,EfsHookCreateDone,0,TRUE,TRUE,TRUE );
}
else
{
//all other requests here
IoSetCompletionRoutine(Irp,EfsHookDone,0,TRUE,TRUE,TRUE );
}
//
// Return the results of the call to the caller
//
return IoCallDriver( hookExt->FileSystem, Irp );
}

NTSTATUS EfsHookCreateDone(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context )
{
PIO_STACK_LOCATION IrpSp;
PEFS_WORK efsWorkContext;
int seq = (int)Context;
KIRQL oldirql;
// A request completed - look at the result
IrpSp = IoGetCurrentIrpStackLocation( Irp );
// Queue off to a worker thread if we have to (now I’m always do this)
//if( KeGetCurrentIrql() == DISPATCH_LEVEL )
{
efsWorkContext = ExAllocatePool( NonPagedPool, sizeof(EFS_WORK));
if( efsWorkContext )
{
PHOOK_EXTENSION hookExt=DeviceObject->DeviceExtension;
efsWorkContext->Irp =Irp;
//pass hooked underlayed device object to the work item
efsWorkContext->DeviceObject=hookExt->FileSystem;
efsWorkContext->Sequence =seq;
efsWorkContext->TimeResult =timeResult;
ExInitializeWorkItem( &efsWorkContext->WorkItem,
EfsHookCreateDoneWork, efsWorkContext );
ExQueueWorkItem( &efsWorkContext->WorkItem, CriticalWorkQueue );
}
}
// Now we have to mark Irp as pending if necessary
if( Irp->PendingReturned ) IoMarkIrpPending( Irp );
return STATUS_MORE_PROCESSING_REQUIRED;
}

// Running in the context of a worker thread
// using ExInitializeWorkItem &ExQueueWorkItem
VOID EfsHookCreateDoneWork( PEFS_WORK pContext )
{
PDEVICE_OBJECT DeviceObject;
PFILE_OBJECT FileObject;
PCHAR Buffer;
IO_STATUS_BLOCK IoStatusBlock;
LARGE_INTEGER ByteOffset;
LARGE_INTEGER OrigByteOffset;
// Get the Previous filtered device object
DeviceObject=pContext->DeviceObject;
FileObject=IoGetCurrentIrpStackLocation(pContext->Irp)->FileObject;
// No point in continuing if there is no FileObject
if (FileObject)
{
// Allocate memory for our 512-bytes Buffer
Buffer = ExAllocatePool( NonPagedPool, 512 );
if (Buffer)
{
ByteOffset.QuadPart = 0;
// Store the original byte offset
OrigByteOffset = FileObject->CurrentByteOffset;
//ALWAYS CRASH HERE (in DbgReadFile, after ioCallDriver)!!!
DbgReadFile( pContext->Irp,DeviceObject, FileObject, &ByteOffset, 512, Buffer, &IoStatusBlock );
// Restore the original byte offset
FileObject->CurrentByteOffset = OrigByteOffset;
if (NT_SUCCESS(IoStatusBlock.Status))
{
}
else
{
}
// Free our read buffer
ExFreePool( Buffer );
}
}
//Complete the Create Request
IoCompleteRequest( pContext->Irp, IO_NO_INCREMENT );
// Free the create context data
ExFreePool( pContext );
}

VOID DbgReadFile( PIRP pIrp, PDEVICE_OBJECT DeviceObject, PFILE_OBJECT
FileObject, PLARGE_INTEGER Offset, ULONG Length, PCHAR Buffer, PIO_STATUS_BLOCK IoStatusBlock )
{
KEVENT kEvent;
PIRP pReadIrp;
NTSTATUS ntStatus;
// Initialise an event to wait for after calling the previous driver
KeInitializeEvent( &kEvent, NotificationEvent, FALSE );
// Build an Irp for the read
pReadIrp=(IRP_MJ_READ,DeviceObject,Buffer,Length,Offset,&kEvent,IoStatusBlock );
if (pReadIrp)
{
PIO_STACK_LOCATION pReadStack = IoGetNextIrpStackLocation( pReadIrp );
// Caching? no thank you maam!
pReadIrp->Flags = IRP_NOCACHE | IRP_READ_OPERATION;
pReadIrp->Tail.Overlay.Thread = pIrp->Tail.Overlay.Thread;
pReadIrp->RequestorMode = KernelMode;
// We need a FileObject to identify the file we are reading
pReadStack->FileObject = FileObject;
pReadStack->DeviceObject = DeviceObject;
// Call on to the previous driver
ntStatus = IoCallDriver( DeviceObject, pReadIrp );
if (ntStatus == STATUS_PENDING)
{
// Wait for the Irp to complete if it is pending
KeWaitForSingleObject( &kEvent, Executive, KernelMode, FALSE, NULL );
}
else IoStatusBlock->Status = ntStatus;
}
else
{
IoStatusBlock->Status=STATUS_INSUFFICIENT_RESOURCES;
IoStatusBlock->Information=0;
}
}

Code looks like without any errors, but in real life it crashes…
Why? If you notice some criminal, let me know, please!

Kind Regards and thanks in advance

Valery A. Boronin,
System Software Engineer, Novosoft
http://www.novosoft.ru