IRP Handling in Windows Kernel
An I/O Request Packet (IRP) is the primary data structure used by the Windows kernel to communicate I/O requests between the I/O manager and driver stacks. Proper handling of IRPs is essential for driver stability, performance, and security.
Key Concepts
- IRP Lifecycle: Creation → Dispatch → Completion → Deletion.
- Major Function Codes: Define the type of operation (e.g.,
IRP_MJ_READ,IRP_MJ_WRITE). - Stack Locations: Each driver in the stack gets its own
IO_STACK_LOCATIONwithin the IRP. - Reference Counting: Managed via
IoMarkIrpPendingandIoCompleteRequest.
Typical IRP Dispatch Routine
NTSTATUS
MyDriverDispatch(
_In_ PDEVICE_OBJECT DeviceObject,
_Inout_ PIRP Irp
)
{
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
switch (irpSp->MajorFunction) {
case IRP_MJ_CREATE:
// Handle create/open
break;
case IRP_MJ_READ:
// Process read request
break;
case IRP_MJ_WRITE:
// Process write request
break;
default:
// Pass down unhandled IRPs
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
}
// Complete IRP if handled here
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
Common Pitfalls
| Issue | Consequence | Fix |
|---|---|---|
Failing to set IoStatus.Status | Undefined behavior, possible system crash | Always assign a valid NTSTATUS before completion |
Missing IoCompleteRequest | IRP leak, driver hang | Complete every IRP you fully handle |
| Improper reference counting | Premature deletion of IRP | Use IoMarkIrpPending when necessary |
IRP Completion Routines
When a lower driver processes an IRP asynchronously, you can attach a completion routine:
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(
Irp,
MyCompletionRoutine,
Context,
TRUE,
TRUE,
TRUE);
return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);