Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results

Home NTDEV

Before Posting...

Please check out the Community Guidelines in the Announcements and Administration Category.

More Info on Driver Writing and Debugging


The free OSR Learning Library has more than 50 articles on a wide variety of topics about writing and debugging device drivers and Minifilters. From introductory level to advanced. All the articles have been recently reviewed and updated, and are written using the clear and definitive style you've come to expect from OSR over the years.


Check out The OSR Learning Library at: https://www.osr.com/osr-learning-library/


Getting USB descriptors from a class filter

Rui_AbreuRui_Abreu Member - All Emails Posts: 4
Hi all,

I have few questions related to an USB class filtering.

- I shouldn't send URBs from a class filter to a PDO, but why? I mean, if a have the PDO of a USB device, why is not safe to ask for the device descriptor, for example, after the device is started?

- Is a reasonable approach to wait for URBs sent by the system to complete succesfully and then read the information from them? I guess... with lower filter?

- Is there any way to get the descriptors from an (upper or lower) USB class filter?

Thanks in advance,

Rui

Comments

  • Peter_Viscarola_(OSR)Peter_Viscarola_(OSR) Administrator Posts: 9,162
    <quote>
    why is not safe to ask for the device descriptor, for
    example, after the device is started?
    </quote>

    Who says it's NOT safe? It sounds perfectly reasonable to me.

    <quote>
    Is a reasonable approach to wait for URBs sent by the system to complete
    succesfully and then read the information from them
    </quote>

    Well... "it depends" -- I don't TYPICALLY like *any* synchronous "wait for it to complete" approach, when it's used generically in the path to a controller. Rather, I'd like to see you send the request asynchronously and get the results in a Completion Callback. All using WDF, of course.

    Peter
    OSR
    @OSRDrivers

    Peter Viscarola
    OSR
    @OSRDrivers

  • Tim_RobertsTim_Roberts Member - All Emails Posts: 14,852
    [email protected] wrote:
    >
    > I have few questions related to an USB class filtering.

    I would caution that the term "USB class filtering" can have several
    different meanings.  What "class" are you filtering?


    > - I shouldn't send URBs from a class filter to a PDO, but why? I mean,
    > if a have the PDO of a USB device, why is not safe to ask for the
    > device descriptor, for example, after the device is started? 

    It is safe, although typically it's not necessary, because you can
    intercept the device descriptor request from the driver you're filtering
    and snaggle its output.  You will typically need to monitor many of the
    standard requests, so you can learn which interfaces are selected, for
    example.


    > - Is a reasonable approach to wait for URBs sent by the system to
    > complete succesfully and then read the information from them? I
    > guess... with lower filter?

    Absolutely.  I do it all the time.


    > - Is there any way to get the descriptors from an (upper or lower) USB
    > class filter?

    Monitoring as a lower filter is easy.  From an upper filter, you'd need
    to send your own request.  Note that, as an upper filter, you won't know
    which interfaces are selected, or which alternate settings are chosen. 
    A USB upper filter typically doesn't deal in URBs very much; you deal in
    whatever interface is spoken out the top end of the driver you're filtering.

    --
    Tim Roberts, [email protected]
    Providenza & Boekelheide, Inc.

    Tim Roberts, [email protected]
    Software Wizard Emeritus

  • Rui_AbreuRui_Abreu Member - All Emails Posts: 4
    Peter, Tim, thank you. Your help is really appreciated.

    After reading your answers I realized there are things (even more) I dont understand properly enough to write the filter. I have been reading a bit more... and I have new basic doubts.


    - According to MSDN the USB class includes USB host controllers and USB hubs, but not USB peripherals. What does "but not USB peripherals" really mean? I can see USB enumerated devices (\USB\VID_*)... and monitor the IRPs before and after arriving the FDO. Is it something like not all USB devices are going to be informed in my AddDevice function?


    - The fact that Peter suggests using WDF...implies that I was wrong about something very basic. As I expected to monitor URBs I wrongly thought the filter is considered a bus filter. Ok, so after reading the forum, I guess the next move is to rewrite it using KMDF, isn't it? Every class filter can be written with KMDF regardless the class?


    - Regardless the framework used, and although this WDM filter is going to the end up in the Recycle Bin... is my code BSODing in (Windows Server 2012, IRQL is PASSIVE_LEVEL) because the approach? It *seemed* to work OK in XP, what I do is:

    1. Install a completion routine on IRP_MN_START_DEVICE
    2. If the start is successful, I try to get the class of the device to save it in my device descriptor by:
    2.1 Declare URB & USB_DEVICE_DESCRIPTOR structs in the stack
    2.2 Init the URB with UsbBuildGetDescriptorRequest
    2.3 Create an IRP with IoBuildDeviceIoControlRequest with an event to wait in case is pended
    2.4 Setup the stack location with the address of the URB
    2.5 Call IoCallDriver with the PDO
    2.6 If needed, wait until the IRP is completed
    2.7 Parse the device descriptor in case of success

    Should this approach work? If I move it to WDF, isn't it this, more or less, what would happen under the hood?

    Thank you again.

    Rui
  • Tim_RobertsTim_Roberts Member - All Emails Posts: 14,852
    On May 26, 2018, at 11:34 AM, [email protected] <[email protected]> wrote:
    >
    > - According to MSDN the USB class includes USB host controllers and USB hubs, but not USB peripherals. What does "but not USB peripherals" really mean? I can see USB enumerated devices (\USB\VID_*)... and monitor the IRPs before and after arriving the FDO. Is it something like not all USB devices are going to be informed in my AddDevice function?

    The situation is not straightforward, in part because the term "class" is heavily overloaded.

    We have the device install class, which is the Class and ClassGUID specified in the INF file. In this case, the USB class has a GUID that starts 36fc9e60. This class is intended for USB host controllers and hubs. However, because there was no other convenient place, many people making USB devices put them in Class=USB, just because the name was so tempting. Microsoft added the USBDevice class (which starts 88bae032) in Windows 10 to solve that problem, but there are a lot of old driver packages out there.

    Microsoft also uses the term "class" to refer to device interfaces, which are PnP concepts that are managed at run-time, not specified in the INF file. There is a device interface class for USB devices as well, and I believe the hubs create that interface for any subdivide that they create.

    A "class filter driver" is ordinarily filtering based on the device install class. That means anything that appears in Device Manager under "Universal Serial Bus Controllers", which might include devices that are not actually USB controllers.


    > - The fact that Peter suggests using WDF...implies that I was wrong about something very basic. As I expected to monitor URBs I wrongly thought the filter is considered a bus filter. Ok, so after reading the forum, I guess the next move is to rewrite it using KMDF, isn't it? Every class filter can be written with KMDF regardless the class?

    No, URBs are sent by individual devices. A straight device filter or class filter can grab those. Being a bus filter is more about watching complicated PnP interactions. If all you need are URBs, that's a straight filter.

    Filter drivers are trivially easy in KMDF. There is NO reason to write a filter driver in straight WDM any more.


    > - Regardless the framework used, and although this WDM filter is going to the end up in the Recycle Bin... is my code BSODing in (Windows Server 2012, IRQL is PASSIVE_LEVEL) because the approach? It *seemed* to work OK in XP, what I do is:
    >
    > 1. Install a completion routine on IRP_MN_START_DEVICE
    > 2. If the start is successful, I try to get the class of the device to save it in my device descriptor by:
    > 2.1 Declare URB & USB_DEVICE_DESCRIPTOR structs in the stack
    > 2.2 Init the URB with UsbBuildGetDescriptorRequest
    > 2.3 Create an IRP with IoBuildDeviceIoControlRequest with an event to wait in case is pended
    > 2.4 Setup the stack location with the address of the URB
    > 2.5 Call IoCallDriver with the PDO
    > 2.6 If needed, wait until the IRP is completed
    > 2.7 Parse the device descriptor in case of success
    >
    > Should this approach work? If I move it to WDF, isn't it this, more or less, what would happen under the hood?

    As long as you are doing this in the completion routine, this should be OK. Where do you get the blue screen?

    Tim Roberts, [email protected]
    Providenza & Boekelheide, Inc.

    Tim Roberts, [email protected]
    Software Wizard Emeritus

  • Rui_AbreuRui_Abreu Member - All Emails Posts: 4
    Thanks a lot for the feedback.

    This is a stack trace in Windows XP, which seems reasonable, during a succesful processing of the IRP:

    kd> kb
    ChildEBP RetAddr Args to Child
    bad07680 ba49ff14 45447367 8ac8ef20 bad077f0 USBPORT!USBPORT_SCT_GetSetDescriptor+0x46 <- Get Descriptor makes sense...
    bad076ac ba4a5088 89b3c618 89b8d028 000000b0 USBPORT!USBPORT_ProcessURB+0x3f4
    bad076cc ba48e3d2 89b3c618 8ac8ef20 89b3c618 USBPORT!USBPORT_PdoInternalDeviceControlIrp+0x7e
    bad076f0 804ee119 8ac8efd8 89b3c770 806d22e8 USBPORT!USBPORT_Dispatch+0x148
    bad07700 8064d628 8ac8ef20 bad077f0 89c83e38 nt!IopfCallDriver+0x31
    bad07724 baa5859c bad0774c baa5c82d 8ac8ef20 nt!IovCallDriver+0xa0
    bad0772c baa5c82d 8ac8ef20 89b3c618 8ac8ef20 usbhub!USBH_PassIrp+0x18
    bad0774c baa5d0ae 89cdd1d8 8ac8ef20 89c83d80 usbhub!USBH_PdoUrbFilter+0xbd
    bad07768 baa5a5e4 bad077f0 8ac8ef20 bad077ac usbhub!USBH_PdoDispatch+0x202
    bad07778 804ee119 89c83d80 8ac8ef20 806d22e8 usbhub!USBH_HubDispatch+0x48
    bad07788 8064d628 8b022ed8 bad07908 8b022fb4 nt!IopfCallDriver+0x31
    bad077ac ba58308d bad07dcc 00040000 00000000 nt!IovCallDriver+0xa0
    bad077dc ba583160 89c83d80 bad077f0 89c83d80 MyDriver!UsbSendUrb+0x6d <- Send the URB
    bad07850 ba57c262 89c83d80 bad07860 01100112 MyDriver!UsbReadDeviceDescriptor+0x50
    bad07880 8064d830 89c82678 8b022ed8 00000000 MyDriver!StartDeviceCompleted+0x202 <- Completion routine, sending URB... <<<<<<
    bad078a4 804f069e 89c82678 8b022ed8 bad07908 nt!IovpLocalCompletionRoutine+0xb4
    bad078d4 8064dcb8 8996ae90 89c84030 8b022e00 nt!IopfCompleteRequest+0xa2
    bad07940 babce03f ffffffff ffffffff 00000000 nt!IovCompleteRequest+0x9a
    bad07988 babc85e5 89c840e8 8b022ed8 0000001b usbccgp!USBC_PnP+0x29f
    bad079c4 804ee119 89c84030 8b022ed8 806d22e8 usbccgp!USBC_Dispatch+0x195
    bad079d4 8064d628 89c82678 89d884d0 8b022e00 nt!IopfCallDriver+0x31
    bad079f8 ba57c459 89c82730 00000000 8b022fd8 nt!IovCallDriver+0xa0
    bad07a0c 804ee119 89c82678 8b022ed8 806d22e8 MyDriver!DispatchPnP+0x139 <- IRP_MN_START_DEVICE recieved, set the completion routine <<<<<
    bad07a1c 8064d628 8b022ffc bad07aac 8b022ed8 nt!IopfCallDriver+0x31
    bad07a40 80587fc9 bad07aac 89c83d80 00000000 nt!IovCallDriver+0xa0
    bad07a6c 80588047 89c82678 bad07a88 00000000 nt!IopSynchronousCall+0xb7
    bad07ab0 804f514c 89c83d80 89c164e0 00000001 nt!IopStartDevice+0x4d
    bad07acc 805876f7 89c83d80 89c16401 00000000 nt!PipProcessStartPhase1+0x4e
    bad07d24 80587bca 89d8fee8 00000001 00000000 nt!PipProcessDevNodeTree+0x1db
    bad07d4c 804f58d6 00000003 80552040 8055b0fc nt!PiProcessStartSystemDevices+0x3a
    bad07d74 80534c02 00000000 00000000 89da1da8 nt!PipDeviceActionWorker+0x166
    bad07dac 805c6160 00000000 00000000 00000000 nt!ExpWorkerThread+0x100
    bad07ddc 80541dd2 80534b02 00000001 00000000 nt!PspSystemThreadStartup+0x34
    00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16

    ##################################################################################

    Now the crash in Windows Server 2012:

    To test the filter, I attach to every device in AddDevice() and then I try to do the same. The first devices that appear are root hubs: USB\ROOT_HUB, USB\ROOT_HUB20 and USB\ROOT_HUB30 which I suspect correspond to UHCI, EHCI and xHCI. For the first two root hubs, the IoCallDriver() call fails with STATUS_NO_SUCH_DEVICE which maybe make sense for root hubs, I don't know yet, but USBview is showing device descriptors only for generic hubs connected to root hubs, but not for root hubs. Anyways the third one does not return an error, it just crashes with bugcheck KERNEL_MODE_EXCEPTION_NOT_HANDLED.

    kd> !analyze -v
    *******************************************************************************
    * *
    * Bugcheck Analysis *
    * *
    *******************************************************************************

    SYSTEM_THREAD_EXCEPTION_NOT_HANDLED (7e)
    This is a very common bugcheck. Usually the exception address pinpoints
    the driver/function that caused the problem. Always note this address
    as well as the link date of the driver/image that contains this address.
    Arguments:
    Arg1: ffffffffc0000005, The exception code that was not handled
    Arg2: fffff8000040f066, The address that the exception occurred at
    Arg3: ffffd0002078c488, Exception Record Address
    Arg4: ffffd0002078bc90, Context Record Address

    Debugging Details:
    ------------------


    EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%p referenced memory at 0x%p. The memory could not be %s.

    FAULTING_IP:
    Wdf01000!imp_WdfObjectGetTypedContextWorker+26
    fffff800`0040f066 4c8b5010 mov r10,qword ptr [rax+10h]

    EXCEPTION_RECORD: ffffd0002078c488 -- (.exr 0xffffd0002078c488)
    ExceptionAddress: fffff8000040f066 (Wdf01000!imp_WdfObjectGetTypedContextWorker+0x0000000000000026)
    ExceptionCode: c0000005 (Access violation)
    ExceptionFlags: 00000000
    NumberParameters: 2
    Parameter[0]: 0000000000000000
    Parameter[1]: 0000307ffee7b438
    Attempt to read from address 0000307ffee7b438

    CONTEXT: ffffd0002078bc90 -- (.cxr 0xffffd0002078bc90)
    rax=0000307ffee7b428 rbx=0000000000000000 rcx=0000000000000000
    rdx=ffffcf8001184bd0 rsi=0000000000000000 rdi=ffffd0002078ca40
    rip=fffff8000040f066 rsp=ffffd0002078c6c0 rbp=000000000000000b
    r8=fffff80001bb00b0 r9=fffff801ea1156b0 r10=ffffe0000518fc70
    r11=0000000000000000 r12=0000000000000021 r13=0000000000000000
    r14=00001ffffae70858 r15=ffffcf800111ed30
    iopl=0 nv up ei pl zr na po nc
    cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00010246
    Wdf01000!imp_WdfObjectGetTypedContextWorker+0x26:
    fffff800`0040f066 4c8b5010 mov r10,qword ptr [rax+10h] ds:002b:0000307f`fee7b438=????????????????
    Resetting default scope

    DEFAULT_BUCKET_ID: VISTA_DRIVER_FAULT

    PROCESS_NAME: System

    CURRENT_IRQL: 0

    ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%p referenced memory at 0x%p. The memory could not be %s.

    EXCEPTION_PARAMETER1: 0000000000000000

    EXCEPTION_PARAMETER2: 0000307ffee7b438

    READ_ADDRESS: 0000307ffee7b438

    FOLLOWUP_IP:
    ucx01000!Urb_USBPORTStyle_ProcessURB+98
    fffff800`01ba3a84 4533db xor r11d,r11d

    BUGCHECK_STR: 0x7E

    LAST_CONTROL_TRANSFER: from fffff80001ba3a84 to fffff8000040f066

    STACK_TEXT:
    ffffd000`2078c6c0 fffff800`01ba3a84 : 00000000`00000000 fffff801`ea473de9 ffffe000`00e6b330 fffff801`ea472368 : Wdf01000!imp_WdfObjectGetTypedContextWorker+0x26
    ffffd000`2078c710 fffff800`01b99e20 : 00001fff`fae70858 ffffcf80`0111ed30 ffffd000`2078c7d0 ffffcf80`0111ef68 : ucx01000!Urb_USBPORTStyle_ProcessURB+0x98
    ffffd000`2078c770 fffff800`00414d43 : ffffcf80`0111ed30 ffffe000`00341818 00000000`0000000f ffffe000`0518f7a0 : ucx01000!RootHub_Pdo_EvtInternalDeviceControlIrpPreprocessCallback+0x448 <<<< Maybe this calls to the preprocess callbacks I have been reading about (WDF). I guess makes sense because URB is sent via IRP_MJ_INTERNAL_DEVICE_CONTROL
    ffffd000`2078c800 fffff801`ea465911 : ffffe000`00e6bed0 00000000`00000002 fffff801`e9f1c04c ffffe000`05190710 : Wdf01000!FxDevice::DispatchWithLock+0xb01
    ffffd000`2078c8e0 fffff800`0031a989 : ffffcf80`0111ed30 fffff800`01071def fffff801`e9f1c04c ffffe000`00e6be30 : nt!IovCallDriver+0x3cd
    ffffd000`2078c930 fffff800`01071def : fffff801`ea0ae880 ffffe000`05433040 ffffe000`0544ae50 00000000`00000000 : VerifierExt!IofCallDriver_internal_wrapper+0x71
    ffffd000`2078c970 fffff800`01071f18 : ffffe000`05190710 ffffd000`2078ca40 00000000`00000000 fffff801`ea0ae890 : MyDriver!UsbSendUrb+0xaf
    ffffd000`2078ca20 fffff800`0106949d : ffffe000`05190710 ffffd000`2078cb48 ffffe000`0544ae50 ffffe000`00e81010 : MyDriver!UsbReadDeviceDescriptor+0x78
    ffffd000`2078cb00 fffff801`ea4726a6 : ffffe000`05433d20 ffffcf80`01184bd0 00000000`00000000 fffff801`e9e02000 : MyDriver!StartDeviceCompleted+0x25d <- Completion routine, sending URB... <<<<<<<<<<
    ffffd000`2078cb70 fffff801`ea4729e4 : fffff801`ea0ae890 fffff801`ea0ae880 00000000`00000080 ffffe000`001e4040 : nt!ViPendingCompleteAfterWait+0xda
    ffffd000`2078cbc0 fffff801`e9ee9664 : 0072a845`c7202444 740069ac`45c70074 006f0069`b045c700 c7000000`6eb445c7 : nt!ViPendingWorkerThread+0x2c
    ffffd000`2078cc00 fffff801`e9f586c6 : fffff801`ea0f3180 ffffe000`001e4040 ffffe000`001e3880 000001b9`41402454 : nt!PspSystemThreadStartup+0x58
    ffffd000`2078cc60 00000000`00000000 : ffffd000`2078d000 ffffd000`20787000 00000000`00000000 00000000`00000000 : nt!KxStartSystemThread+0x16


    SYMBOL_STACK_INDEX: 1

    SYMBOL_NAME: ucx01000!Urb_USBPORTStyle_ProcessURB+98

    FOLLOWUP_NAME: MachineOwner

    MODULE_NAME: ucx01000

    IMAGE_NAME: ucx01000.sys

    DEBUG_FLR_IMAGE_TIMESTAMP: 5215f7fc

    STACK_COMMAND: .cxr 0xffffd0002078bc90 ; kb

    FAILURE_BUCKET_ID: X64_0x7E_VRF_ucx01000!Urb_USBPORTStyle_ProcessURB+98

    BUCKET_ID: X64_0x7E_VRF_ucx01000!Urb_USBPORTStyle_ProcessURB+98

    Followup: MachineOwner
    ---------

    Any idea of what could be happening?

    Kind regards,

    Rui
  • Tim_RobertsTim_Roberts Member - All Emails Posts: 14,852
    On May 27, 2018, at 2:39 PM, [email protected] <[email protected]> wrote:
    >
    > Thanks a lot for the feedback.
    > ,,,
    > FAULTING_IP:
    > Wdf01000!imp_WdfObjectGetTypedContextWorker+26
    > fffff800`0040f066 4c8b5010 mov r10,qword ptr [rax+10h]
    > ,,,
    > rax=0000307ffee7b428 rbx=0000000000000000 rcx=0000000000000000
    > rdx=ffffcf8001184bd0 rsi=0000000000000000 rdi=ffffd0002078ca40
    > rip=fffff8000040f066 rsp=ffffd0002078c6c0 rbp=000000000000000b
    > r8=fffff80001bb00b0 r9=fffff801ea1156b0 r10=ffffe0000518fc70
    > r11=0000000000000000 r12=0000000000000021 r13=0000000000000000
    > r14=00001ffffae70858 r15=ffffcf800111ed30
    > iopl=0 nv up ei pl zr na po nc
    > cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00010246
    > Wdf01000!imp_WdfObjectGetTypedContextWorker+0x26:
    > fffff800`0040f066 4c8b5010 mov r10,qword ptr [rax+10h] ds:002b:0000307f`fee7b438=????????????????

    In this case, it's using a KMDF handle as if it were an address. Is it possible you accidentally inserted a KMDF handle into one of the IRP fields? That seems really unlikely.


    > ffffd000`2078c770 fffff800`00414d43 : ffffcf80`0111ed30 ffffe000`00341818 00000000`0000000f ffffe000`0518f7a0 : ucx01000!RootHub_Pdo_EvtInternalDeviceControlIrpPreprocessCallback+0x448 <<<< Maybe this calls to the preprocess callbacks I have been reading about (WDF). I guess makes sense because URB is sent via IRP_MJ_INTERNAL_DEVICE_CONTROL

    It does that in case the call came from user mode. It needs to be able to grab pointers from user-mode memory, and that requires preprocessing.

    Tim Roberts, [email protected]
    Providenza & Boekelheide, Inc.

    Tim Roberts, [email protected]
    Software Wizard Emeritus

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. Sign in or register to get started.

Upcoming OSR Seminars
OSR has suspended in-person seminars due to the Covid-19 outbreak. But, don't miss your training! Attend via the internet instead!
Kernel Debugging 9-13 Sept 2024 Live, Online
Developing Minifilters 15-19 July 2024 Live, Online
Internals & Software Drivers 11-15 Mar 2024 Live, Online
Writing WDF Drivers 20-24 May 2024 Live, Online