IRP_MJ_WRITE 的 IoBuildAsynchronousFsdRequest
IoBuildAsynchronousFsdRequest with IRP_MJ_WRITE
我在磁盘驱动上开发了一个WDM过滤驱动。我想发送一个异步请求将数据写入磁盘。当我删除 WriteDataIRPCompletion
函数中的 writeBuffer
内存时 windows 会崩溃。
我的问题是:如何在不崩溃的情况下安全地释放 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 clear\n"));
}
driverIrp->MdlAddress = NULL;
}
delete [] writeContext->writeBuffer;
if(Context)
ExFreePool(Context);
KdPrint(("leave WriteDataIRPCompletion \n"));
return STATUS_CONTINUE_COMPLETION;
}
我不太了解您正在处理的具体内容,所以这里有一些细节引起了我的注意。
在WriteDataIRPCompletion
函数中
PMYDRIVER_WRITE_CONTEXT writeContext = (PMYDRIVER_WRITE_CONTEXT) Context;
// ...
delete [] writeContext->writeBuffer;
if(Context)
ExFreePool(Context);
请注意,您的 writeContext
源自您的 Context
论点。不过,你好像是deleting/freeing两次分配的内存。
ExFreePool
函数docs状态:
Specifies the address of the block of pool memory being deallocated.
看来问题可能是 delete [] writeContext->writeBuffer;
行造成的,只需将其删除即可。
就像现在一样,当您调用 ExFreePool
、但未设置为 NULL
,这反过来导致 ExFreePool
接收到现在无效的指针(即非空指针指向已释放内存的指针)在其 Context
参数中,导致崩溃。
在WriteToDeviceRoutine
函数中
ExFreePool
的文档明确指出它会释放已分配给其他函数的内存,例如 ExAllocatePool
和其他朋友。
但是,您的代码试图分别使用 new
/delete
运算符 allocate/deallocate 和 writeContext->writeBuffer
。似乎您应该使用 ExAllocatePool
分配内存,然后使用 ExFreePool
解除分配,而不是像那样尝试手动执行操作。
这些函数可能以特定方式组织内存,if/when在 ExFreePool
中不满足此先决条件,它可能会以崩溃告终。
另外,在调用 ExFreePool
之前检查 if(Context)
是否为 null 似乎很奇怪,但在尝试为本地 writeContext
变量进行类型转换之前却没有检查并使用它。
也许您还应该在第一次使用时检查一下?如果 Context
总是 非空,那么在调用 ExFreePool
.
之前也可能不需要检查
你在下一行出错
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
并且没有更多数据时,这不会产生错误。否则你会覆盖分配的内存(只有 sizeof(PVOID)),这会产生错误
以及关于 IoBuildAsynchronousFsdRequest
的完成。不幸的是文档不是很好。这里满足
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.
但随后所有注意力都集中在
The Irp->MdlAddress field is non-NULL.
但是我们必须检查 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
已经毫无意义和无意义。您真的需要在 WriteToDeviceRoutine()
中检查 context != NULL
我在磁盘驱动上开发了一个WDM过滤驱动。我想发送一个异步请求将数据写入磁盘。当我删除 WriteDataIRPCompletion
函数中的 writeBuffer
内存时 windows 会崩溃。
我的问题是:如何在不崩溃的情况下安全地释放 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 clear\n"));
}
driverIrp->MdlAddress = NULL;
}
delete [] writeContext->writeBuffer;
if(Context)
ExFreePool(Context);
KdPrint(("leave WriteDataIRPCompletion \n"));
return STATUS_CONTINUE_COMPLETION;
}
我不太了解您正在处理的具体内容,所以这里有一些细节引起了我的注意。
在WriteDataIRPCompletion
函数中
PMYDRIVER_WRITE_CONTEXT writeContext = (PMYDRIVER_WRITE_CONTEXT) Context; // ... delete [] writeContext->writeBuffer; if(Context) ExFreePool(Context);
请注意,您的 writeContext
源自您的 Context
论点。不过,你好像是deleting/freeing两次分配的内存。
ExFreePool
函数docs状态:
Specifies the address of the block of pool memory being deallocated.
看来问题可能是 delete [] writeContext->writeBuffer;
行造成的,只需将其删除即可。
就像现在一样,当您调用 ExFreePool
、但未设置为 NULL
,这反过来导致 ExFreePool
接收到现在无效的指针(即非空指针指向已释放内存的指针)在其 Context
参数中,导致崩溃。
在WriteToDeviceRoutine
函数中
ExFreePool
的文档明确指出它会释放已分配给其他函数的内存,例如 ExAllocatePool
和其他朋友。
但是,您的代码试图分别使用 new
/delete
运算符 allocate/deallocate 和 writeContext->writeBuffer
。似乎您应该使用 ExAllocatePool
分配内存,然后使用 ExFreePool
解除分配,而不是像那样尝试手动执行操作。
这些函数可能以特定方式组织内存,if/when在 ExFreePool
中不满足此先决条件,它可能会以崩溃告终。
另外,在调用 ExFreePool
之前检查 if(Context)
是否为 null 似乎很奇怪,但在尝试为本地 writeContext
变量进行类型转换之前却没有检查并使用它。
也许您还应该在第一次使用时检查一下?如果 Context
总是 非空,那么在调用 ExFreePool
.
你在下一行出错
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
并且没有更多数据时,这不会产生错误。否则你会覆盖分配的内存(只有 sizeof(PVOID)),这会产生错误
以及关于 IoBuildAsynchronousFsdRequest
的完成。不幸的是文档不是很好。这里满足
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.
但随后所有注意力都集中在
The Irp->MdlAddress field is non-NULL.
但是我们必须检查 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
已经毫无意义和无意义。您真的需要在 WriteToDeviceRoutine()
context != NULL