Encryption Filter Doesn't Work for Memory Mapped Files

Hello

I have created a simple encryption filter, it works fine for regular
I/O, but fails for memory mapped files. When opening text files with
notepad, which uses memory mapped files, I see encrypted content,
other programs that use regular I/O (Write) work fine.

How can I correct this behavior? Thanks,


Aram Hăvărneanu

On Sun, Sep 5, 2010 at 7:31 PM, Aram Hăvărneanu wrote:
> I have created a simple encryption filter, it works fine for regular
> I/O, but fails for memory mapped files. When opening text files with
> notepad, which uses memory mapped files, I see encrypted content,
> other programs that use regular I/O (Write) work fine.
>
> How can I correct this behavior? Thanks,

I think I only need to do crypto in the non-caching paths? I tried
FLTFL_OPERATION_REGISTRATION_SKIP_CACHED_IO in
FLT_OPERATION_REGISTRATION but it doesn’t seem to work.


Aram Hăvărneanu

On Sun, Sep 5, 2010 at 7:48 PM, Aram Hăvărneanu wrote:
> On Sun, Sep 5, 2010 at 7:31 PM, Aram Hăvărneanu wrote:
>> I have created a simple encryption filter, it works fine for regular
>> I/O, but fails for memory mapped files. When opening text files with
>> notepad, which uses memory mapped files, I see encrypted content,
>> other programs that use regular I/O (Write) work fine.
>>
>> How can I correct this behavior? Thanks,
>
> I think I only need to do crypto in the non-caching paths? I tried
> FLTFL_OPERATION_REGISTRATION_SKIP_CACHED_IO in
> FLT_OPERATION_REGISTRATION but it doesn’t seem to work.

Could it be that I decrypt the plain data from the cache? How do I
skip the caching paths if FLTFL_OPERATION_REGISTRATION_SKIP_CACHED_IO
doesn’t work?

Thanks,


Aram Hăvărneanu

On Sun, Sep 5, 2010 at 11:11 PM, Aram Hăvărneanu wrote:
> On Sun, Sep 5, 2010 at 7:48 PM, Aram Hăvărneanu wrote:
>> On Sun, Sep 5, 2010 at 7:31 PM, Aram Hăvărneanu wrote:
>>> I have created a simple encryption filter, it works fine for regular
>>> I/O, but fails for memory mapped files. When opening text files with
>>> notepad, which uses memory mapped files, I see encrypted content,
>>> other programs that use regular I/O (Write) work fine.
>>>
>>> How can I correct this behavior? Thanks,
>>
>> I think I only need to do crypto in the non-caching paths? I tried
>> FLTFL_OPERATION_REGISTRATION_SKIP_CACHED_IO in
>> FLT_OPERATION_REGISTRATION but it doesn’t seem to work.
>
> Could it be that I decrypt the plain data from the cache? How do I
> skip the caching paths if FLTFL_OPERATION_REGISTRATION_SKIP_CACHED_IO
> doesn’t work?

From the FAQ:

For example, a traditional mistake for an encryption filter is to trap
the IRP_MJ_WRITE where the IRP_NOCACHE bit is set (which catches both
user non-cached I/O as well as paging I/O) and, using the provided MDL
or user buffer, encrypt the data in-place. The risk here is that some
other thread will gain access to that memory in its encrypted state.
For example, if the file is memory mapped, the application will
observe the modified data, rather than the original, cleartext data.

That is the behavior I get, though I don’t encrypt in place. I replace
the user buffer (I started from SwapBuffers that does this correctly).


Aram Hăvărneanu

This is a real old question, I myself asked this few years back :),

To start with you need to encrypt/decrypt only in case of non-cached (and paging) path. change your read, write accordingly.

On Mon, Sep 6, 2010 at 4:59 PM, wrote:
> To start with you need to encrypt/decrypt only in case of non-cached (and paging) path. change your read, write accordingly.

I understand this, that’s why I specified
FLTFL_OPERATION_REGISTRATION_SKIP_CACHED_IO, but it doesn’t seem to be
enough. From my understanding, if I specify
FLTFL_OPERATION_REGISTRATION_SKIP_CACHED_IO then my filter callbacks
won’t get called for cached i/o. Is my understanding wrong? Do I need
to specify something else?

Thanks,


Aram Hăvărneanu

On Mon, Sep 6, 2010 at 5:17 PM, Aram Hăvărneanu wrote:
> On Mon, Sep 6, 2010 at 4:59 PM, wrote:
>> To start with you need to encrypt/decrypt only in case of non-cached (and paging) path. change your read, write accordingly.
>
> I understand this, that’s why I specified
> FLTFL_OPERATION_REGISTRATION_SKIP_CACHED_IO, but it doesn’t seem to be
> enough. From my understanding, if I specify
> FLTFL_OPERATION_REGISTRATION_SKIP_CACHED_IO then my filter callbacks
> won’t get called for cached i/o. Is my understanding wrong? Do I need
> to specify something else?

More precisely, if I use FLTFL_OPERATION_REGISTRATION_SKIP_CACHED_IO,
then I get NO encryption at all.


Aram Hăvărneanu

you are using this flag for both read and write IRPs? As per docs it should work but I did not tried it. Instead I checked the flags from call back data.

On Tue, Sep 7, 2010 at 7:45 AM, wrote:
> you are using this flag for both read and write IRPs? As per docs it should work but I did not tried it. Instead I checked the flags from call back data.

I am using the flags for both read and write. I will try checking the
flags from the call back data.

Could it be that read-ahead is caching my test files before I attach
the filter so that after I attach the filter, I only get caching I/O?


Aram Hăvărneanu

