Driver function causing a BSOD -- Buffer overflow -- why?

I have a very simple completion routine for the first occurance of (IRP_MJ_READ or IRP_MJ_WRITE, whichever occurs first) that does nothing more than read from the MBR of a raw disk. The method itself performs exactly as I require it to… however as the method ends and returns, it causes a BSOD indicating that there was a buffer overflow possibly with ‘MBRBuffer’. I don’t understand why and more importantly how to resolve it so that it stops crashing.

Thanks for any help in advance.

NTSTATUS
MyIoCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
PIRP irp;
KEVENT Event;
IO_STATUS_BLOCK ioStatus;
NTSTATUS status;
IO_STATUS_BLOCK file_status;
OBJECT_ATTRIBUTES obj_attrib;
BYTE MBRBuffer[513];
LARGE_INTEGER offset;

UNREFERENCED_PARAMETER(Context);

if (Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}

// Open the raw disk which we are filtering
InitializeObjectAttributes(&obj_attrib, &deviceExtension->PhysicalDeviceName,
OBJ_CASE_INSENSITIVE, NULL, NULL);
status = ZwCreateFile(&deviceExtension->MBR,
FILE_READ_DATA | FILE_WRITE_DATA,
&obj_attrib,
&file_status,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN,
FILE_NON_DIRECTORY_FILE,
NULL,
0);

// Read the MBR from raw disk which we are filtering
if (deviceExtension->MBR != NULL){
offset.QuadPart = 0;
status = ZwReadFile(deviceExtension->MBR, NULL, NULL, NULL,
&ioStatus, MBRBuffer, (sizeof(MBRBuffer)-1),
&offset, NULL);
}
// Close the raw disk which we are filtering
status = ZwClose(deviceExtension->MBR);
deviceExtension->MBR = NULL;

return STATUS_SUCCESS;
} // DARKIoCompletion

Perhaps unrelated to what is reported as a buffer overrun but how is it you
are guaranteeing PASSIVE_LEVEL execution to meet the requirements of ZwXxx()
and yet you seem to be running in an I/O Completion Routine which AFAIK has
IRQL <= DISPATCH_LEVEL as its IRQL contract?

Good Luck,
Dave Cattley

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@gmail.com
Sent: Sunday, March 28, 2010 10:54 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] Driver function causing a BSOD – Buffer overflow – why?

I have a very simple completion routine for the first occurance of
(IRP_MJ_READ or IRP_MJ_WRITE, whichever occurs first) that does nothing more
than read from the MBR of a raw disk. The method itself performs exactly as
I require it to… however as the method ends and returns, it causes a BSOD
indicating that there was a buffer overflow possibly with ‘MBRBuffer’. I
don’t understand why and more importantly how to resolve it so that it stops
crashing.

Thanks for any help in advance.

NTSTATUS
MyIoCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION)
DeviceObject->DeviceExtension;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
PIRP irp;
KEVENT Event;
IO_STATUS_BLOCK ioStatus;
NTSTATUS status;
IO_STATUS_BLOCK file_status;
OBJECT_ATTRIBUTES obj_attrib;
BYTE MBRBuffer[513];
LARGE_INTEGER offset;

UNREFERENCED_PARAMETER(Context);

if (Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}

// Open the raw disk which we are filtering
InitializeObjectAttributes(&obj_attrib,
&deviceExtension->PhysicalDeviceName,
OBJ_CASE_INSENSITIVE, NULL, NULL);
status = ZwCreateFile(&deviceExtension->MBR,
FILE_READ_DATA | FILE_WRITE_DATA,
&obj_attrib,
&file_status,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN,
FILE_NON_DIRECTORY_FILE,
NULL,
0);

// Read the MBR from raw disk which we are filtering
if (deviceExtension->MBR != NULL){
offset.QuadPart = 0;
status = ZwReadFile(deviceExtension->MBR, NULL, NULL, NULL,
&ioStatus, MBRBuffer, (sizeof(MBRBuffer)-1),
&offset, NULL);
}
// Close the raw disk which we are filtering
status = ZwClose(deviceExtension->MBR);
deviceExtension->MBR = NULL;

