Send ioctl from a driver to another

Hello,

Sorry for my english.

I’ve wrote a little driver to manage memory some times ago, it is managing a pool of memory with physical address below 4GB.
I have an open source driver that have some issue when the system is under heavy memory load. This driver require some memory with physical address below 4GB that may not be avaible when it is loading.
So i tryed to remplace the MmAllocatePagesForMdl and the MmFreePagesFromMdl from the open source driver to ioctl call to my driver.

Here is the call function, i wrote, in the open source driver:

RtlInitUnicodeString(&ObjectPhysMem, L"\Device\MyDriver");
ntStatus = IoGetDeviceObjectPointer(&Object, FILE_ANY_ACCESS, &File, &Device);
if(!NT_SUCCESS(ntStatus))
{
return ntStatus;
}

KeInitializeEvent(&Event, NotificationEvent, FALSE);

irp = IoBuildDeviceIoControlRequest(ioCode, Device, inData, inSize, outData, outSize, FALSE, &Event, &ioStatusBlock);
if(NULL == irp)
{
ObDereferenceObject(File);
return ntStatus;
}

ntStatus = IoCallDriver(Device, irp);
if (STATUS_PENDING == ntStatus)
{
ntStatus = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
if (!NT_SUCCESS(ntStatus))
{
ObDereferenceObject(File);
return ntStatus;
}
ntStatus = ioStatusBlock.Status;
}
if(!NT_SUCCESS(ntStatus))
{
ObDereferenceObject(File);
return ntStatus;
}

ObDereferenceObject(File);
return STATUS_SUCCESS;

For allocation : inData = size_t*, inSize = sizeof(size_t), outData = PMDL*, outSize = sizeof(PMDL). I init the outData this way : *outData = NULL;
For free : inData = PMDL*, inSize = sizeof(PMDL), outData = NULL, outSize = 0

The IOCTL code are :
CTL_CODE(XXXX, YYYY, METHOD_BUFFERED, FILE_ANY_ACCESS)

The dispatch function of my driver is :

PIO_STACK_LOCATION irpStack;
ULONG dwInBufLen;
ULONG dwOutBufLen;
ULONG dwIoCtlCode;
NTSTATUS ntStatus;

irp->IoStatus.Status = STATUS_SUCCESS;
irp->IoStatus.Information = 0;

irpStack = IoGetCurrentIrpStackLocation(irp);

dwInBufLen = irpStack->Parameters.DeviceIoControl.InputBufferLength;
dwOutBufLen = irpStack->Parameters.DeviceIoControl.OutputBufferLength;

switch (irpStack->MajorFunction)
{
case IRP_MJ_DEVICE_CONTROL:
dwIoCtlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
switch (dwIoCtlCode)
{
case LOWALLOCATE:
if (dwInBufLen == sizeof(size_t) && dwOutBufLen == sizeof(PMDL))
{
int status;
PMDL pmdl = NULL;
status = myFuncAllocate(*((size_t*)irp->AssociatedIrp.SystemBuffer), &pmdl);
if (0 == status)
{
RtlCopyMemory(irp->AssociatedIrp.SystemBuffer, &pmdl, sizeof(PMDL));
irp->IoStatus.Information = sizeof(PMDL);
}
else
irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
}
else
irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
break;
case LOWFREE:
if (dwInBufLen == sizeof(PMDL) && dwOutBufLen == 0)
{
myFuncFree(*((PMDL*)irp->AssociatedIrp.SystemBuffer));
irp->IoStatus.Information = 0;
}
else
irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
break;
}
break;
}
ntStatus = irp->IoStatus.Status;
IoCompleteRequest(irp, IO_NO_INCREMENT);

return ntStatus;

In my test the dispatch function return 100% ntStatus = STATUS_SUCCESS with correct value as output. When i look at the content irp->UserBuffer and ipr->AssociatedIrp.SystemBuffer then value seems always good : irp->UserBuffer has the address of where to store the mdl address and ipr->AssociatedIrp.SystemBuffer have the address returned by my driver.
My problem is 50% of the time Windows freeze and when i watch the log display when it froze, it tell me that *outData is NULL. It is like the data returned by my driver are copied at a wrong place, making windows freeze, even if irp->UserBuffer seems right.

It seems i have not understand something in the driver world.
Anyone can explain me this issue, and what i do wrong ?

Best regards,
O.D.

On 19-Sep-2012 00:41, xxxxx@yahoo.fr wrote:
[snip]

My problem is 50% of the time Windows freeze and when i watch the log display when it froze, it tell me that *outData is NULL. It is like the data returned by my driver are copied at a wrong place, making windows freeze, even if irp->UserBuffer seems right.

It seems i have not understand something in the driver world.
Anyone can explain me this issue, and what i do wrong ?

Do not tamper with the IRPs and MDLs. Think of MDLs and IRPs as of
opaque structures that you cannot copy and overwrite as a whole.
Keep it simple: your driver allocated some memory, store the pointer and
size, and return to the caller pointer and size.
Same with freeing.
Also, the size parameter that you pass to the ioctl should not be
size_t, because it can be either 4 or 8 bytes depending on 32/64 bit.
Use some explicit type like UINT32.