>>Could it be that read-ahead is caching my test files before I attach the filter so that after I attach the filter, I only get caching I/O?

IF the file is being read before your filter is loaded than yes, prefetcher could also play its part here. A simple test is to use dbgprint or step into debugger and verify whether you are getting a (non-cached/paging) read operation on that file or not? This is the first thing I would verify.

On Tue, Sep 7, 2010 at 12:39 PM, wrote:
>>>Could it be that read-ahead is caching my test files before I attach the filter so that after I attach the filter, I only get caching I/O?
> IF the file is being read before your filter is loaded than yes, prefetcher could also play its part here. A simple test is to use dbgprint or step into debugger and verify whether you are getting a (non-cached/paging) read operation on that file or not?

I am getting non-cached I/O from read-ahead. That is the good news.
It’s also good news that I determined why if I set
FLTFL_OPERATION_REGISTRATION_SKIP_CACHED_IO the driver appears not to
work. I am doing encryption only for some files and
FltGetFileNameInformation() fails with
STATUS_FLT_INVALID_NAME_REQUEST. Why can’t I get the name for
non-cached I/O? Is there an alternative?

Thanks,


Aram Hăvărneanu

On Tue, Sep 7, 2010 at 6:14 PM, Aram Hăvărneanu wrote:
> I am doing encryption only for some files and
> FltGetFileNameInformation() fails with
> STATUS_FLT_INVALID_NAME_REQUEST. Why can’t I get the name for
> non-cached I/O?

I found the answer:

><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><

A minifilter can call FltGetFileNameInformation() at any point during
its IO processing when it is executing an IRQL less than DPC. If the
minifilter is requesting to query the name at a time when it is
possible for the name query to cause the system to deadlock (e.g.,
while processing paging IO), the call will fail if the name is not
found in the cache or the caller requested to only query the file
system.

A minifilter can use FltGetFileNameInformationUnsafe() to query a name
for a file object if it does not have a callback data to describe the
current operation targeting this file object and the filter knows that
this is a safe time to potentially query the file system to get a
name. This routine cannot detect that a file system query could
potentially deadlock the system and return a failure status as
FltGetFileNameInformation() can.

><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><

I think it’s safe to use FltGetFileNameInformationUnsafe(). I’m using
that function and my filter performs just fine with regular I/O and
memory mapped I/O. For reference, I’m processing only non cached I/O
via FLTFL_OPERATION_REGISTRATION_SKIP_CACHED_IO.

Thanks for help.


Aram Hăvărneanu

FltGetFileNameInformationUnsafe does not look *safe* to me :slight_smile: (obvious from name in fact), read the remark section and it should be clear.

You can actually call it only in create and than store it, later in read/write you can referred to the stored value. Will actually save you from overhead.

IF you have not looked yet, than take a look at contexts.

On 9/7/2010 9:35 AM, Aram Hăvărneanu wrote:

I think it’s safe to use FltGetFileNameInformationUnsafe(). I’m using
that function and my filter performs just fine with regular I/O and
memory mapped I/O. For reference, I’m processing only non cached I/O
via FLTFL_OPERATION_REGISTRATION_SKIP_CACHED_IO.

Thanks for help.

I definitely recommend obtaining the name information during post-crate
processing and storing it in a stream context. This way you are not
having to obtain the name information on every IO, you can simply
retrieve the stream context and you will have the name.

Pete


Kernel Drivers
Windows File System and Device Driver Consulting
www.KernelDrivers.com
866.263.9295

On Tue, Sep 7, 2010 at 7:29 PM, wrote:
> FltGetFileNameInformationUnsafe does not look safe to me :slight_smile: (obvious from name in fact), read the remark section and it should be clear.
>
> You can actually call it only in create and than store it, later in read/write you can referred to the stored value. Will actually save you from overhead.
>
> IF you have not looked yet, than take a look at contexts.

On Tue, Sep 7, 2010 at 7:29 PM, Peter Scott wrote:
> I definitely recommend obtaining the name information during post-crate
> processing and storing it in a stream context. This way you are not having
> to obtain the name information on every IO, you can simply retrieve the
> stream context and you will have the name.

Oh, I am very aware of this facts. However, I was under the impression
that file contexts require at least Windows Vista? I think stram
context are what I want though.


Aram Hăvărneanu

On 9/7/2010 1:18 PM, Aram Hăvărneanu wrote:

Oh, I am very aware of this facts. However, I was under the impression
that file contexts require at least Windows Vista? I think stram
context are what I want though.

Stream contexts, FLT_STREAM_CONTEXT, are supported on all platforms
where Filter Manager is supported which includes 2000 sp4 + SRP, XP sp2
and above, 2K3 sp1, Vista and above. FLT_FILE_CONTEXT and
FLT_TRANSACTION_CONTEXT types are the ones which are only supported on
Vista and above.

Pete


Kernel Drivers
Windows File System and Device Driver Consulting
www.KernelDrivers.com
866.263.9295

On Tue, Sep 7, 2010 at 10:41 PM, Peter Scott wrote:
> Stream contexts, FLT_STREAM_CONTEXT, are supported on all platforms where
> Filter Manager is supported which includes 2000 sp4 + SRP, XP sp2 and above,
> 2K3 sp1, Vista and above. FLT_FILE_CONTEXT and FLT_TRANSACTION_CONTEXT types
> are the ones which are only supported on Vista and above.

I have updated my filter to use stream context. I check what I need
only in the post-create path, and then save the information in the
context. It works perfectly and the performance of my filter is great.
No problems with Driver Verifier either. Prefast is clean, too bad SDV
doesn’t work for file system minifilters.


Aram Hăvărneanu