return STATUS_SUCCESS;
} // DARKIoCompletion


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

Turn on driver verifier. Also, do not put 513 bytes on the stack, allocate that from pool. That is way too large to put on the stack.

d

tiny phone keyboard + fat thumbs = you do the muth

-----Original Message-----
From: xxxxx@gmail.com
Sent: Sunday, March 28, 2010 7:53 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] Driver function causing a BSOD – Buffer overflow – why?

I have a very simple completion routine for the first occurance of (IRP_MJ_READ or IRP_MJ_WRITE, whichever occurs first) that does nothing more than read from the MBR of a raw disk. The method itself performs exactly as I require it to… however as the method ends and returns, it causes a BSOD indicating that there was a buffer overflow possibly with ‘MBRBuffer’. I don’t understand why and more importantly how to resolve it so that it stops crashing.

Thanks for any help in advance.

NTSTATUS
MyIoCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
PIRP irp;
KEVENT Event;
IO_STATUS_BLOCK ioStatus;
NTSTATUS status;
IO_STATUS_BLOCK file_status;
OBJECT_ATTRIBUTES obj_attrib;
BYTE MBRBuffer[513];
LARGE_INTEGER offset;

UNREFERENCED_PARAMETER(Context);

if (Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}

// Open the raw disk which we are filtering
InitializeObjectAttributes(&obj_attrib, &deviceExtension->PhysicalDeviceName,
OBJ_CASE_INSENSITIVE, NULL, NULL);
status = ZwCreateFile(&deviceExtension->MBR,
FILE_READ_DATA | FILE_WRITE_DATA,
&obj_attrib,
&file_status,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN,
FILE_NON_DIRECTORY_FILE,
NULL,
0);

// Read the MBR from raw disk which we are filtering
if (deviceExtension->MBR != NULL){
offset.QuadPart = 0;
status = ZwReadFile(deviceExtension->MBR, NULL, NULL, NULL,
&ioStatus, MBRBuffer, (sizeof(MBRBuffer)-1),
&offset, NULL);
}
// Close the raw disk which we are filtering
status = ZwClose(deviceExtension->MBR);
deviceExtension->MBR = NULL;

return STATUS_SUCCESS;
} // DARKIoCompletion


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Along with the suggestion from Doron:-

You are issuing ZwCalls which in turn will come from top of stack.
Are you setting completion for every IO in your filter? This could create
problems.

Regards
Deepak

On Mon, Mar 29, 2010 at 8:59 AM, Doron Holan wrote:

> Turn on driver verifier. Also, do not put 513 bytes on the stack, allocate
> that from pool. That is way too large to put on the stack.
>
> d
>
> tiny phone keyboard + fat thumbs = you do the muth
>
>
>
> -----Original Message-----
> From: xxxxx@gmail.com
> Sent: Sunday, March 28, 2010 7:53 PM
> To: Windows System Software Devs Interest List
> Subject: [ntdev] Driver function causing a BSOD – Buffer overflow – why?
>
>
> I have a very simple completion routine for the first occurance of
> (IRP_MJ_READ or IRP_MJ_WRITE, whichever occurs first) that does nothing more
> than read from the MBR of a raw disk. The method itself performs exactly as
> I require it to… however as the method ends and returns, it causes a BSOD
> indicating that there was a buffer overflow possibly with ‘MBRBuffer’. I
> don’t understand why and more importantly how to resolve it so that it stops
> crashing.
>
> Thanks for any help in advance.
>
> NTSTATUS
> MyIoCompletion(
> IN PDEVICE_OBJECT DeviceObject,
> IN PIRP Irp,
> IN PVOID Context
> )
> {
> PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION)
> DeviceObject->DeviceExtension;
> PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
> PIRP irp;
> KEVENT Event;
> IO_STATUS_BLOCK ioStatus;
> NTSTATUS status;
> IO_STATUS_BLOCK file_status;
> OBJECT_ATTRIBUTES obj_attrib;
> BYTE MBRBuffer[513];
> LARGE_INTEGER offset;
>
> UNREFERENCED_PARAMETER(Context);
>
> if (Irp->PendingReturned) {
> IoMarkIrpPending(Irp);
> }
>
> // Open the raw disk which we are filtering
> InitializeObjectAttributes(&obj_attrib,
> &deviceExtension->PhysicalDeviceName,
> OBJ_CASE_INSENSITIVE, NULL, NULL);
> status = ZwCreateFile(&deviceExtension->MBR,
> FILE_READ_DATA | FILE_WRITE_DATA,
> &obj_attrib,
> &file_status,
> NULL,
> FILE_ATTRIBUTE_NORMAL,
> FILE_SHARE_READ | FILE_SHARE_WRITE,
> FILE_OPEN,
> FILE_NON_DIRECTORY_FILE,
> NULL,
> 0);
>
> // Read the MBR from raw disk which we are filtering
> if (deviceExtension->MBR != NULL){
> offset.QuadPart = 0;
> status = ZwReadFile(deviceExtension->MBR, NULL, NULL, NULL,
> &ioStatus, MBRBuffer, (sizeof(MBRBuffer)-1),
> &offset, NULL);
> }
> // Close the raw disk which we are filtering
> status = ZwClose(deviceExtension->MBR);
> deviceExtension->MBR = NULL;
>
> return STATUS_SUCCESS;
> } // DARKIoCompletion
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

