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/


Synchronization for WDF inverted call

Ehsan_TaheriEhsan_Taheri Member Posts: 187
edited September 10 in NTDEV

Hi Experts.
I want to implement a messaging model using inverted call in KMDF.
In my design a message-reply phase needs a few ioctls to to be completed.
To implement it I need to pass execution between control IO callback and other callbacks namely addDevice for now.
How am I supposed to do the synchronization?
I first thought I can achieve it using WDFWAITLOCK and implemented it happily but there is the kernel bugcheck and i found this:
https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/kmdf-wdfwaitlock
It seems I can't do it using WDSWAITLOCK.
Am I clear enough about what I need?
Can you suggest me a solution?
Do I have to do it Asynchronously?

Comments

  • Tim_RobertsTim_Roberts Member - All Emails Posts: 13,605

    I can't imagine what you mean by "pass execution", but I'm quite certain you misunderstand your needs. AddDevice is called by PnP when a new device instance is created. You don't get to control its execution at all.

    You're going to need to describe in more detail what you're trying to protect.

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

  • Ehsan_TaheriEhsan_Taheri Member Posts: 187
    Ok
    In addDevice I want to inform the user mode with the device information and ask for device access control rights using my library sendmessage command.
    I call sendmessage at the end after I create a separate messaging control device and finished creating pended Io queue. I mean the inverted call is initialized by then

    Sendmessage flow
    1. removes a pended request and retrieves output buffer then sends the message length and reply length in ioctl response.
    2. The send message execution must be blocked here and wait for a ioctl_get_message to be received in Ioctl callback function and output buffer retrieved then Io callback block and wait for sendmessage to copy message buffer. Then sendmessage should block letting Io callback complete ioctl_get_message
    3. Some other steps for recieving user reply Ioctl and storing data in sendmessage replybuffer parameter.

    My question is how I can achieve that.

    Can you approve of my approach or not even that?
    I welcome any guidance in that case?
  • Tim_RobertsTim_Roberts Member - All Emails Posts: 13,605

    Well, you don't do it like that. As a filter driver, you cannot abort the AddDevice process. If you return a failure, the system will simply set up the driver stack without you. The documentation describes that. Remember, by the time AddDevice is called, the bus driver has already created a PDO, AddDevice is just creating an FDO to drive it.

    I have a personal objection to the many, many Windows products that are intended to PREVENT the normal execution of Windows, rather than enhance it, and that's what you're describing. If you really want to prevent device creation, you need to intercept the PNP process earlier than that, like at the BusRelations level, maybe. But the flow is not as complicated as what you've described. Your filter will have created a control device early on. Your user-mode approver app will have submitted some requests. When a PNP request comes in, you'll complete a pended request, and store the PNP request somewhere without completing it. When the user-mode app responds,, you'll pop the pending PNP request and decide how to process it. There's no blocking and no syncing. If you're blocking a KM thread to wait for a UM response, then you're doing it wrong.

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

  • Ehsan_TaheriEhsan_Taheri Member Posts: 187
    edited September 11

    If you really want to prevent device creation

    I don't need to do that. I just deny write access depending on user mode app policy. I actually do it at the end of addDevice and store the access control data in device context.
    If I was not planning to implement inverted call as a library(for later reuse), it could be done as you said.
    but now I want to implement my library SendMessage function:

        NTSTATUS
            SendMessage(
                _In_ PVOID senderBuffer,
                _In_ ULONG senderBufferLength,
                _Out_ PVOID replyBuffer,
                _In_ ULONG replyLength
            );
    

    How would you implement such function using inverted call?

    If you're blocking a KM thread to wait for a UM response, then you're doing it wrong.

    Is that an always true statement?

    In that case how is the FltSendMessage implemented?

    What is important for me is implementing the library SendMessage function correctly. using sendmessage in addDevice was just a use case of mine.

    Post edited by Ehsan_Taheri on
  • Peter_Viscarola_(OSR)Peter_Viscarola_(OSR) Administrator Posts: 8,052
    edited September 11

    How would you implement such function using inverted call?

    Hmmm.. when SendMessage is called, you martial your args into the IN buffer, send your IOCTL and then... in your app you do whatever it is you want to handle the eventual completion of the Request. That means wait for the response or have a thread pool handle the completion, or whatever.

    Is that an always true statement?

    Always is a pretty high standard. But it is always the right design goal. Anything else is a trade-off. Any long (or indeterminate) wait is always the wrong design.

    In that case how is the FltSendMessage implemented?

    Huh?

    For the second time in one week, it seems people are confusing two related, but separate, concepts:

    • A thread can ask for either sync or asynchronous processing for a given Request

    • The driver servicing that Request can provide sync or asynchronous handling of the Request. Such handling will almost always be asynchronous.

    It’s the I/O Manager that’s responsible for “gluing” these things together. If an app asks for sync processing, clearly it’s not possible for the app to get back “status pending”... so, the I/O Manager detects this common case, and if the driver returns STATUS_PENDING blocks the calling app thread until the I/O Request is complete.

    So, yup... driver processing is always always always asynchronous unless the result is “immediately” available (such as a “get statistics” Request in which the driver just copies some stats into the OUT buffer and completes the Request).

    You need to take our WDF seminar. All this would become very clear.

    Peter

    Peter Viscarola
    OSR
    @OSRDrivers

  • Tim_RobertsTim_Roberts Member - All Emails Posts: 13,605

    In that case how is FltSendMessage implemented?

    I've never done file system drivers, but my guess is it's done like a named pipe or a local socket. There's system kernel infrastructure to make that happen, which you don't have. Remember that can't force a message to go through -- the UM app still has to call FilterGetMessage.

    What is important for me is implementing the library SendMessage function correctly. using sendmessage in addDevice was just a use case of mine.

    So you were thinking about SendMessage as a kernel mode function? I suppose you could have the function pop a pending request and complete it, but I don't know quite how you're going to get the result back. That needs to be asynchronous.

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

  • Ehsan_TaheriEhsan_Taheri Member Posts: 187

    So you were thinking about SendMessage as a kernel mode function?

    Yes.

    I suppose you could have the function pop a pending request and complete it, but I don't know quite how you're going to get the result back. That needs to be asynchronous.

    I tried to copy almost all my lib function prototypes from FltMgr.
    user mode calls getMessage and gets blocked or not. depending on kernel sending message prior to that or not
    driver calls sendmessage and send message buff to user and block execution,
    message is received by user. reply is sent by calling sendReply, IOcallback in kernel gets reply and signals send message to continue.
    and sendMessage can return result in outbuffer param. Guess I can patch it up using semaphore.
    I understand My objective here is not clear enough to ask for advice.
    Actually I don't want to continue taking your time on this specific topic.
    A few hours or days of playing with this is what I need to do.

  • Ehsan_TaheriEhsan_Taheri Member Posts: 187

    @Peter_Viscarola_(OSR) said:

    How would you implement such function using inverted call?

    Hmmm.. when SendMessage is called, you martial your args into the IN buffer, send your IOCTL and then... in your app you do whatever it is you want to handle the eventual completion of the Request. That means wait for the response or have a thread pool handle the completion, or whatever.

    Is that an always true statement?

    Always is a pretty high standard. But it is always the right design goal. Anything else is a trade-off. Any long (or indeterminate) wait is always the wrong design.

    In that case how is the FltSendMessage implemented?

    Huh?

    For the second time in one week, it seems people are confusing two related, but separate, concepts:

    • A thread can ask for either sync or asynchronous processing for a given Request

    • The driver servicing that Request can provide sync or asynchronous handling of the Request. Such handling will almost always be asynchronous.

    It’s the I/O Manager that’s responsible for “gluing” these things together. If an app asks for sync processing, clearly it’s not possible for the app to get back “status pending”... so, the I/O Manager detects this common case, and if the driver returns STATUS_PENDING blocks the calling app thread until the I/O Request is complete.

    So, yup... driver processing is always always always asynchronous unless the result is “immediately” available (such as a “get statistics” Request in which the driver just copies some stats into the OUT buffer and completes the Request).

    You need to take our WDF seminar. All this would become very clear.

    Peter

    I will make sure to read your post a few times and think on it to get the max understanding!
    Thanks

  • Peter_Viscarola_(OSR)Peter_Viscarola_(OSR) Administrator Posts: 8,052

    Filter Manager’s communications port functionality is implemented with... IOCTLs. Nothing more. It’s just a wrapper around the usual inverted call infrastructure.

    Peter

    Peter Viscarola
    OSR
    @OSRDrivers

  • Ehsan_TaheriEhsan_Taheri Member Posts: 187

    @Peter_Viscarola_(OSR) said:
    Filter Manager’s communications port functionality is implemented with... IOCTLs. Nothing more. It’s just a wrapper around the usual inverted call infrastructure.

    Peter

    I am exactly at the point I want to implement a function exactly like FltSendMessage(with reply).
    I guess It uses a few ioctls to come into kernel and go to be completed.
    FltSendMessage should also block and wait for those ioctls to complete so it can return after the overall progress is done.
    It should also sync with IOcallback to input data to or output data from IO buffers correctly.
    Rright?

  • Peter_Viscarola_(OSR)Peter_Viscarola_(OSR) Administrator Posts: 8,052

    Well... the call to DeviceIoControl can either block waiting for completion, OR you would use a completion port or other mechanism for servicing async I/Os. Probably not both.

    Peter

    Peter Viscarola
    OSR
    @OSRDrivers

  • Tim_RobertsTim_Roberts Member - All Emails Posts: 13,605

    It's not really that hard to see, is it? FilterGetMessage from UM sends an ioctl and blocks waiting for a reply. In response, the driver puts the ioctl into a manual queue. FltSendMessage from KM fetches the next waiting request, fills it, completes it, and apparently blocks until another request comes in.

    Blocking like that raises a red flag, but if you really think you need to do this in AddDevice, I don't see any alternative. In KMDF, at least, you can't pend that and complete it later.

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

  • Peter_Viscarola_(OSR)Peter_Viscarola_(OSR) Administrator Posts: 8,052
    There’s no way you should be doing anything like this in EvtDriverDeviceAdd. Sorry, but something is absolutely broken if you think you have to do this.

    Peter

    Peter Viscarola
    OSR
    @OSRDrivers

  • Peter_Viscarola_(OSR)Peter_Viscarola_(OSR) Administrator Posts: 8,052

    In terms of whether or not FltSendMessage blocks... it quite obviously does. The last parameter is the wait timeout limit. Its incumbent on the caller to call this function in a context where a wait will not be detrimental. That would generally rule-out calling this FltSendMessage in an arbitrary thread context.

    Peter

    Peter Viscarola
    OSR
    @OSRDrivers

  • Ehsan_TaheriEhsan_Taheri Member Posts: 187

    Thanks for your comments gentlemen,

    It's not really that hard to see, is it? FilterGetMessage from UM sends an ioctl and blocks waiting for a reply. In response, the driver puts the ioctl into a manual queue. FltSendMessage from KM fetches the next waiting request, fills it, completes it, and apparently blocks until another request comes in.

    There is also the case FltSendMessage is called in kernel first So I think FilterGetMessage At the start of execution blocks on a completion port for driver to complete a previously pended inverted call ioctl. And wont start with sending ioctl itself. That is how I implemented my library functions.

    As For blocking addDevice,
    I never insisted on sending a message in addDevice. (maybe that was just in my mind and I did not express it well)
    Well I wanted to set the access rule for device. The first place which came to my mind was addDevice, But as you said it seems to not be the right spot. so I can do it on the first ioctl encounter for device or some other place. I'm sure I will have a lot of options on where to query the access rules before the device starts being written to or read from. So no problem!

    Also I have my fltmessaging like library running. It was quite good for learning!!
    I query accessfrom user using my kernel library sendMessage function on IOCTL_DISK_IS_WRITABLE for DiskDrive class filter and successfully blocked writeAccess.
    The library is quite heavy compared to using inverted call directly on the filter so I will replace it later!
    But for now it can have a few happy days of being used while I am still working on my filter.

  • MBond2MBond2 Member Posts: 184

    I think you will struggle to make a useful general purpose library for inverted calls

  • Ehsan_TaheriEhsan_Taheri Member Posts: 187

    Did you emphasis on the struggle?
    was that a question?
    IDK how to respond!!

  • MBond2MBond2 Member Posts: 184

    Well, now I don't know how to respond. I assume that IDK means something like that. But my knowledge is very short on these kinds of acronyms.

    Clearly I did not ask a question, and I personally have never struggled with this since I have never attempted it. The point is I won't try because I don't think you can do it in a general purpose enough way to be bothered. The pattern is well known and understood, but the specifics are such that a library implementation that is useful and general purpose seems unlikely.

  • Ehsan_TaheriEhsan_Taheri Member Posts: 187

    IDK = I don't know.
    This case is closed to me now. But since you are so kind to post some advice I am giving a short explanation.
    The purpose here was not a business goal I was training mostly. However I made a library and I am using it currently. It was a bit hard for me as a learner. But not that much hard you mentioned.
    Of course we don't know if my library is perfect enough and optimized. But it is working for me.
    A real general purpose library should be written by experienced experts to be completely optimized and consider low performance, high performance and low recourse conditions and probably more considerations I'm not aware of yet.
    I think it's better to not drag this discussion anymore since the case is solved and I kind of feel it is against the community guidelines to post more

  • MBond2MBond2 Member Posts: 184

    the case is closed? does that mean that you no longer intend to pursue this goal or something else?

    20 years ago I was not an experienced person, but I understood a topic well enough to make a generally purpose library. Shortly there after Microsoft introduced the thread pool APIs in UM rendering all that I had done obsolete. I still use my code for this instead of theirs, but had is started 1 year later, I'm sure I would do the reverse.

    I don't think that any of the guidelines opposes learning by those who want to. in fact I think that we actively encourage it - no matter how harsh some of the responses might seem

  • Ehsan_TaheriEhsan_Taheri Member Posts: 187

    the case is closed? does that mean that you no longer intend to pursue this goal or something else?

    No. it is the opposite. The goal for this post and that project is reached. As I said before, I got the help I needed on this topic and I made my library.
    I am using it now.

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

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!
Internals & Software Drivers 30 Nov 2020 LIVE ONLINE
Writing WDF Drivers 7 Dec 2020 LIVE ONLINE
Developing Minifilters Early 2021 LIVE ONLINE