none
Inverted call vs mapped user-mode events RRS feed

  • Question

  • Hi All.

    I have several applications (listeners) that need to receive notifications from events occurring in hardware managed by a kmdf driver stack.  Nothing new here.  I was gung-ho to implement inverted call where each user mode listener has a pended IOCTL that gets completed when an event of interest occurs in the kmdf driver.  The slight wrinke is that every user-mode client must receive every notification, regardless of how long it takes it to get around to pending the next IOCTL for notification.  The issue is:

    Suppose app A,B and C have pended an IOCTL which the kmdf driver completes as soon as an event of interest comes along. Another event occurs in the kmdf driver but only App A and App B have completed processing the previous event and posted a new pended request.  App C is taking its time, and the driver now completes the requests for for App A and App B with the second event.  App C comes dragging along later, posts its IOCTL and has entirely missed the 2nd event.

    Several brute-force solutions come to mind, but is there a preferred / simpler way of ensuring that all listeners get all events?  The legacy solution had many user mode Events (one for each event type) mapped to kernel space with a separate handler for each.

    Any help appreciated,

     


    • Edited by Wade_Dawson Monday, November 24, 2014 9:31 PM
    Monday, November 24, 2014 9:30 PM

Answers

  • Personally, I've used a queue of events per file object for cases like this.  Each app's open means there is a WDF fileobject and in its context I have a queue head with the list of event's that have occurred.  The IOCTl picks up the event from the queue first and only pends when the queue is empty.;


    Don Burn Windows Filesystem and Driver Consulting Website: http://www.windrvr.com

    Monday, November 24, 2014 10:09 PM
  • Hi Don. Yes. All apps should get all events, so I'm not sure what I was thinking with a global queue. I would need to associate the file objects ( vector or linked list) so they can be enumerated when an event comes in. Thanks for your time!
    • Marked as answer by Wade_Dawson Tuesday, November 25, 2014 12:21 PM
    Tuesday, November 25, 2014 12:21 PM

All replies

  • Use a notification event object that is signaled by the driver. You can create the event in the app, then pass the handle (to the event) to the driver. The driver calls ObReferenceObjectByHandle to get a pointer to the event object. Multiple threads can wait on the object. When the driver signals the event (by calling KeSetEvent), all the threads will be resumed. Ensure that the driver decrements the reference count on the event by calling ObDereferenceObject before the app exits!

     -Brian


    Azius Developer Training www.azius.com Windows device driver, internals, security, & forensics training and consulting. Blog at www.azius.com/blog

    Monday, November 24, 2014 10:03 PM
    Moderator
  • Personally, I've used a queue of events per file object for cases like this.  Each app's open means there is a WDF fileobject and in its context I have a queue head with the list of event's that have occurred.  The IOCTl picks up the event from the queue first and only pends when the queue is empty.;


    Don Burn Windows Filesystem and Driver Consulting Website: http://www.windrvr.com

    Monday, November 24, 2014 10:09 PM
  • Hi Brian.  What you've suggested is basically the current implementation.  Because no data can be passed, to identify each event type, there are ~10 separate user-mode events mapped into kernel space using ObReferenceObjectByHandle() to identify each event.  The "listeners" all call WaitForMultipleObjects() then determine the signaled event, process the event, then loop back to WaitForMultipleObjects() waiting for the next event.  The issue with this concept by itself is that once the "multiple threads" run because of the single KSEvent being signaled, there is no guarantee that they will ALL be ready and waiting for the next signaling of the event by the kmdf driver by the time the next event happens in hardware.  I.e., some of the threads may not have finished processing the previous event and gotten back around to their respective WaitForMultipleObject() calls.  One thing I'm not sure about is if the event has signaled before a particular thread gets back around to calling WaitForMultipleObjects() will the event be immediately signaled, or does it depend on the UM call to CreateEvent()? 
    Tuesday, November 25, 2014 12:27 AM
  • In that case, I'd share a page of memory between the driver and the application. On that shared page, implement a ring buffer with multiple readers (Bing/Google for the implementation details of multiple reader ring buffers). The contents of the ring would be the notifications and context information. That way, even if one thread fell behind, it wouldn't miss any data because each thread would have its own pointer into the ring.

     -Brian


    Azius Developer Training www.azius.com Windows device driver, internals, security, & forensics training and consulting. Blog at www.azius.com/blog

    Tuesday, November 25, 2014 12:33 AM
    Moderator
  • Hi Don.  I was leaning towards something along these lines.  Does this sound feasible?  

    I was thinking of adding an event list to the FileObject's context and creating a global (shared by all FileObjects) "pended request" queue.  

    So when an IOCTL (request) arrives you get the associated FileObject and check the event list stashed in its context.  If the list is empty, you push the request onto the global "pended request" queue.  If the FileObject's event list is not empty, you pop an event from it and complete the request.

    Conversely, when an event arrives, you spin through the entire queue, and for each queued request, check the associated FileObject's event list.  If the event list is empty, you complete the request with the current event.  If the FileObject's event list is not empty, you push the current event to the list, pop an (oldest) event from the event list and complete the request.

    thanks,

    -Wade

    Tuesday, November 25, 2014 2:19 AM
  • Wade, Is the goal to have all apps get all events, or apps get the events as they arrive?  The global request queue means that you are either searching for all  fileobjects, or only the app with the oldest request gets it.  I was under the impression that all the apps were to recieve all the events, in that case have a manual queue for each fileobject and when an event occurss either complete the requests from the file objects queue, or else insert the event onto a linked list the event for the file object.  When a request comes in check for the   fileobject context for a non-empty event list and complete the request immediately, and free the event list item, or if the event queue is empty queue the request to the fileobjects request queue.

    Don Burn Windows Filesystem and Driver Consulting Website: http://www.windrvr.com

    Tuesday, November 25, 2014 2:35 AM
  • Hi Don. Yes. All apps should get all events, so I'm not sure what I was thinking with a global queue. I would need to associate the file objects ( vector or linked list) so they can be enumerated when an event comes in. Thanks for your time!
    • Marked as answer by Wade_Dawson Tuesday, November 25, 2014 12:21 PM
    Tuesday, November 25, 2014 12:21 PM
  • Hi Pavel.  Agreed, that is a more concise way of stating the problem.

     
    Tuesday, November 25, 2014 2:48 PM