Dave -

how is it you are guaranteeing PASSIVE_LEVEL execution to meet the requirements of ZwXxx()
and yet you seem to be running in an I/O Completion Routine which AFAIK has
IRQL <= DISPATCH_LEVEL as its IRQL contract?

You are correct that I am not guaranteeing the correct IRQL, though I probably should be. I will admit I assumed that it was running at PASSIVE_LEVEL. But just saw it jump to IRQL:2 after running through a build with Doron’s suggestion of allocating the buffer from the pool. How would you recommend to guarantee running at IRQL: PASSIVE_LEVEL?

Doron -

Turn on driver verifier. Also, do not put 513 bytes on the stack, allocate that from pool. That is
way too large to put on the stack.
I had tried allocating the 513 bytes out of the pool but was never able to get a successful read from the disk.
PBYTE pMBRBuffer;
ULONG MBRSize = 513;
pMBRBuffer = ExAllocatePool(PagedPool, MBRSize);
memset(pMBRBuffer, 0x00, MBRSize);
status = ZwReadFile(deviceExtension->MBR, NULL, NULL, NULL, &ioStatus, pMBRBuffer,
MBRSize, &offset, NULL);

But that sometimes results in NT STATUS code: 3221225485 (an invalid parameter was passed to a service or function) other times it BSODS… though based on what Dave said, I just ran it again and it is a IRQL:2, definetly the wrong level to call the Zw functions, though other times it is at IRQL:0.

