Modifying data when processing IRP_WRITE request

Hello everybody. I wrote a wdf filter driver for the usb device. When EvtIoWrite triggers, I want to change the data and put it on the device. I tried to use these methods WdfRequestRetrieveInputMemory, WdfMemoryCopyFromBuffer and WdfMemoryCopyToBuffer. But after sending this request to the next driver, there is a fatal error 0x00000023: FAT_FILE_SYSTEM. If you can explain the principle or give an example, I will be very happy. Thank you.

xxxxx@gmail.com wrote:

Hello everybody. I wrote a wdf filter driver for the usb device.

For WHICH USB device?  Upper filter or lower filter?

When EvtIoWrite triggers, I want to change the data and put it on the device. I tried to use these methods WdfRequestRetrieveInputMemory, WdfMemoryCopyFromBuffer and WdfMemoryCopyToBuffer. But after sending this request to the next driver, there is a fatal error 0x00000023: FAT_FILE_SYSTEM.

How did you decide which requests to modify?  If you do have a filter on
USB disks, and you arbitrarily change write requests without
understanding what those requests contain, then you should not be
surprised by this result.

What are you actually trying to do?

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

Hi, Tim. I installed my driver as a upper filter driver.
When I write a file to the device, I want to encrypt it, and when processing the read request, I decrypt the files on the device. I’ve found some examples based on wdm, but would like to write a wdf driver. Is it possible to somehow check when a write request comes, exactly, on a file record?
An example of processing a write request on wdm that I could find.
NTSTATUS
FilterWrite (
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)
{
PVOID Buffer, Buffer2;
LARGE_INTEGER ByteOffset;
ULONG Length, sector;
PDISK_CRYPT_EXTENSION ext = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
PMDL OriginalMdl, Mdl2;
#ifdef _DBG_TEST
DbgPrint(“FilterWrite\n”);
#endif

ByteOffset.QuadPart = irpStack->Parameters.Read.ByteOffset.QuadPart;
Length = irpStack->Parameters.Read.Length;

Buffer = MapUserBuffer (Irp);
Buffer2 = ExAllocatePool (NonPagedPool, Length);

CryptSectors (
&ext->Filter.CryptKey,
Buffer,
Buffer2,
irpStack->Parameters.Read.ByteOffset,
irpStack->Parameters.Read.Length >> 9,
TRUE);

OriginalMdl = Irp->MdlAddress;

MmBuildMdlForNonPagedPool (IoAllocateMdl (Buffer2, Length, FALSE, FALSE, Irp));

IoCopyCurrentIrpStackLocationToNext (Irp);

IoSetCompletionRoutine(
Irp,
FilterWriteCompletion,
OriginalMdl,
TRUE, TRUE, TRUE);

return IoCallDriver(ext->LowerDevice, Irp);
}

NTSTATUS
FilterWriteCompletion (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PMDL OriginalMdl = Context;
PVOID Buffer2;
#ifdef _DBG_TEST
DbgPrint(“FilterWriteCompletion\n”);
#endif
Buffer2 = MapUserBuffer (Irp);

IoFreeMdl (Irp->MdlAddress);
ExFreePool (Buffer2);

Irp->MdlAddress = OriginalMdl;

if (Irp->PendingReturned)
IoMarkIrpPending(Irp);

return STATUS_SUCCESS;
}

xxxxx@gmail.com wrote:

Hi, Tim. I installed my driver as a upper filter driver.

Upper filter to what?  It doesn’t help to know where you are filtering,
if we don’t know which device you are filtering.

When I write a file to the device, I want to encrypt it, and when processing the read request, I decrypt the files on the device.

But you never deal with files, at ANY level.  You deal with sectors, or
with parts of sectors.  Above the file system level, the user opens a
file handle, and then reads and writes portions of the file, possibly at
random.  Below the file system level, drivers deal with sectors
addressed by sector numbers, and you can’t tell whether the request is
inside a file or inside the file system’s bookkeeping tables.

If your encryption algorithm changes the size of the buffer, then this
whole approach is doomed.  To do that, you have to work above the file
system level, and you DO have to do whole files at a time.

If the input and output are the same size, then your approach can be
made to work, although there are many, many problems to overcome. How
will you handle a device being plugged in that is not encrypted?  How
will you know whether to decrypt or not?  And, if you operate below the
file system level, then your drive will appear as unformatted garbage to
any system that does not have your filter.

I’ve found some examples based on wdm, but would like to write a wdf driver. Is it possible to somehow check when a write request comes, exactly, on a file record?

Assuming you are filtering at the USB level, then no, there is no way. 
At the USB level, it’s all just reads and writes of sectors. The device
has no knowledge of file systems, or even whether a file system is
present or not.  You need to sit down with a whiteboard and figure out
where you need to filter, what requests you are going to see, and how
you will handle the various combinations of requests.

An example of processing a write request on wdm that I could find.

Unless there’s more code you aren’t showing us, that example has a
serious problem.  It allocates a new MDL for the new encrypted buffer,
but it never replaces the buffer pointer in the IRP.  The IRP gets
submitted with the user’s buffer.  Then, in the completion routine, you
fetch the user’s buffer and free it.  That’s a BSOD.


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