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_LOCATION
within the IRP. - Reference Counting: Managed via
IoMarkIrpPending
andIoCompleteRequest
.
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);