c++wdmfilter-driver

IoBuildAsynchronousFsdRequest with IRP_MJ_WRITE


I developed a WDM filter driver on disk driver. I want to send an asynchronous request to write data on disk. The windows will crash when I delete the writeBuffer memory in WriteDataIRPCompletion function.

My question is: How can I safely free the writeBuffer memory without crashing?

This my send request code:

#pragma PAGEDCODE
NTSTATUS WriteToDeviceRoutine() {
    PMYDRIVER_WRITE_CONTEXT context = (PMYDRIVER_WRITE_CONTEXT)ExAllocatePool(NonPagedPool,sizeof(PMYDRIVER_WRITE_CONTEXT));
    context->writeBuffer = new(NonPagedPool) unsigned char[4096];

    PIRP pNewIrp = IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE,
         pdx->LowerDeviceObject,
         context->writeBuffer,(wroteRecordNodeCount<<SHIFT_BIT),
         &startingOffset,NULL);
   IoSetCompletionRoutine(pNewIrp,WriteDataIRPCompletion,context,TRUE,TRUE,TRUE);
   IoCallDriver(pdx->LowerDeviceObject,pNewIrp);
}

This is my completion routine code:

#pragma LOCKEDCODE
NTSTATUS WriteDataIRPCompletion(IN PDEVICE_OBJECT DeviceObject,IN PIRP driverIrp,IN PVOID Context) {
   PMDL mdl,nextMdl;
   KdPrint((" WriteDataIRPCompletion \n"));
   PMYDRIVER_WRITE_CONTEXT writeContext = (PMYDRIVER_WRITE_CONTEXT) Context;
   if(driverIrp->MdlAddress!=NULL){
      for(mdl=driverIrp->MdlAddress;mdl!=NULL;mdl = nextMdl) {
         nextMdl = mdl->Next;
         MmUnlockPages(mdl);
         IoFreeMdl(mdl);
         KdPrint(("mdl clear\n"));
     }
     driverIrp->MdlAddress = NULL;
   }
   delete [] writeContext->writeBuffer;
   if(Context)
      ExFreePool(Context);

    KdPrint(("leave WriteDataIRPCompletion \n"));
    return STATUS_CONTINUE_COMPLETION;
}

Solution

  • you error in next line

    context = ExAllocatePool(NonPagedPool,sizeof(PMYDRIVER_WRITE_CONTEXT));
    

    when must be

    context = ExAllocatePool(NonPagedPool,sizeof(MYDRIVER_WRITE_CONTEXT));
    

    not sizeof(PMYDRIVER_WRITE_CONTEXT) but sizeof(MYDRIVER_WRITE_CONTEXT) you allocate not structure but pointer to it.

    this not produce error only if your MYDRIVER_WRITE_CONTEXT containing single field writeBuffer and no more data. otherwise you overwrite allocated memory (which is only sizeof(PVOID)) and this create bug

    and about completion for IoBuildAsynchronousFsdRequest. unfortunately documentation not very good. here sated that

    Before calling IoFreeIrp, an additional step is required to free the buffer for an IRP built by IoBuildAsynchronousFsdRequest if the following are all true:

    The buffer was allocated from system memory pool.
    

    but then all attention for

    The Irp->MdlAddress field is non-NULL.

    however we must check and for IRP_DEALLOCATE_BUFFER|IRP_BUFFERED_IO, without this we can leak Irp->AssociatedIrp.SystemBuffer. need next code

    if (Irp->Flags & IRP_BUFFERED_IO)
    {
        if (Irp->Flags & IRP_INPUT_OPERATION)
        {
            if (!NT_ERROR(Irp->IoStatus.Status) && Irp->IoStatus.Information)
            {
                memcpy( Irp->UserBuffer, Irp->AssociatedIrp.SystemBuffer, Irp->IoStatus.Information );
            }
        }
    
        if (Irp->Flags & IRP_DEALLOCATE_BUFFER)
        {
            ExFreePool(Irp->AssociatedIrp.SystemBuffer);
            Irp->AssociatedIrp.SystemBuffer = 0;
        }
    
        Irp->Flags &= ~(IRP_DEALLOCATE_BUFFER|IRP_BUFFERED_IO);
    }
    

    and check for if (writeContext) after use writeContext->writeBuffer already senseless and nosense. really you need do check for context != NULL yet in WriteToDeviceRoutine()