Hi, everybody
Recently my usb virtual bus driver was hitting a blue screen, and I need you guys the driver experts to helping me. the virtual usb bus driver simulate a USB controller, and dynamically enumerate usb devices using the technique learned from DDK toaster sample, and the driver communicate to the real usb device over network with the help of a usb filter driver sit on other machine, for every URB it received, the driver mark it as pending and forward to request queue, send the URB to filter driver, wait the response, and finally complete the IRP when response is received. cause the URB processing envolve in network transfer, it is affected by network load and the two machine cpu utilization, the processing time is longer than normal usb bus driver.
the blue screen was caused by a URB, which is pending by my driver, and later cancelled by usbccgp driver, and usbccgp cause a free memory access error. I use IDA Pro decompile the driver, and the following is the function, the bug code is marked.
typedef struct CallDriverContext {
PKEVENT hEvent;
int *completed;
} CallDriverContext, *PCallDriverContext;
//----- (00016600) --------------------------------------------------------
NTSTATUS __stdcall CallDriverSync(int a1, PIRP Irp)
{
char *v3; // ecx@1
PCallDriverContext context; //v4; // eax@1
int v5; // eax@2
NTSTATUS v6; // eax@3
char *v7; // [sp+20h] [bp-14h]@1
int v8; // [sp+4h] [bp-30h]@1
int v9; // [sp+1Ch] [bp-18h]@1
struct _KEVENT Event; // [sp+8h] [bp-2Ch]@1
int v11; // [sp+28h] [bp-Ch]@1
PVOID P; // [sp+24h] [bp-10h]@1
char *v13; // [sp+0h] [bp-34h]@2
NTSTATUS Status; // v14; // [sp+18h] [bp-1Ch]@2
LARGE_INTEGER Timeout; // [sp+2Ch] [bp-8h]@3
v3 = (char *)IoGetCurrentIrpStackLocation(Irp) - 36;
v7 = (char *)Irp->Tail.Overlay.CurrentStackLocation - 36;
v8 = *v3;
v9 = *(v3 + 1);
KeInitializeEvent(&Event, 0, 0);
v11 = 0;
context = v4 = (PCallDriverContext)ExAllocatePoolWithTag(0, sizeof(CallDriverContext), 0x43627355u);
P = v4;
if ( v4 )
{
context->hEvent = &Event;
context->completed = &v11;
IoSetCompletionRoutine(
Irp,
CallDriverSyncCompletion,
(PVOID)context,
TRUE,
TRUE,
TRUE
);
Status = IofCallDriver(a1, Irp);
if ( Status == STATUS_PENDING )
{
Timeout = (LARGE_INTEGER)-5000,0000 i64; // 5000ms = 5s
Status = KeWaitForSingleObject(&Event, 0, 0, 0, &Timeout);
if ( Status == STATUS_TIMEOUT )
{
if ( !InterlockedExchange(&v11, 1) )
{
IoCancelIrp(Irp);
if ( InterlockedExchange(&v11, 2) == 3 )
{
*((_BYTE *)Irp->Tail.Overlay.CurrentStackLocation + 3) |= 1u;
IofCompleteRequest(Irp, 0); // I found this function free the Irp
}
}
KeWaitForSingleObject(&Event, 0, 0, 0, 0);
Irp->IoStatus.Status = 0xC000009C; // <=== BUG CHECK AT HERE! STATUS_DEVICE_DATA_ERROR, -1073741668;
}
}
ExFreePool(context);
Status = Irp->IoStatus.Status;
}
else
{
Status = -1073741670;
}
return Status;
}
signed int __stdcall CallDriverSyncCompletion(int a1, int a2, int a3)
{
PCallDriverContext context; //v4; // eax@1
context = (PCallDriverContext)a3;
InterlockedExchange(context->completed, 3);
KeSetEvent(*context->Event, 0, 0);
return 0xC0000016; // STATUS_MORE_PROCESSING_REQUIRED -1073741802;
}
in WinDbg, I found after return from IofCompleteRequest(), the Irp is freed, does CalllDriverSync suppose to access Irp after it was freed?
function CallDriverSync use the Irp processing style like http://support.microsoft.com/kb/326315/en-us/ Scenario 7: Send a synchronous device-control (IOCTL) request and cancel it if not completed in a certain time period, but the sample does not touch the Irp after complete it.
any helping are welcome