Regards,
– pa

Hi,

Thanks for the answer.
Thanks for the advice on not using size_t, i’ll change that.

Sorry for my english, seems i was not clear enough.

I do not try to tamper with IRPs and MDLs.
I use an IRP because it is the only way i found to send a query/answer to my driver. If there is any other way, i’m interrested in.
My driver use just IRP to get input value, set ouput value and the completion value.
My call function build an IRP and use it with IoCallDriver, nothing else.

To debug my problem:
myFuncAllocate and myFuncFree are just proxy for MmAllocatePagesForMdl and MmFreePagesFromMdl. For allocation my driver return the PMDL returned by MmAllocatePagesForMdl. For free my driver call MmFreePagesFromMdl on the PMDL pass as input data. So i do nothing special with MDLs and I use them only as opaque structure.

Best regards,
OD

On 19-Sep-2012 16:03, xxxxx@yahoo.fr wrote:

Hi,

Thanks for the answer.
Thanks for the advice on not using size_t, i’ll change that.

Sorry for my english, seems i was not clear enough.

I do not try to tamper with IRPs and MDLs.
I use an IRP because it is the only way i found to send a query/answer to my driver. If there is any other way, i’m interrested in.
My driver use just IRP to get input value, set ouput value and the completion value.
My call function build an IRP and use it with IoCallDriver, nothing else.

To debug my problem:
myFuncAllocate and myFuncFree are just proxy for MmAllocatePagesForMdl and MmFreePagesFromMdl. For allocation my driver return the PMDL returned by MmAllocatePagesForMdl. For free my driver call MmFreePagesFromMdl on the PMDL pass as input data. So i do nothing special with MDLs and I use them only as opaque structure.

Best regards,
OD

Ah, so it returns PMDL. then it may be ok.
But writing into irp->AssociatedIrp.SystemBuffer looks suspicious to me:

if (0 == status)
{
RtlCopyMemory(irp->AssociatedIrp.SystemBuffer, &pmdl, sizeof(PMDL));

Can you return the MDL in some other way?
Another question is, should myFuncAllocate allocate a new MDL?
If the buffer in low memory is not too big, you can map it permanently
and return a virtual address. Otherwise, if you create a MDL for the
physical memory every time, you’ll eventually need to map it. This
mapping can fail and you must handle this situation.
– pa

Hello,

Thanks for the answer.

I try to fix a problem in this old open source driver, so i’m just “hooking” the MmAllocatePagesForMdl and MmFreePagesFromMdl to functions i have write time ago in another driver. Doing more would means rewrite all, i fear.
The open source driver manage the PMDL, taking care to map it, manage fail if it is NULL, …

I use the irp->AssociatedIrp.SystemBuffer to put the output data from what i read here for a METHOD_BUFFERED ioctl :

http://msdn.microsoft.com/en-us/library/windows/hardware/ff540663(v=vs.85).aspx

“METHOD_BUFFERED
For this transfer type, IRPs supply a pointer to a buffer at Irp->AssociatedIrp.SystemBuffer. This buffer represents both the input buffer and the output buffer that are specified in calls to DeviceIoControl and IoBuildDeviceIoControlRequest. The driver transfers data out of, and then into, this buffer.”

From what i understood the call to IoCompleteRequest should make Windows copy irp->IoStatus.Information data located at the adress in Irp->AssociatedIrp.SystemBuffer to the adress contain in Irp->UserBuffer

If there is any other method to call functions in my driver, i would be very interrested to learn them.

Best regards
OD

Pavel A wrote:

Ah, so it returns PMDL. then it may be ok.
But writing into irp->AssociatedIrp.SystemBuffer looks suspicious to me:

if (0 == status)
{
RtlCopyMemory(irp->AssociatedIrp.SystemBuffer, &pmdl, sizeof(PMDL));

Why is it suspicious? Note that this is not copying into the
SystemBuffer field, it’s copying to the address stored in SystemBuffer.
That’s exactly how you return something in a METHOD_BUFFERED request.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

“Tim Roberts” wrote in message news:xxxxx@ntdev…
> Pavel A wrote:
>> Ah, so it returns PMDL. then it may be ok.
>> But writing into irp->AssociatedIrp.SystemBuffer looks suspicious to me:
>>
>> if (0 == status)
>> {
>> RtlCopyMemory(irp->AssociatedIrp.SystemBuffer, &pmdl, sizeof(PMDL));
>
> Why is it suspicious? Note that this is not copying into the
> SystemBuffer field, it’s copying to the address stored in SystemBuffer.
> That’s exactly how you return something in a METHOD_BUFFERED request.
>
> –
> Tim Roberts, xxxxx@probo.com
> Providenza & Boekelheide, Inc.

Hm, you’re right. Then I don’t see anything suspicious at all in the posted
snippet. The OP is up to ordinary, boring debugging.
– pa