BACKGROUND INFO:
I figured I would provide some background information for what I am trying to do and have done so far to help you understand what I am trying to do and perhaps make suggestions to get to that goal. I am trying to build a disk driver (based off of diskperf.sys in the DDK) that enforces the Bel LaPadulla (BLP) security model. I have a working generic disk filter driver, and have been trying various locations to look at each disk device for a marker (that I define) in the MBR preferably before the OS interacts with the data on the device, that identifies the disk’s status according to the BLP model, and then takes appropriate action (such as change a disk device to read only by the all groups via ZwSetSecurityObject(). I have first tried in the completion routine of START_DEVICE but it soon became apparent that the disks were not ready for IO operations yet, then I tried in the function for IRP_MJ_READ/WRITE dispatch I have, but I figured I can’t call a IO operation while I’m in the very first IO operation for the disk, so now I was trying the iocompletion routine for the very first IO operation conducted on that disk.

So I guess the big question then for anyone to answer is how/where can I perform the ZwRead/WriteFile ops and the ZwSetSecurityObject on the disk device without causing BSODS, like I am now?

Here is a thought, if I were to in my IRP_MJ_READ/WRITE dispatch change the Zw[Read/Write]File to constructed IRPs and just pass them to the next driver below me in theI could in theory still read/write to the MBR correct? How then could I change the disk device security say to SDDL: SDDL_DEVOBJ_SYS_ALL_ADM_ALL?

Thank you.

Deepak,

*Hey my friend!*

You are issuing ZwCalls which in turn will come from top of stack. Are you setting completion for > every IO in your filter? This could create problems.

No I have a flag that is set during Device_Add called IOFirstTime set to True. Then in the IO dispatch routine it looks to see if this flag is true, if it is sets the flag to false and then performs at this moment the setcompletion routine, and then passes the current IRP down the device stack. All other IO IRPs are forwarded straight on down without touching them from that point forward as I don’t care what happens after that first IO operation.

Brian

1 allocate with exallocatepoolwith tag
2 allocate from nonpaged pool
3 queue a work item ans return status_more_processing_required from the completion to get to passive
4 complete the irp in the work item after you have read the mbr

d

tiny phone keyboard + fat thumbs = you do the muth

-----Original Message-----
From: xxxxx@gmail.com
Sent: Sunday, March 28, 2010 9:53 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Driver function causing a BSOD – Buffer overflow – why?

Dave -

> how is it you are guaranteeing PASSIVE_LEVEL execution to meet the requirements of ZwXxx()
> and yet you seem to be running in an I/O Completion Routine which AFAIK has
> IRQL <= DISPATCH_LEVEL as its IRQL contract?

You are correct that I am not guaranteeing the correct IRQL, though I probably should be. I will admit I assumed that it was running at PASSIVE_LEVEL. But just saw it jump to IRQL:2 after running through a build with Doron’s suggestion of allocating the buffer from the pool. How would you recommend to guarantee running at IRQL: PASSIVE_LEVEL?

Doron -

> Turn on driver verifier. Also, do not put 513 bytes on the stack, allocate that from pool. That is
> way too large to put on the stack.
I had tried allocating the 513 bytes out of the pool but was never able to get a successful read from the disk.
PBYTE pMBRBuffer;
ULONG MBRSize = 513;
pMBRBuffer = ExAllocatePool(PagedPool, MBRSize);
memset(pMBRBuffer, 0x00, MBRSize);
status = ZwReadFile(deviceExtension->MBR, NULL, NULL, NULL, &ioStatus, pMBRBuffer,
MBRSize, &offset, NULL);

But that sometimes results in NT STATUS code: 3221225485 (an invalid parameter was passed to a service or function) other times it BSODS… though based on what Dave said, I just ran it again and it is a IRQL:2, definetly the wrong level to call the Zw functions, though other times it is at IRQL:0.

BACKGROUND INFO:
I figured I would provide some background information for what I am trying to do and have done so far to help you understand what I am trying to do and perhaps make suggestions to get to that goal. I am trying to build a disk driver (based off of diskperf.sys in the DDK) that enforces the Bel LaPadulla (BLP) security model. I have a working generic disk filter driver, and have been trying various locations to look at each disk device for a marker (that I define) in the MBR preferably before the OS interacts with the data on the device, that identifies the disk’s status according to the BLP model, and then takes appropriate action (such as change a disk device to read only by the all groups via ZwSetSecurityObject(). I have first tried in the completion routine of START_DEVICE but it soon became apparent that the disks were not ready for IO operations yet, then I tried in the function for IRP_MJ_READ/WRITE dispatch I have, but I figured I can’t call a IO operation while I’m in the very first IO operation for the disk, so now I was trying the iocompletion routine for the very first IO operation conducted on that disk.

So I guess the big question then for anyone to answer is how/where can I perform the ZwRead/WriteFile ops and the ZwSetSecurityObject on the disk device without causing BSODS, like I am now?

Here is a thought, if I were to in my IRP_MJ_READ/WRITE dispatch change the Zw[Read/Write]File to constructed IRPs and just pass them to the next driver below me in theI could in theory still read/write to the MBR correct? How then could I change the disk device security say to SDDL: SDDL_DEVOBJ_SYS_ALL_ADM_ALL?

Thank you.


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Doran -

1 allocate with exallocatepoolwith tag
2 allocate from nonpaged pool
3 queue a work item ans return status_more_processing_required from the completion to get to >passive
4 complete the irp in the work item after you have read the mbr

I appreciate your feedback, however I’m a little confused with your directions. I understand how to do 1) & 2), that is pretty straight forward.

