OpenHCI bug on Win2k?

W

WT

I developed a USB driver for smartcard reader and it was running fine on
WinXP. It works fine on Win2k too if my reader is connected through a
hispeed hub. However, if I connect the reader to the root hub directly, the
driver would fail to load. I snooped around with SoftICE into the driver
stack and discovered that it is in OpenHCI that my IRP, or URB, failed a
parameter validation. Turns out that it does not take a buffer with size
greater than 64 bytes (possibly because the max packet size of of my bulk
input pipe is 64 bytess) and rejected my URB with STATUS_INVALID_PARAMETER
(0xc000000D).
When a reader is connected through a hub, openhci is not involved. My driver
passes the URB to usbport.sys instead.
Anybody out there experienced the same problem? I can provide more details
if anybody is interested.
Winston
 
W

WT

The code to init IRP and URB are given below. I am wondering if OpenHCI will
handle data buffers bigger than the max packet size on the pipes. It appears
that it also does not like the buffer (512 bytes) I pass to the interrupt
pipe (with max packet size of 8 bytes). The usbport.sys, which my driver
calls on XP, handles bigger buffers just fine.
Now MS document on UsbBuildInterruptOrBulkTransferRequest does not put size
limit on the data buffer used. However, I am also highly suspicious that
this bug happens under special circustance--a bug like this would have been
spotted long time ago.

// routine to init and send URB
// Note: the call to read the response failed with
STATUS_INVALID_PARAMETER--the input buffer size (
// pReply->BufferSize is 0x120 (while my max packet size for the input pipe
is 64 bytes).

NTSTATUS
PcscSendSmartcardCommand(
PSMARTCARD_EXTENSION SmartcardExtension)
{
NTSTATUS status = STATUS_SUCCESS;

PSMARTCARD_REPLY pReply = &SmartcardExtension->SmartcardReply;
PSMARTCARD_REQUEST pRequest = &SmartcardExtension->SmartcardRequest;

PDEVICE_OBJECT fdo =
(PDEVICE_OBJECT)SmartcardExtension->OsData->DeviceObject;
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;

#ifdef DEBUG
SmartcardDebug(DEBUG_INFO, ("%s!PcscSendSmartcardCommand: cmd = ",
DRIVERNAME));
for (ULONG j = 0; j < pRequest->BufferLength; j++) {
SmartcardDebug(DEBUG_INFO, ("/x%02X", pRequest->Buffer[j]));
}
SmartcardDebug(DEBUG_INFO, ("\n"));
#endif

URB urb;

// init URB to send command via bulk out pipe
UsbBuildInterruptOrBulkTransferRequest(
&urb, // URB to build
sizeof(_URB_BULK_OR_INTERRUPT_TRANSFER), //
pdx->houtpipe, // pipe handle
pRequest->Buffer, // transfer buffer
NULL, // MDL
pRequest->BufferLength, // transfer buffer length
USBD_TRANSFER_DIRECTION_OUT, // transfer flags
NULL); //


// Send URB
status = SendAwaitUrb(fdo, &urb);

if (status == STATUS_SUCCESS) {
// Read response from bulk in pipe
// init URB to read response from bulk in pipe
UsbBuildInterruptOrBulkTransferRequest(
&urb, // URB to build
sizeof(_URB_BULK_OR_INTERRUPT_TRANSFER), //
pdx->hinpipe, // pipe handle
pReply->Buffer, // transfer buffer
NULL, // MDL
pReply->BufferSize, // transfer buffer length
USBD_TRANSFER_DIRECTION_IN
| USBD_SHORT_TRANSFER_OK, // transfer flags
NULL);
//
// Send URB
status = SendAwaitUrb(fdo, &urb);
if (status == STATUS_SUCCESS) {
pReply->BufferLength =
urb.UrbBulkOrInterruptTransfer.TransferBufferLength;
#ifdef DEBUG
SmartcardDebug(DEBUG_INFO, ("%s!PcscSendSmartcardCommand: resp = ",
DRIVERNAME));
for (ULONG j = 0; j < pReply->BufferLength; j++) {
SmartcardDebug(DEBUG_INFO, ("/x%02X", pReply->Buffer[j]));
}
SmartcardDebug(DEBUG_INFO, ("\n"));
#endif
}
else {
SmartcardDebug(DEBUG_ERROR,
("%s!PcscSendSmartcardCommand: error reading resp (%lX)\n",
DRIVERNAME, status));
}
}
else {
SmartcardDebug(DEBUG_ERROR,
("%s!PcscSendSmartcardCommand: error writing cmd (%lX)\n",
DRIVERNAME, status));
}

return (status);
}

