Security Issues for I/O Control Codes

Secure processing of IRPs that contain I/O control codes depends on defining IOCTL codes properly and on carefully examining parameters that the driver receives with the IRP.

When defining new IOCTL codes, use the following rules:

  • Always specify a FunctionCode value that is equal to or greater than 0x800.

  • Always specify a RequiredAccess value. The I/O manager does not send IOCTLs if the caller has insufficient access rights.

  • Do not define IOCTL codes that allow callers to read or write nonspecific areas of kernel memory.

When processing IOCTL codes within a driver, use the following rules:

  • Whenever a driver's dispatch routines test received IOCTL codes, they must always test the entire 32-bit value.

  • Drivers can use IoValidateDeviceIoControlAccess to dynamically perform stricter access checking than that specified by the RequiredAccess value in the definition of the I/O control code.

  • Never read or write more data than the buffer that is pointed to by Irp->AssociatedIrp.SystemBuffer can contain. Therefore, always check Parameters.DeviceIoControl.InputBufferLength or Parameters.DeviceIoControl.OutputBufferLength in the IO_STACK_LOCATION structure to determine buffer limits.

  • Always zero driver-allocated buffers that will contain data intended for an application that originated an IOCTL request. That way, you will not accidentally copy sensitive data to the application.

  • For METHOD_IN_DIRECT and METHOD_OUT_DIRECT transfers, follow the rules above. Additionally, check for a NULL return value from MmGetSystemAddressForMdlSafe, which indicates that mapping failed or that a zero-length buffer was supplied.

  • For METHOD_NEITHER transfers, follow the rules that are provided in Using Neither Buffered Nor Direct I/O.