ULONG MBRSize = 513;
pMBRBuffer = ExAllocatePoolWithTag(NonPagedPool, MBRSize, ‘1gaT’);

But where are you suggesting to do this, in my IRP_MJ_READ/WRITE dispatch routine or the IoCompletionRoutine?

  1. I am not sure how to do any of that.

  2. Do I perform read/write the MBR with Zw calls and perform the security object adjustment all in the work item? The work item does the Irp completion call, got it…

Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;

> How would you recommend to guarantee running at IRQL: PASSIVE_LEVEL?

Deferring the completion processing to system thread that you create in your
driver. Perhaps it would be OK to use a Work Item. I am not sure given
what your processing is if it is short enough duration and ‘safe’ for
processing on a Work Item.

Good Luck,
Dave Cattley

Doran & Dave –

3 queue a work item ans return status_more_processing_required from the
completion to get to >passive
Looking at the MSDN page (http://msdn.microsoft.com/en-us/library/aa490317.aspx) for work items indicates that using them is a WDF feature, and my driver is written in WDM. I didn’t think you could switch back and forth between the two driver styles. Can something similar be called still? If so what?

Deferring the completion processing to system thread that you create in your driver. Perhaps it
would be OK to use a Work Item. I am not sure given what your processing is if it is short
enough duration and ‘safe’ for processing on a Work Item.

I googled ‘create a system thread in windows kernel driver’ and the top result was a MSDN page (http://msdn.microsoft.com/en-us/library/aa490176.aspx) for a system worker thread that appears to do the same thing that the WDF work item does, but uses IoAllocateWorkItem, IoQueueWorkItem, & IoFreeWorkItem.

Dave I see your concern with the work item “If one of these routines runs for too long (if it contains an indefinite loop, for example) or waits for too long, the system can deadlock. Therefore, if a driver requires long periods of delayed processing, it should instead call PsCreateSystemThread to create its own system thread.” Would simply doing a ZwCreateFile, ZwReadFile, 4 if statements, a possible ZwWriteFile in one of those ifs, a ZwSetSecurityObject in 2 of the ifs and a ZwClose be too much delay processing?

Can either of you recommend a good example of performing this type of operation?

Thanks! My head is starting to hurt from all of this, but I know that means I’m learning!
Brian

Work items are not specific to kmdf. You can use the io apis you listed below. The file operations you want to do are fine for a work item, no need to create your own thread

d

tiny phone keyboard + fat thumbs = you do the muth

-----Original Message-----
From: xxxxx@gmail.com
Sent: Monday, March 29, 2010 3:14 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Driver function causing a BSOD – Buffer overflow – why?

Doran & Dave –

>3 queue a work item ans return status_more_processing_required from the
completion to get to >passive
Looking at the MSDN page (http://msdn.microsoft.com/en-us/library/aa490317.aspx) for work items indicates that using them is a WDF feature, and my driver is written in WDM. I didn’t think you could switch back and forth between the two driver styles. Can something similar be called still? If so what?

> Deferring the completion processing to system thread that you create in your driver. Perhaps it
> would be OK to use a Work Item. I am not sure given what your processing is if it is short
> enough duration and ‘safe’ for processing on a Work Item.

I googled ‘create a system thread in windows kernel driver’ and the top result was a MSDN page (http://msdn.microsoft.com/en-us/library/aa490176.aspx) for a system worker thread that appears to do the same thing that the WDF work item does, but uses IoAllocateWorkItem, IoQueueWorkItem, & IoFreeWorkItem.

Dave I see your concern with the work item “If one of these routines runs for too long (if it contains an indefinite loop, for example) or waits for too long, the system can deadlock. Therefore, if a driver requires long periods of delayed processing, it should instead call PsCreateSystemThread to create its own system thread.” Would simply doing a ZwCreateFile, ZwReadFile, 4 if statements, a possible ZwWriteFile in one of those ifs, a ZwSetSecurityObject in 2 of the ifs and a ZwClose be too much delay processing?

Can either of you recommend a good example of performing this type of operation?

Thanks! My head is starting to hurt from all of this, but I know that means I’m learning!
Brian


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

xxxxx@gmail.com wrote:

Looking at the MSDN page (http://msdn.microsoft.com/en-us/library/aa490317.aspx) for work items indicates that using them is a WDF feature, and my driver is written in WDM.

WdfWorkItemCreate, WdfWorkItemEnqueue, and its friends are the WDF
wrappers around the WDM APIs IoInitializeWorkItem, IoQueueWorkItem, and
so on. Those are what you need.

I didn’t think you could switch back and forth between the two driver styles.

That’s not really true, but…

KMDF is a layer on top of WDM. So, if you are a KMDF driver, all of WDM
is still available to you. However, if you are not a KMDF driver, then
none of KMDF is available to you. So, in your case, you can’t use the
Wdf versions. You need to use the Io versions.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Doran -

Work items are not specific to kmdf. You can use the io apis you listed below.
The file operations you want to do are fine for a work item, no need to create
your own thread

Thanks.

So I think this following code snippet captures everything you have told me Doran. Did I miss anything or improperly format anything?

NTSTATUS
MyIoCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PIO_WORKITEM MyWorkItem;
if (Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}
MyWorkItem = IoAllocateWorkItem( DeviceObject );
IoQueueWorkItem( MyWorkItem, MyWorkItemRoutine, DelayedWorkQueue, Context );
IoFreeWorkItem( MyWorkItem );
return status_more_processing_required;

IO_WORKITEM_ROUTINE MyWorkItemRoutine;
VOID MyWorkItemRoutine(
__in PDEVICE_OBJECT DeviceObject,
__in_opt PVOID Context )
{
ULONG MBRSize = 512;
pMBRBuffer = ExAllocatePoolWithTag(NonPagedPool, MBRSize, ‘1gaT’);

…Do ZwCreateFile, ZwReadFile, logic checks, & ZwCloseFile…

ExFreePool(pMBRBuffer);
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}

xxxxx@gmail.com wrote:

So I think this following code snippet captures everything you have told me Doran. Did I miss anything or improperly format anything?

NTSTATUS
MyIoCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PIO_WORKITEM MyWorkItem;
if (Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}
MyWorkItem = IoAllocateWorkItem( DeviceObject );
IoQueueWorkItem( MyWorkItem, MyWorkItemRoutine, DelayedWorkQueue, Context );
IoFreeWorkItem( MyWorkItem );
return status_more_processing_required;

You can’t free the work item while it is queued. You need to do the
IoFreeWorkItem call inside the work item routine. That means you’ll
have to tuck the work item pointer in the device extension, or in the
Context value.

You’re also going to need to pass the IRP into the work item, so you
might want to create a structure to hold the IRP and the PIO_WORKITEM.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Thanks Tim for the responce. I’m going to code this up in a bit and will post back if it works or if I have more questions.

Brian

Ok, the work item works perfectly, but something is still amiss. No BSODs, but windows never finishes loading in the VM. It just stays at the splash screen with the progress bar moving after completing my routine and I hit ‘g’ on WinDbg. Would someone mind double checking my work? I have a feeling something did not get returned correctly and it may be stuck waiting for something that is already done. As the VM has been at the same point on the splash screen during the entire time I have written this message. Soo close…

NTSTATUS
MyReadWrite(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
KEVENT Event;
NTSTATUS status;

KeInitializeEvent(&Event, NotificationEvent, FALSE);
if (deviceExtension->IOFirstTime){
deviceExtension->IOFirstTime = 0;//Set to False

// copy the irpstack for the next device
IoCopyCurrentIrpStackLocationToNext(Irp);

// set a completion routine
IoSetCompletionRoutine(Irp, DARKIoCompletion, &Event, TRUE, TRUE, TRUE);

// call the next lower device
status = IoCallDriver(deviceExtension->TargetDeviceObject, Irp);

// wait for the actual completion
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
status = Irp->IoStatus.Status;
}
return status;
}
IoSkipCurrentIrpStackLocation(Irp);

return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
} // end MyReadWrite()

NTSTATUS
MyIoCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);

if (Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}
deviceExtension->WorkItem = IoAllocateWorkItem( DeviceObject );
deviceExtension->irp = Irp;
IoQueueWorkItem( deviceExtension->WorkItem, MyWorkItemRoutine, DelayedWorkQueue,
Context );

return(STATUS_MORE_PROCESSING_REQUIRED);
} // end MyIoCompletion

VOID
MyWorkItemRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PVOID Context
)
{
PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
//…//
PBYTE pMBRBuffer;

pMBRBuffer = ExAllocatePoolWithTag(NonPagedPool, (ULONG)MBR_SIZE, ‘1gaT’);

//…Do ZwCreateFile, ZwReadFile, logic checks, & ZwCloseFile…//

// Close the raw disk which we are filtering
status = ZwClose(deviceExtension->MBR);
deviceExtension->irp->IoStatus.Status = status;
ExFreePool(pMBRBuffer);

// Free the WorkItem from the queue
IoFreeWorkItem(deviceExtension->WorkItem);

// Complete the Irp which got us here
IoCompleteRequest(deviceExtension->irp, IO_NO_INCREMENT);
} // end MyWorkItemRoutine

HAHAHA!! That was retartedly easy… after posting I was walking through the functions over and over again… trying to figure out what was not returning correctly… FOUND IT!

KeSetEvent(Event, IO_NO_INCREMENT, FALSE);

was missing from MyIoCompletion(). I added that right above the return and low and behold it works. Yay! Now to finish implementing and testing the logic of the Work Item Routine. Hopefully this is the last post…

Thank you all.

Why are you calling the TargetDeviceObject twice?

wrote in message news:xxxxx@ntdev…
> Ok, the work item works perfectly, but something is still amiss. No
> BSODs, but windows never finishes loading in the VM. It just stays at the
> splash screen with the progress bar moving after completing my routine and
> I hit ‘g’ on WinDbg. Would someone mind double checking my work? I have
> a feeling something did not get returned correctly and it may be stuck
> waiting for something that is already done. As the VM has been at the same
> point on the splash screen during the entire time I have written this
> message. Soo close…
>
> NTSTATUS
> MyReadWrite(
> IN PDEVICE_OBJECT DeviceObject,
> IN PIRP Irp
> )
> {
> PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
> KEVENT Event;
> NTSTATUS status;
>
> KeInitializeEvent(&Event, NotificationEvent, FALSE);
> if (deviceExtension->IOFirstTime){
> deviceExtension->IOFirstTime = 0;//Set to False
>
> // copy the irpstack for the next device
> IoCopyCurrentIrpStackLocationToNext(Irp);
>
> // set a completion routine
> IoSetCompletionRoutine(Irp, DARKIoCompletion, &Event, TRUE, TRUE,
> TRUE);
>
> // call the next lower device
> status = IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
>
> // wait for the actual completion
> if (status == STATUS_PENDING) {
> KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
> status = Irp->IoStatus.Status;
> }
> return status;
> }
> IoSkipCurrentIrpStackLocation(Irp);
>
> return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
> } // end MyReadWrite()
>
>
> NTSTATUS
> MyIoCompletion(
> IN PDEVICE_OBJECT DeviceObject,
> IN PIRP Irp,
> IN PVOID Context
> )
> {
> PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION)
> DeviceObject->DeviceExtension;
> PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
>
> if (Irp->PendingReturned) {
> IoMarkIrpPending(Irp);
> }
> deviceExtension->WorkItem = IoAllocateWorkItem( DeviceObject );
> deviceExtension->irp = Irp;
> IoQueueWorkItem( deviceExtension->WorkItem, MyWorkItemRoutine,
> DelayedWorkQueue,
> Context );
>
> return(STATUS_MORE_PROCESSING_REQUIRED);
> } // end MyIoCompletion
>
> VOID
> MyWorkItemRoutine(
> IN PDEVICE_OBJECT DeviceObject,
> IN PVOID Context
> )
> {
> PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION)
> DeviceObject->DeviceExtension;
> //…//
> PBYTE pMBRBuffer;
>
> pMBRBuffer = ExAllocatePoolWithTag(NonPagedPool, (ULONG)MBR_SIZE,
> ‘1gaT’);
>
> //…Do ZwCreateFile, ZwReadFile, logic checks, & ZwCloseFile…//
>
> // Close the raw disk which we are filtering
> status = ZwClose(deviceExtension->MBR);
> deviceExtension->irp->IoStatus.Status = status;
> ExFreePool(pMBRBuffer);
>
> // Free the WorkItem from the queue
> IoFreeWorkItem(deviceExtension->WorkItem);
>
> // Complete the Irp which got us here
> IoCompleteRequest(deviceExtension->irp, IO_NO_INCREMENT);
> } // end MyWorkItemRoutine
>

