File System Redirector

Hello,

I am trying to do at file system level, what subst.exe does. From user
space point of view, I have 2 drive letters, let’s call them C: D:. I
wish that every file access that references D:, to go to another
directory on the C drive, like C:\foo.

D:\ -> C:\foo\
D:\bar -> C:\foo\bar

I wish to log every file I/O to D, and not log file access that is
done through C:\foo. When I mean `not log’ I mean that I wish that my
logging filters won’t run at all on the real volume, not that there’s
some check in the filter that tells it to log only a specific
directory. That is, I wish my filters to reside only on D, and somehow
file I/O to be ultimately redirected to C:\foo.

I create a virtual volume (RamDisk) that gets a new drive letter and I
format it as NTFS. It’s not used directly for file system operations,
I just create it so I can have something my filter driver can attach
to. I wish to implement a file system minifilter that does the
operations described above. From my understanding this can be done in
3 ways:

  1. Filter IRP_MJ_CREATE, IRP_MJ_READ, IRP_MJ_WRITE and associated
    stuff, do the file I/O on the real target myself in the filter, copy
    data to necessary buffers and complete the I/O in the filter. This is
    very hard to do right, a lot of code to write, security is very
    complicated (you can do in your filter anything, while you should do
    only what the caller could do). I don’t think I’ll do this, I post it
    here just for reference.

  2. Filter only IRP_MJ_CREATE, modify the target paths and return
    STATUS_REPARSE. This is easier to do and there is no need to think
    about security (it just works right). However, the problem is that
    since I return in the filter, and since I don’t return the real stuff,
    my logging filters attached to the virtual volume will either see
    bogus stuff in the completion routine if the redirect filter is below
    the logging filter, either nothing if it’s above the filter. This is
    not good.

  3. Filter IRP_MJ_CREATE, IRP_MJ_READ, IRP_MJ_WRITE and associated
    stuff, the change FLT_IO_PARAMETER_BLOCK::TargetFileObject and
    FLT_IO_PARAMETER_BLOCK::TargetInstance. I don’t understand this yet.
    It seems like I need another filter (same filter?) on the target
    volume, which kind of defies the point of doing this, plus I am not
    sure how it will interact with the logging stuff.

What (else) do you recommend?

Thanks,


Aram Hăvărneanu

On Wed, Aug 25, 2010 at 10:11 AM, Aram Hăvărneanu wrote:
> I wish that every file access that references D:, to go to another
> directory on the C drive, like C:\foo.
>
> […]
>
> 3) Filter IRP_MJ_CREATE, IRP_MJ_READ, IRP_MJ_WRITE and associated
> stuff, the change FLT_IO_PARAMETER_BLOCK::TargetFileObject and
> FLT_IO_PARAMETER_BLOCK::TargetInstance. I don’t understand this yet.
> It seems like I need another filter (same filter?) on the target
> volume, which kind of defies the point of doing this, plus I am not
> sure how it will interact with the logging stuff.

Actually, from my understanding, if I wish to go this path, I think I
only need to filter IRP_MJ_CREATE. Is
FLT_IO_PARAMETER_BLOCK::TargetFileObject relevant in other operations
except IRP_MJ_CREATE? I can’t find anything in the docs, but that was
my conclusion after reading list archives. Please correct me if I am
wrong.

The docs state when I can change TargetInstance. It seems my filter
needs to reside on the target volume too (obviously I can configure it
differently for PassThrough operation, so it doesn’t do anything but
serve as a proxy). What I don’t understand is who will receive the
completion notification. If I have the following design (simplified
for clarity):

D -> [logging filter] -> [redirect filter D] -> [NTFS] -> [Bogus Volume]
C -> [redirect filter C] -> [NTFS] -> [Real Volume]

Where [redirect filter D] does the I/O redirection to [redirect filter C].

1) Will [redirect filter D] receive completion notification or
(only) [redirect filter C]?
2) Will [logging filter] receive completion notifcation (after I/O
has been redirected)?

Hope you will clarify my doubts regarding this design. If everything
works as I understand it now, it should be easy to implement.

Thanks,


Aram Hăvărneanu

Hmm. No suggestions?

On Wed, Aug 25, 2010 at 12:33 PM, Aram Hăvărneanu wrote:
> On Wed, Aug 25, 2010 at 10:11 AM, Aram Hăvărneanu wrote:
>> I wish that every file access that references D:, to go to another
>> directory on the C drive, like C:\foo.
>>
>> […]
>>
>> 3) Filter IRP_MJ_CREATE, IRP_MJ_READ, IRP_MJ_WRITE and associated
>> stuff, the change FLT_IO_PARAMETER_BLOCK::TargetFileObject and
>> FLT_IO_PARAMETER_BLOCK::TargetInstance. I don’t understand this yet.
>> It seems like I need another filter (same filter?) on the target
>> volume, which kind of defies the point of doing this, plus I am not
>> sure how it will interact with the logging stuff.
>
> Actually, from my understanding, if I wish to go this path, I think I
> only need to filter IRP_MJ_CREATE. Is
> FLT_IO_PARAMETER_BLOCK::TargetFileObject relevant in other operations
> except IRP_MJ_CREATE? I can’t find anything in the docs, but that was
> my conclusion after reading list archives. Please correct me if I am
> wrong.
>
> The docs state when I can change TargetInstance. It seems my filter
> needs to reside on the target volume too (obviously I can configure it
> differently for PassThrough operation, so it doesn’t do anything but
> serve as a proxy). What I don’t understand is who will receive the
> completion notification. If I have the following design (simplified
> for clarity):
>
> D -> [logging filter] -> [redirect filter D] -> [NTFS] -> [Bogus Volume]
> C -> [redirect filter C] -> [NTFS] -> [Real Volume]
>
> Where [redirect filter D] does the I/O redirection to [redirect filter C].
>
> 1) Will [redirect filter D] receive completion notification or
> (only) [redirect filter C]?
> 2) Will [logging filter] receive completion notifcation (after I/O
> has been redirected)?
>
> Hope you will clarify my doubts regarding this design. If everything
> works as I understand it now, it should be easy to implement.
>
> Thanks,
>
> –
> Aram Hăvărneanu
>


Aram Hăvărneanu

I haven’t looked at this in a while, but from what I remember, your filter wouldn’t see the request twice. Only the instance on volume D would see it and then the operation would be send to minifilters below the instance you have on volume C. The instance on volume D should receive the completion notification (basically your instance on volume C is used as a reference point on where to insert the IO in the other stack). However, you specifically stated that one of the requirements of your design is to not have a minfilter attached to volume C at all…

Now, again, my memory is a bit sketchy on the subject so please try and validate this.

Also, IIRC, if you redirect IRP_MJ_CREATE in this manner then subsequent operations on that FILE_OBJECT will be automatically redirected by the IO manager. This might not be what you want, as it is basically the same as a STATUS_REPARSE.

Another problem with this approach is that you might run out of IO_STACK_LOCATIONs in the IRP since you would be effectively be taking an IRP from one device stack and sending it to another.

Looking at your original mail, your goal seems to be "…trying to do at file system level, what subst.exe does. " and you have the additional requirement that "my logging filters won’t run at all on the real volume ". I don’t have a better solution than to redirect each IO operation (redirecting IRP_MJ_CREATE either with STATUS_REPARSE or with TargetInstance will send subsequent operations directly to the target volume (at least as far as I remember)), which I’m afraid is the more complicated approach that you’ve already suggested in your original mail.

Perhaps you could explain what it is you are trying to do at a higher level (i.e. “log access to a file for security purposes” or “keep track of all modifications to files for back-up purposes”).

Thanks,
Alex.

On Fri, Aug 27, 2010 at 7:08 PM, Alex Carp wrote:
> Looking at your original mail, your goal seems to be "…trying to do at file system level, what subst.exe does. " and you have the additional requirement that "my logging filters won’t run at all on the real volume ". I don’t have a better solution than to redirect each IO operation (redirecting IRP_MJ_CREATE either with STATUS_REPARSE or with TargetInstance will send subsequent operations directly to the target volume (at least as far as I remember)), which I’m afraid is the more complicated approach that you’ve already suggested in your original mail.

What is the minimum set of I/O operations I need to support?

I obviously need IRP_MJ_CREATE for opening files, IRP_MJ_READ and
IRP_MJ_WRITE for reading and writing files, and
IRP_MJ_DIRECTORY_CONTROL for directory listings. Is everything else
optional?

Isn’t it possible to generate IRPs directly in my driver (as opposed
to the I/O manager) by creating a new IRP, copying the old IRP
(obviously changing what’s relevant) and then letting it go instead of
doing file I/O the `classic’ way (with FltCreateFile)? I am not sure
how FastIO will interact with this (maybe I can disable FastIO?).


Aram Hăvărneanu