IoBuildAsynchronousFsdRequest с IRP_MJ_WRITE

Я разработал драйвер фильтра WDM для драйвера диска. Я хочу отправить асинхронный запрос на запись данных на диск. Windows вылетит при удалении writeBuffer память в WriteDataIRPCompletion функция.

Мой вопрос: как я могу безопасно освободить 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;
}

2

Решение

вы ошиблись в следующей строке

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. к сожалению документация не очень хорошая. здесь, что

Перед вызовом IoFreeIrp требуется дополнительный шаг, чтобы освободить
буфер для IRP, созданный IoBuildAsynchronousFsdRequest, если
Следующее все верно:

The buffer was allocated from system memory pool.

но тогда все внимание для

Поле Irp-> MdlAddress не равно 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 уже бессмысленно и глупо. действительно нужно проверить context != NULL еще в WriteToDeviceRoutine()

0

Другие решения

Я не слишком знаком со спецификой того, с чем вы работаете, поэтому вот несколько деталей, которые привлекли мое внимание.

В WriteDataIRPCompletion функция

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

Обратите внимание, что ваш writeContext происходит от вашего Context аргумент. Тем не менее, вы, кажется, удаляете / освобождаете выделенную память дважды.

ExFreePool функция документы государство:

Указывает адрес освобождаемого блока памяти пула.

Похоже, delete [] writeContext->writeBuffer; линия может быть причиной проблемы, и это просто нужно удалить.

Как сейчас, часть памяти, которая должна быть freeд функция уже была вручную deleted к тому времени, когда вы вызываете ExFreePool, но не установлено NULL, что в свою очередь вызывает ExFreePool получить недействительный теперь указатель (то есть ненулевой указатель, указывающий на нераспределенную память) в своем Context аргумент, вызывающий аварию.

В WriteToDeviceRoutine функция

Документация для ExFreePool явно заявляет, что освобождает память, выделенную другим функциям, таким как ExAllocatePool и другие друзья.

Тем не менее, ваш код пытается выделить / освободить writeContext->writeBuffer непосредственно используя new/delete операторы соответственно. Кажется, вы должны распределять свою память ExAllocatePool а затем избавиться от ExFreePool вместо того, чтобы пытаться делать такие вещи вручную, как это.

Эти функции могут организовывать память определенным образом, и если / когда это предварительное условие не выполняется в ExFreePool, это может привести к аварии.


На отдельном примечании кажется странным, что вы проверяете if(Context) является нулевым перед вызовом ExFreePool, но не выше, прежде чем пытаться набрать для вашего местного writeContext Переменная и использовать его.

Может быть, вы также должны проверить в этой первой точке использования? Если Context является всегда не нулевой, тогда проверка может быть ненужной до вызова ExFreePool,

0

По вопросам рекламы [email protected]