So your device object can only support one outstanding request at a time for
which you provide this service? I see you stick the IRP in the
DeviceExtension and you do not have any synchronization (protection) around
that field.

Good Luck,
Dave Cattley

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@gmail.com
Sent: Tuesday, March 30, 2010 2:58 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Driver function causing a BSOD – Buffer overflow –
why?

Ok, the work item works perfectly, but something is still amiss. No BSODs,
but windows never finishes loading in the VM. It just stays at the splash
screen with the progress bar moving after completing my routine and I hit
‘g’ on WinDbg. Would someone mind double checking my work? I have a
feeling something did not get returned correctly and it may be stuck waiting
for something that is already done. As the VM has been at the same point on
the splash screen during the entire time I have written this message. Soo
close…

NTSTATUS
MyReadWrite(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
KEVENT Event;
NTSTATUS status;

KeInitializeEvent(&Event, NotificationEvent, FALSE);
if (deviceExtension->IOFirstTime){
deviceExtension->IOFirstTime = 0;//Set to False

// copy the irpstack for the next device
IoCopyCurrentIrpStackLocationToNext(Irp);

// set a completion routine
IoSetCompletionRoutine(Irp, DARKIoCompletion, &Event, TRUE, TRUE,
TRUE);

// call the next lower device
status = IoCallDriver(deviceExtension->TargetDeviceObject, Irp);

// wait for the actual completion
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
status = Irp->IoStatus.Status;
}
return status;
}
IoSkipCurrentIrpStackLocation(Irp);

