IoBuildAsynchronousFsdRequest with IRP_MJ_WRITE

IoBuildAsynchronousFsdRequest with IRP_MJ_WRITE

本文关键字:MJ WRITE IRP with IoBuildAsynchronousFsdRequest      更新时间:2023-10-16

我在磁盘驱动程序上开发了一个WDM筛选器驱动程序。我想发送一个异步请求以在磁盘上写入数据。当我删除WriteDataIRPCompletion函数中的writeBuffer内存时,窗口将崩溃。

我的问题是:如何安全地释放writeBuffer内存而不会崩溃?

这是我的发送请求代码:

#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);
}

这是我的完成例程代码:

#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 clearn"));
     }
     driverIrp->MdlAddress = NULL;
   }
   delete [] writeContext->writeBuffer;
   if(Context)
      ExFreePool(Context);
    KdPrint(("leave WriteDataIRPCompletion n"));
    return STATUS_CONTINUE_COMPLETION;
}
您在

下一行出错

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

何时必须

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

不是sizeof(PMYDRIVER_WRITE_CONTEXT)而是sizeof(MYDRIVER_WRITE_CONTEXT)你分配的不是结构,而是指向它的指针。

仅当您的MYDRIVER_WRITE_CONTEXT包含单个字段writeBuffer并且没有更多数据时,这才会产生错误。 否则,您将覆盖分配的内存(仅大小(PVOID((,这会产生错误

关于完成IoBuildAsynchronousFsdRequest. 不幸的是,文档不是很好。 这里说

在调用 IoFreeIrp 之前,需要执行额外的步骤来释放 由 IoBuildAsyncFsdRequest 构建的 IRP 的缓冲区,如果 以下都是正确的:

The buffer was allocated from system memory pool.

但随后所有的注意力都为

Irp->MdlAddress 字段为非空。

但是我们必须检查并IRP_DEALLOCATE_BUFFER|IRP_BUFFERED_IO ,没有这个,我们可能会泄漏Irp->AssociatedIrp.SystemBuffer . 需要下一个代码

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);
}

并在使用检查if (writeContext) writeContext->writeBuffer已经毫无意义和无稽之谈了。 真的,您需要检查context != NULL尚未WriteToDeviceRoutine()

我不太熟悉你正在使用的细节,所以这里有一些细节引起了我的注意。

WriteDataIRPCompletion函数

PMYDRIVER_WRITE_CONTEXT writeContext = (PMYDRIVER_WRITE_CONTEXT) Context;
// ...
delete [] writeContext->writeBuffer;
if(Context)
     ExFreePool(Context);

请注意,您的writeContext源自您的Context参数。但是,您似乎删除/释放了两次分配的内存。

ExFreePool函数文档指出:

指定正在解除分配的池内存块的地址。

看起来delete [] writeContext->writeBuffer;行可能导致问题,只需要将其删除即可。

就像现在一样,应该由函数free的部分内存已经在您调用 ExFreePool 时手动delete d,但未设置为 NULL ,这反过来又导致ExFreePool在其 Context 参数中接收现在无效的指针(即指向已解除分配的内存的非空指针(, 导致崩溃。

WriteToDeviceRoutine函数

ExFreePool的文档明确指出,它会释放已分配给其他函数(如ExAllocatePool和其他好友(的内存。

但是,您的代码尝试分别使用 new/delete 运算符直接分配/释放writeContext->writeBuffer。似乎您应该使用ExAllocatePool分配内存,然后使用ExFreePool进行分配,而不是尝试像那样手动执行操作。

这些功能可能以特定的方式组织内存,如果/当ExFreePool中不满足此前提条件时,它可能会崩溃。


另外,在调用 ExFreePool 之前检查 if(Context) 为 null 似乎很奇怪,但在您尝试为局部 writeContext 变量进行类型转换并使用它之前,则不检查上面。

也许您还应该在第一个使用点进行检查?如果Context始终为非 null,则在调用 ExFreePool 之前也可能不需要检查。