Errors in Referencing User-Space Addresses
Any driver, whether supporting IRPs or fast I/O operations, should validate any address in user space before trying to use it. The I/O manager does not validate such addresses, nor does it validate pointers that are embedded in buffers passed to drivers.
Failure to Validate Addresses Passed in METHOD_NEITHER IOCTLs and FSCTLs
The I/O manager does no validation whatsoever for METHOD_NEITHER IOCTLs and FSCTLs. To ensure that user-space addresses are valid, the driver must use the ProbeForRead and ProbeForWrite routines, enclosing all buffer references in try/except blocks.
In the following example, the driver assumes that the value passed in the Type3InputBuffer represents a valid address.
case IOCTL_GET_HANDLER:
{
PULONG EntryPoint;
EntryPoint =
IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
*EntryPoint = (ULONG)DriverEntryPoint;
...
}
The following code avoids this problem:
case IOCTL_GET_HANDLER:
{
PULONG_PTR EntryPoint;
EntryPoint =
IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
try
{
if (Irp->RequestorMode != KernelMode)
{
ProbeForWrite(EntryPoint,
sizeof(ULONG_PTR),
TYPE_ALIGNMENT(ULONG_PTR));
}
*EntryPoint = (ULONG_PTR)DriverEntryPoint;
}
except(EXCEPTION_EXECUTE_HANDLER)
{
...
}
...
}
Note also that the correct code casts DriverEntryPoint to a ULONG_PTR, instead of a ULONG. This change allows for use in a 64-bit Windows environment.
Failure to validate pointers embedded in buffered I/O requests
Often drivers embed pointers within buffered requests, as in the following example:
struct ret_buf
{
void *arg; // Pointer embedded in request
int rval;
};
pBuf = Irp->AssociatedIrp.SystemBuffer;
...
arg = pBuf->arg; // Fetch the embedded pointer
...
// If the arg pointer is not valid, the following
// statement can corrupt the system:
RtlMoveMemory(arg, &info, sizeof(info));
In this example, the driver should validate the embedded pointer by using the ProbeXxx routines enclosed in a try/except block in the same way as for the METHOD_NEITHER IOCTLs described earlier. Although embedding a pointer allows a driver to return extra information, a driver can more efficiently achieve the same result by using a relative offset or a variable length buffer.
For more information about using try/except blocks to handle invalid addresses, see Handling Exceptions.