I am in the process of developing a WDM device driver which already
handles pretty well several IOCTL codes when sent by a user-mode
application, using DeviceIoControl().
Now I want to make sure that driver can handle any crazy input that an
application programmer may throw at it. For that purpose I placed in
the switch case for the pIoStackLocation-
>Parameters.DeviceIoControl.IoControlCode a default case that all it
does is this:
default:
{
pIRP->IoStatus.Information = 0;
ntStatus = STATUS_INVALID_DEVICE_REQUEST;
pIRP->IoStatus.Status = ntStatus;
IoCompleteRequest(pIRP, IO_NO_INCREMENT);
return ntStatus;
}
This works great (i.e. returns an error with a suitable GetLastError()
code) when I test it with an unrecognized IOCTL as follows:
int dummy;
if ( !DeviceIoControl(hWdm, IOCTL_UNRECOGNIZED,
NULL, 0, //
input
&dummy, sizeof(dummy), // output
&BytesReturned, NULL))
but when I pass the output paramter as NULL, too (see below), the
system hangs (i.e. only a hard reset would get it out of that state):
if ( !DeviceIoControl(hWdm, IOCTL_UNRECOGNIZED,
NULL, 0, // input
NULL, 0, // output
&BytesReturned, NULL))
Notice, the only difference is "NULL, 0" vs. "&dummy,
sizeof(dummy)" ...
On the WinDbg side, all I can see is the following:
Access violation - code c0000005 (!!! second chance !!!)
*** ERROR: Symbol file could not be found. Defaulted to export
symbols for ks.sys -
ks!KsDispatchIrp+0x3b:
f82b9f0d ff10 call dword ptr [eax]
Which doesn't give me enough information about what's happening in the
driver.
So, for now, my workaround is to never pass a NULL output buffer
pointer to DeviceIoControl() - but is it really impossible to protect
a driver against something like this?
I thought that (not) handling an unrecognized IOCTL is a no brainer
(as described above in the 'default' case).
What am I missing?
Thanks,
Don