// routine to init and send IRP
NTSTATUS SendAwaitUrb(PDEVICE_OBJECT fdo, PURB urb)
{ // SendAwaitUrb
PAGED_CODE();
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;

KEVENT event;
KeInitializeEvent(&event, NotificationEvent, FALSE);

IO_STATUS_BLOCK iostatus;
PIRP Irp = IoBuildDeviceIoControlRequest(
IOCTL_INTERNAL_USB_SUBMIT_URB,
pdx->LowerDeviceObject, NULL, 0,
NULL, 0, TRUE, &event, &iostatus);

if (!Irp) {
KdPrint((DRIVERNAME " - Unable to allocate IRP for sending URB\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}

// Set up our completion routine
IoSetCompletionRoutine(Irp, SendUrbComplete, (PVOID)&event, TRUE, TRUE,
TRUE);

PIO_STACK_LOCATION stack = IoGetNextIrpStackLocation(Irp);
stack->Parameters.Others.Argument1 = (PVOID) urb;

// We will wait for 1 min before the reader returns
LARGE_INTEGER timeOut;
// 1 min = 60 sec, in units of 100 nano sec
timeOut.QuadPart = -60 * 1000 * 1000 * 10;

// Send URB to USBD
NTSTATUS status = IoCallDriver(pdx->LowerDeviceObject, Irp);

if (status == STATUS_PENDING) {
status = KeWaitForSingleObject(
&event, Executive, KernelMode, FALSE, &timeOut);
if (status == STATUS_TIMEOUT) {
SmartcardDebug(DEBUG_INFO,
("%s!SendAwaitUrb: cmd time out, cancelling IRP\n", DRIVERNAME));
// We timed out, need to cancel the IRP
IoCancelIrp(Irp);
// Now wait for our completion routine to signal us
KeWaitForSingleObject(
&event, Executive, KernelMode, FALSE, NULL);
}
else {
// Since our completion routine returned STATUS_MORE_PROCESSING_NEEDED
that
// prevents USBD to finish the IRP, we need to do it here
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
}
else {
iostatus.Status = status;
}

status = iostatus.Status;

if (status != STATUS_SUCCESS)
SmartcardDebug(DEBUG_INFO,
("%s!SendAwaitUrb: err 0x%x\n", DRIVERNAME, status));

return status;
} // SendAwaitUrb

I traced the driver stack and found that the parameter validation happens in
openhci.sys. Here a dump from SoftICE:
:u openhci_queuetransfer l200

_OpenHCI_QueueTransfer

0008:EB6C3B3C PUSH EBP

0008:EB6C3B3D MOV EBP,ESP

0008:EB6C3B3F PUSH ECX

0008:EB6C3B40 PUSH ECX

0008:EB6C3B41 MOV EAX,[EBP+08]

0008:EB6C3B44 PUSH EBX

0008:EB6C3B45 PUSH ESI

0008:EB6C3B46 PUSH EDI

0008:EB6C3B47 MOV EDI,[EBP+0C] ; edi = IRP

0008:EB6C3B4A MOV EAX,[EAX+28]

0008:EB6C3B4D MOV DWORD PTR [EBP-04],00000103

0008:EB6C3B54 MOV [EBP-08],EAX

0008:EB6C3B57 MOV ECX,[EDI+60] ; ecx = IO_stack

0008:EB6C3B5A MOV ESI,[ECX+04] ; esi = URB

0008:EB6C3B5D MOV EBX,[ESI+28] ; HCA area, opapue to driver

0008:EB6C3B60 MOV [ESI+2C],EDI

0008:EB6C3B63 PUSH DWORD PTR [EAX+00000174]

0008:EB6C3B69 CALL [__imp__READ_REGISTER_ULONG]

0008:EB6C3B6F CMP EAX,-01

0008:EB6C3B72 JNZ EB6C3B85

0008:EB6C3B74 MOV DWORD PTR [EBP-04],C00000C0 ; STATUS_DEVICE_DOES_NOT_EXIST

0008:EB6C3B7B PUSH 80000500

0008:EB6C3B80 JMP EB6C3C09

0008:EB6C3B85 TEST BYTE PTR [EBX+10],02

0008:EB6C3B89 JZ EB6C3BA9

0008:EB6C3B8B TEST ESI,ESI

0008:EB6C3B8D JZ EB6C3CC5

0008:EB6C3B93 PUSH EBX

0008:EB6C3B94 PUSH ESI

0008:EB6C3B95 PUSH EDI

0008:EB6C3B96 PUSH DWORD PTR [EBP-08]

0008:EB6C3B99 PUSH DWORD PTR [EBP+08]

0008:EB6C3B9C CALL _OpenHCI_RootHubStartXfer

0008:EB6C3BA1 MOV ESI,[ESI+24]

0008:EB6C3BA4 MOV [EBP-04],EAX

0008:EB6C3BA7 JMP EB6C3B8B

0008:EB6C3BA9 CMP BYTE PTR [EBX+30],01

0008:EB6C3BAD JNZ EB6C3BF5

0008:EB6C3BAF TEST BYTE PTR [ESI+14],04

0008:EB6C3BB3 JNZ EB6C3BF5

0008:EB6C3BB5 PUSH DWORD PTR [EBP-08]

0008:EB6C3BB8 CALL _Get32BitFrameNumber

0008:EB6C3BBD MOV ECX,[ESI+48]

0008:EB6C3BC0 PUSH DWORD PTR [EBP-08]

0008:EB6C3BC3 SUB ECX,EAX

0008:EB6C3BC5 TEST ECX,ECX

0008:EB6C3BC7 JLE EB6C3BD5

0008:EB6C3BC9 CALL _Get32BitFrameNumber

0008:EB6C3BCE MOV ECX,[ESI+48]

0008:EB6C3BD1 SUB ECX,EAX

0008:EB6C3BD3 JMP EB6C3BDF

0008:EB6C3BD5 CALL _Get32BitFrameNumber

0008:EB6C3BDA MOV ECX,EAX

0008:EB6C3BDC SUB ECX,[ESI+48]

0008:EB6C3BDF CMP ECX,00000400

0008:EB6C3BE5 JLE EB6C3BF5

0008:EB6C3BE7 MOV DWORD PTR [EBP-04],C000000D ; STATUS_INVALID_PARAMETER

0008:EB6C3BEE PUSH C0000A00

0008:EB6C3BF3 JMP EB6C3C09

0008:EB6C3BF5 MOV EAX,[ESI+18] ;; NOTE: eax = input buffer size = 0x120

0008:EB6C3BF8 CMP EAX,[EBX+4C] ;; [ebx + 4c] = 0x40, ie 64 bytes, possibly
the max packet size for the pipe?

0008:EB6C3BFB JBE EB6C3C14 (NO JUMP)

0008:EB6C3BFD MOV DWORD PTR [EBP-04],C000000D ; STATUS_INVALID_PARAMETER <=
error code returned to IdtSp3Usb

0008:EB6C3C04 PUSH 80000300

0008:EB6C3C09 PUSH ESI

0008:EB6C3C0A CALL _OpenHCI_SetTranferError

0008:EB6C3C0F JMP EB6C3CC5

0008:EB6C3C14 LEA EAX,[EBP+0C]

0008:EB6C3C17 PUSH EAX

0008:EB6C3C18 CALL [__imp__IoAcquireCancelSpinLock]

0008:EB6C3C1E LEA ECX,[EBX+40]

0008:EB6C3C21 CALL [__imp_@KfAcquireSpinLock]

0008:EB6C3C27 CMP BYTE PTR [EDI+24],00

0008:EB6C3C2B MOV [EBP+08],AL

0008:EB6C3C2E JZ EB6C3C39

0008:EB6C3C30 MOV DWORD PTR [EBP-04],C0000120 ; STATUS_CANCELLED

0008:EB6C3C37 JMP EB6C3C46

0008:EB6C3C39 TEST BYTE PTR [EBX+10],01

0008:EB6C3C3D JZ EB6C3C5E

0008:EB6C3C3F MOV DWORD PTR [EBP-04],C000020F ; STATUS_TRANSACTION_ABORTED

0008:EB6C3C46 XOR EDX,EDX

0008:EB6C3C48 LEA ECX,[EDI+38]

0008:EB6C3C4B CALL [__imp_@InterlockedExchange]

0008:EB6C3C51 PUSH 00010000

0008:EB6C3C56 PUSH ESI

0008:EB6C3C57 CALL _OpenHCI_SetTranferError

0008:EB6C3C5C JMP EB6C3CA7

0008:EB6C3C5E TEST ESI,ESI

0008:EB6C3C60 JZ EB6C3C8B

0008:EB6C3C62 LEA ECX,[EBX+18]

0008:EB6C3C65 LEA EAX,[ESI+38]

0008:EB6C3C68 MOV [ESI+3C],EAX

0008:EB6C3C6B MOV [EAX],EAX

0008:EB6C3C6D MOV DWORD PTR [ESI+04],40404003

0008:EB6C3C74 MOV EDX,[ECX+04]

0008:EB6C3C77 LEA EAX,[ESI+30]

0008:EB6C3C7A MOV [ESI+34],EDX

0008:EB6C3C7D MOV [EAX],ECX

0008:EB6C3C7F MOV [EDX],EAX

0008:EB6C3C81 MOV [ECX+04],EAX

0008:EB6C3C84 MOV ESI,[ESI+24]

0008:EB6C3C87 TEST ESI,ESI

0008:EB6C3C89 JNZ EB6C3C65

0008:EB6C3C8B MOV EAX,[EDI+60]

0008:EB6C3C8E MOV DWORD PTR [EDI+18],00000103

0008:EB6C3C95 MOV EDX,_OpenHCI_CancelTransfer

0008:EB6C3C9A LEA ECX,[EDI+38]

0008:EB6C3C9D OR BYTE PTR [EAX+03],01

0008:EB6C3CA1 CALL [__imp_@InterlockedExchange]

0008:EB6C3CA7 MOV DL,[EBP+08]

0008:EB6C3CAA LEA ECX,[EBX+40]

0008:EB6C3CAD CALL [__imp_@KfReleaseSpinLock]

0008:EB6C3CB3 PUSH DWORD PTR [EBP+0C]

0008:EB6C3CB6 CALL [__imp__IoReleaseCancelSpinLock]

0008:EB6C3CBC PUSH EBX

0008:EB6C3CBD PUSH DWORD PTR [EBP-08]

0008:EB6C3CC0 CALL _OpenHCI_ProcessEndpoint

0008:EB6C3CC5 MOV EAX,[EBP-04]

0008:EB6C3CC8 POP EDI

0008:EB6C3CC9 POP ESI

0008:EB6C3CCA POP EBX

0008:EB6C3CCB LEAVE

0008:EB6C3CCC RET 0008

0008:EB6C3CCF INT 3
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top