return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
} // end MyReadWrite()

NTSTATUS
MyIoCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION)
DeviceObject->DeviceExtension;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);

if (Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}
deviceExtension->WorkItem = IoAllocateWorkItem( DeviceObject );
deviceExtension->irp = Irp;
IoQueueWorkItem( deviceExtension->WorkItem, MyWorkItemRoutine,
DelayedWorkQueue,
Context );

return(STATUS_MORE_PROCESSING_REQUIRED);
} // end MyIoCompletion

VOID
MyWorkItemRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PVOID Context
)
{
PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION)
DeviceObject->DeviceExtension;
//…//
PBYTE pMBRBuffer;

pMBRBuffer = ExAllocatePoolWithTag(NonPagedPool, (ULONG)MBR_SIZE,
‘1gaT’);

//…Do ZwCreateFile, ZwReadFile, logic checks, & ZwCloseFile…//

// Close the raw disk which we are filtering
status = ZwClose(deviceExtension->MBR);
deviceExtension->irp->IoStatus.Status = status;
ExFreePool(pMBRBuffer);

// Free the WorkItem from the queue
IoFreeWorkItem(deviceExtension->WorkItem);

// Complete the Irp which got us here
IoCompleteRequest(deviceExtension->irp, IO_NO_INCREMENT);
} // end MyWorkItemRoutine


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

Alex -

Why are you calling the TargetDeviceObject twice?

I assume you are referring to the MyReadWrite() method. The first is for registering the callback and returns with the result of the callback if it goes that way. The other is actually the guts of a passthrough method - rather than list that and have to explain what it does since it is used elsewhere multiple times. The actual final return as written is ‘return MyPassThrough();’

Dave -

So your device object can only support one outstanding request at a time for
which you provide this service? I see you stick the IRP in the
DeviceExtension and you do not have any synchronization (protection) around
that field.

I’m not sure I fully understand your questions. I am only interested in performing this task once per each disk device as long as the device exists. For that reason, nothing will ever access that IRP in the DeviceExtension but the MyWorkItemRoutine once for that one time all of this runs per disk device. If I missed what you were getting at, please clarify for me.

Thanks.

Brian