Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results
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/
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 | 7 February 2022 | Live, Online |
Kernel Debugging | 21 March 2022 | Live, Online |
Developing Minifilters | 23 May 2022 | Live, Online |
Writing WDF Drivers | 12 September 2022 | Live, Online |
Comments
Result is still code 1 (incorrect function). This further indicates that the driver's MJ_CONTROL routine isn't getting called.
Also, ... I have a second driver with similar code, and I can perform DeviceIoControl OK with that driver. This is encouraging, because I can compare the user and kernel side code between the two and hopefully see what I changed recently in the former that broke it. If I find something, I'll post it.
>
> Can you tell me what are possible causes of this error code from calling this function, or at least what may be relevant to my particular case?
Either STATUS_NOT_IMPLEMENTED or STATUS_INVALID_DEVICE_REQUEST will map to ERROR_INVALID_FUNCTION in user mode.
> The driver's DeviceControl routine handles an unknown IOCTL code (or any incorrect parameters for the correct IOCTL code) by setting the IRP with a STATUS_INVALID_DEVICE_REQUEST, or C0000010h. So I suspect that DeviceControl is not even getting called.
Oh, I suspect it is. STATUS_INVALID_DEVICE_REQUEST will bubble up as ERROR_INVALID_FUNCTION.
How much validation do you do? One common problem is to have a 32-bit app calling a 64-bit driver, where one of the fields in the buffer structure has a different size or causes it to have different padding.
—
Tim Roberts, [email protected]
Providenza & Boekelheide, Inc.
Tim Roberts, [email protected]
Providenza & Boekelheide, Inc.
Hi again, Tim,
I just figured that out. I called the second driver with an unknown control code, to which it responds by posting STATUS_INVALID_DEVICE_REQUEST to the IRP and also returning the same. And sure enough, on the user side I saw ERROR_INVALID_FUNCTION, just like you said.
Pity that this behavior is not documented by Microsoft. It would have saved me from going down the rabbit hole.
By the way, what's the difference between the return value from my DispatchControl and the value I store in pIrp->IoStatus.Status? I'm planning to use a DPC to complete the DispatchControl in some cases, so the pIrp->IoStatus.Status value presumably won't be used until later when the DPC calls IoCompleteRequest (). What is DispatchControl supposed to return in this case?
Thanks.
1. If the dispatch routine does complete the IRP, either successfully or otherwise, then it stores the status in the IRP _and_ returns the same status value.
2. If the dispatch routine does not complete the IRP, then it returns STATUS_PENDING.
This seems simple enough. Is my understanding correct?
I'm curious about a possible race condition. If I queue a DPC to complete the IRP, is it possible that the DPC will start running immediately and will call IoCompleteRequest before the dispatch routine returns with STATUS_PENDING. I suppose this is not a problem, either because the kernel won't run any new DPCs until the dispatch routine returns, or because the kernel realizes the IRP has already been completed and does the right thing. Can you confirm this?
Thanks.
>
> I just figured that out. I called the second driver with an unknown control code, to which it responds by posting STATUS_INVALID_DEVICE_REQUEST to the IRP and also returning the same. And sure enough, on the user side I saw ERROR_INVALID_FUNCTION, just like you said.
>
> Pity that this behavior is not documented by Microsoft. It would have saved me from going down the rabbit hole.
It IS documented. Or at least it was. There is an MSDN page somewhere that documents the mapping from NTSTATUS codes to Win32 error codes.
> By the way, what's the difference between the return value from my DispatchControl and the value I store in pIrp->IoStatus.Status?
The driver is required by contract to return the same value you put in the IoStatus, except for IRPs you pend. That's why KMDF doesn't give you the chance to get that wrong.
> I'm planning to use a DPC to complete the DispatchControl in some cases, so the pIrp->IoStatus.Status value presumably won't be used until later when the DPC calls IoCompleteRequest (). What is DispatchControl supposed to return in this case?
STATUS_PENDING. You'll need to call IoMarkIrpPending in that case as well.
—
Tim Roberts, [email protected]
Providenza & Boekelheide, Inc.
Tim Roberts, [email protected]
Providenza & Boekelheide, Inc.
>
> I just read the Microsoft docs article "Completing the IRP". My reading of this is:
> 1. If the dispatch routine does complete the IRP, either successfully or otherwise, then it stores the status in the IRP _and_ returns the same status value.
> 2. If the dispatch routine does not complete the IRP, then it returns STATUS_PENDING.
>
> This seems simple enough. Is my understanding correct?
Yep, with the additional requirement that you call IoMarkIrpPending in the 2nd case.
> I'm curious about a possible race condition. If I queue a DPC to complete the IRP, is it possible that the DPC will start running immediately and will call IoCompleteRequest before the dispatch routine returns with STATUS_PENDING. I suppose this is not a problem, either because the kernel won't run any new DPCs until the dispatch routine returns, or because the kernel realizes the IRP has already been completed and does the right thing. Can you confirm this?
Yes, as long as you have marked the IRP as pending. I assume you wouldn't just be queuing a DPC; that would be silly, because you could just complete the IRP in the dispatch routine. I assume you're waiting for a timer or some piece of hardware, which will then cause the DPC to be queued.
—
Tim Roberts, [email protected]
Providenza & Boekelheide, Inc.
Tim Roberts, [email protected]
Providenza & Boekelheide, Inc.
I get NON-ZERO return from DeviceIoControl() using
IOCTL_STORAGE_QUERY_PROPERTY, QueryType = PropertyExistsQuery (which I
take to mean that said property is available)
but then get ERROR_INVALID_FUNCTION with PropertyStandardQuery.
The semantics of "STATUS_NOT_IMPLEMENTED" and
"STATUS_INVALID_DEVICE_REQUEST" suggest that information is lost in
mapping both to the same error code.
If it's NOT_IMPLEMENTED then the positive result from the initial query
seems to be in error (standard Windows 10 disk drivers).
If it's INVALID_DEVICE_REQUEST then perhaps I'm doing something wrong
with this particular device?
Which seems more likely, given that with other devices I get consistent
results?