Hi all,
I'm still trying to understand how the filesytem is working under XP.
As a learning exercise I've written a small driver which locates, and hooks
into the \FileSystem\FastFat driver - all I'm doing is replacing the
function
pointer in the FastFat dispatch-table with a pointer to a function in my
driver, which
looks like this:
NTSTATUS NewDispatchRead(PDEVICE_OBJECT DeviceObj, PIRP Irp)
{
NTSTATUS status;
PMDL Mdl = Irp->MdlAddress;
PVOID Buffer;
/* step1: lock down IRP here and access memory */
if(Mdl != 0) Buffer = MmGetMdlForNonPagedPool(Mdl, ...);
status = OldDispatchRead(DeviceObj, Irp);
/* step2: lock down IRP and access memory */
if(Mdl != 0) Buffer = MmGetMdlForNonPagedPool(Mdl, ...);
return status;
}
OK, I don't want to get into a debate as to whether this is good practise
or not (I know it isn't) - this is for experimental purposes only.
So what I'm observing is the following:
the "original" dispatch routine for FastFat IRP_MJ_READ generally
returns STATUS_SUCCESS rather than STATUS_PENDING. This presumably
means that the original handler has (during it's processing) set up it's
own completion routine, called whatever the next driver might be with the
IRP,
and then waited for the completion routine to execute (using an event and
KeWaitForxxx)
before finally returning "yes, the read is complete"
Does this diagnositic sound correct?
So my conclusion from this is that the buffer described by Irp->MdlAddress
should contain valid data when the OldDispatchRead function returns
STATUS_SUCCESS,
right?
But....if you look at the code I posted, I have two steps (1+2). At step1, I
can
see the contents of the buffer no problems (using ProbeForRead etc). But
this is
not useful because the buffer hasn't been filled up by the read operation
yet. What
I really want to do is access the buffer contents at step2 (after the
OldDispatchRead)
but the memory range the Mdl references seems to be invalid at this point -
so my second conclusion is that the normal FastFat IRP_MJ_READ function
completes the read operation and then frees the memory referenced by the Mdl
in the original IRP. Does this sound correct?
So my next goal is to somehow access the buffer the Mdl references *after*
the
original dispatch routine has returned.
My current "hack" is to do this at step 1:
Mdl = IoAllocateMdl(IoCurrentStack->UserBuffer);
MmBuildMdlForNonPagedPool(Mdl);
MmMapLockedPages(Mdl, KernelMode);
/* call the original dispatch routine */
and then this at step 2:
PVOID Buffer = MmGetSystemAddressForMdlSafe(Mdl, LowPriority);
MmUnmapLockedPages(Buffer, Mdl);
IoFreeMdl(Mdl);
I can now access the Buffer and see the results of the read operation!!!
But I'm pretty wary of why this is even possible, or even legal, as I'm
assuming
that the original memory range has been freed, and the Mdl I build myself
points to "dirty" pages that by chance contain valid data . So, could
someone
please explain what the effect is of locking down the buffer in this manner,
why it is
unsafe, any better methods to achieve what I want...?
Note: FileSystem filter driver is too much for my needs, this is just a
quick
one-off experiment, but I'd like to know what's really happening here.
Cheers,
James