Data modification in filter driver

I am writing a driver that would allow encryption/protection of specific files based on their name and/or content. I have already worked in anti-virus software development, so legacy-style attaching is not a problem to me, however I never needed to modify data stream to/from the lower driver. Two problems arose during my work.

  1. Modifying read data
    I managed to allocate a new MDL, set UserBuffer and so on to cope with paging/non-cached IRP_MJ_WRITES. IRP_MJ_READ should be easier, because I can decrypt in-place, but some weird thing occurred.

I set a completion routine at IRP_MJ_READ and in the completion routine I have the following code:

void FsFilterDevice::ReadComplete(IN PIRP Irp, PVOID _context)
{
__try
{
void *Buffer=0;
if (Irp->MdlAddress)
{
DbgPrint(“%s getting address for MDL %p\n”, FUNCTION, Irp->MdlAddress);
Buffer=MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
}
else
{
Buffer=Irp->UserBuffer;
}

ULONG_PTR Length=Irp->IoStatus.Information;

DbgPrint(“%s probing for write %p %i\n”, FUNCTION, Buffer, Length);
ProbeForWrite(Buffer, Length, 1);
DbgPrint("%s modifying data\n, FUNCTION);
// decryption goes here
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
DbgPrint(“Exception: %08X\n”, GetExceptionCode());
}

And I never see the “modifying data” on the debugger. What I get is:

FsFilterDevice::ReadComplete getting address for MDL 82396C20
FsFilterDevice::ReadComplete probing for write F8C18000 13
Exception: C0000005

It is pretty strange, because MmGetSystemAddressForMdlSafe seems to return some non-zero address and does not raise any exception (as xxxSafe functions usually do on error). The buffer does not exceed one page, so it seems that the page address returned by MmGetSystemAddressForMdlSafe is invalid (probing for read fails as well, so it is not due to protection).
I am quite sure that some (most?) of you have a solution for this.

  1. The system file cache… Can I (and how) make some programs see encrypted and some see plain file? For example, when I decide to logoff a user, programs that have handle to an open file should see it decrypted and newly open files should be visible in an undecrypted form.

I know this questions are probably pretty lame (especially 1st one), but I am new to data modification and hope you will help me.

> if (Irp->MdlAddress)

{
}
else
{
Buffer=Irp->UserBuffer;
}
ProbeForWrite(Buffer, Length, 1);

Don’t probe for write the buffer returned by MmGetSystemAddressForMdl/Safe. You can attempt MmProbeAndLockPages only.

  1. The system file cache… Can I (and how) make some programs see encrypted and some see plain file? For example, when I decide to logoff a user, programs that have handle to an open file should see it decrypted and newly open files should be visible in an undecrypted form.

Take over cache management for the particular file.
This is far from easy, whatever way you try to do it.


Kind regards, Dejan (MSN support: xxxxx@alfasp.com)
http://www.alfasp.com
File system audit, security and encryption kits.

Thanks a lot!

  1. I just didn’t notice that ProbeForXxx are only for user mode buffers. Everything seems to work after just putting the probe only when Irp->UserBuffer is used.

  2. I will deny access to the encrypted file then (for now, at least). Anyway, the point is for the non-authorized user NOT to read the file contents. After storing the file on removable media and moving to another machine the file will remain encrypted anyway.

Is there a simple way to reset file cache for a given file?

This has been answered many times, the answer is NO! You will have a ton of
work to do to handle this case.


Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr
Remove StopSpam to reply

<mike_phsx> wrote in message news:xxxxx@ntfsd…
> Is there a simple way to reset file cache for a given file?
>
></mike_phsx>

What about re-reading the file with IRP_NOCACHE flag? It should skip the cache and issue proper read request to the file system. Will the data also skip cache on “its way back” to the requestor?

Go buy a copy of Rajeev Nagar’s book and start reading, bottom line is that
schemes are not going to cut it. You are going to have to manage the
caching yourself to be safe which is a lot of work.


Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr
Remove StopSpam to reply

<mike_phsx> wrote in message news:xxxxx@ntfsd…
> What about re-reading the file with IRP_NOCACHE flag? It should skip the
> cache and issue proper read request to the file system. Will the data also
> skip cache on “its way back” to the requestor?
>
>
></mike_phsx>

The answer turned out to be CcPurgeCacheSection, if I only want to reset the cache.
Now the only problem is to determine, whether the cache for the file being opened should be purged or not.

This has been answered many times, the answer is NO! You will have a ton of
work to do to handle this case.

> Is there a simple way to reset file cache for a given file?

Sorry, this does not always work you will get FALSE returned for many cases
at which point you haven’t purged the cache. Worse yet it is possible at
times to purge valid updates to the file, so you could create data
corruption. As Dejan and I have been saying you have to take over the
cache management for the file completely.


Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr
Remove StopSpam to reply

<mike_phsx> wrote in message news:xxxxx@ntfsd…
> The answer turned out to be CcPurgeCacheSection, if I only want to reset
> the cache.
> Now the only problem is to determine, whether the cache for the file being
> opened should be purged or not.
>
>> This has been answered many times, the answer is NO! You will have a ton
>> of
>> work to do to handle this case.
>
>>> Is there a simple way to reset file cache for a given file?
>
>
></mike_phsx>

Yes, reboot the system.

<mike_phsx> wrote in message news:xxxxx@ntfsd…
> Is there a simple way to reset file cache for a given file?
>
></mike_phsx>

It is possible to force cache to flush, so I think the problem is mainly due to these somewhat strange failures of CcPurge… and CcFlush… Some experiments show that when I do the flush/purge on creation of the first handle to the file, it seems to succeed every time. When the file remains open - well, this case is so hard that I will deny access to the file or postpone switching the status of encryption until flush/purge pair succeeds. While enabling the decryption engine it is unlikely that any program will keep open an encrypted file (unless programmer f…ed up and didn’t close the file after seing its unrecognizable content).

Or maybe there are some silent failures of the flush/purge functions?

Worse yet it is possible at times to purge valid updates to the file

Well you have now reached the point where you’ve done enough testing to
convince yourself you can, but not enough to realize how often you will be
denying access. I’ve had multiple queries from firms that did it your way,
found that customers screamed because they could not get at their data
without a reboot, and wanted a little help. Of course they always start
with “We spent X months getting a really good filter, we just need a little
help on a minor problem,…” they seem to get upset when the solution
involves rewriting large portions of the code, and adding a ton of support.


Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr
Remove StopSpam to reply

<mike_phsx> wrote in message news:xxxxx@ntfsd…
> It is possible to force cache to flush, so I think the problem is mainly
> due to these somewhat strange failures of CcPurge… and CcFlush… Some
> experiments show that when I do the flush/purge on creation of the first
> handle to the file, it seems to succeed every time. When the file remains
> open - well, this case is so hard that I will deny access to the file or
> postpone switching the status of encryption until flush/purge pair
> succeeds. While enabling the decryption engine it is unlikely that any
> program will keep open an encrypted file (unless programmer f…ed up and
> didn’t close the file after seing its unrecognizable content).
>
> Or maybe there are some silent failures of the flush/purge functions?
>
>> Worse yet it is possible at times to purge valid updates to the file
>
></mike_phsx>

> so I think the problem is mainly due to these somewhat strange failures of CcPurge…

Actually there is nothing strange in failures of CcPurge…/MmPurge… functions. This is a feature of Windows. Purging always fails if there is at least one virtual page, excepting Cache Manager’s pages, backed by this file. The reason is lacking of reverse mapping in Windows. You can’t circumvent this.


Slava Imameyev , xxxxx@hotmail.com

> What about re-reading the file with IRP_NOCACHE flag? It should skip the cache

and issue proper read request to the file system.

It does not necessarily work this way - it is up to FSD to decide how to handle things. As it has been discussed quite a few times on this forum, IRP_NOCACHE flag alone cannot guarantee that Cache Manager does not get involved - only IRP_PAGING_IO flag can guarantee that, and you just cannot send IRPs with IRP_PAGING_IO flag on your own initiative.

Anton Bassov

Anton,

sorry to hijack the thread and maybe you want to reply off the list ...

[...] and you just cannot send IRPs with IRP_PAGING_IO flag on your own
initiative.

why exactly can't I send my own IRPs with this flag set? Or is "can't" just a way to say "mustn't"?

Cheers,

Oliver


May the source be with you, stranger :wink:

ICQ: #281645
URL: http://assarbad.info | http://windirstat.info | http://blog.assarbad.info

Oliver,

it's nice to talk to you but I'm afraid I'm other Anton :slight_smile: I was not asking
THIS PARTICULAR question :slight_smile:

Thanks!

Anton

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Oliver Schneider
Sent: Wednesday, October 03, 2007 1:35 AM
To: Windows File Systems Devs Interest List
Subject: Re: RE:[ntfsd] Data modification in filter driver

Anton,

sorry to hijack the thread and maybe you want to reply off the list ...

[...] and you just cannot send IRPs with IRP_PAGING_IO flag on your own
initiative.

why exactly can't I send my own IRPs with this flag set? Or is "can't" just
a way to say "mustn't"?

Cheers,

Oliver


May the source be with you, stranger :wink:

ICQ: #281645
URL: http://assarbad.info | http://windirstat.info |
http://blog.assarbad.info


NTFSD is sponsored by OSR

For our schedule debugging and file system seminars
(including our new fs mini-filter seminar) visit:

You are currently subscribed to ntfsd as: xxxxx@rocketdivision.com
To unsubscribe send a blank email to xxxxx@lists.osr.com

> why exactly can’t I send my own IRPs with this flag set? Or is “can’t” just a way to say “mustn’t”?

IRPs with IRP_PAGING_IO flag are sent by those components that do paging IO (i.e. Memory Manager and Cache Manager), with TopLevelIrp indicating who the request originator is, so that FSD
knows how to deal with locking upon the particular request on paging IO path. Therefore, if you want to send IRPs with IRP_PAGING_IO flag, you have to know a bit more than you do - otherwise, be ready to get a “surprize”…

Anton Bassov

Sorry for intrusion in this personal question,

why exactly can’t I send my own IRPs with this flag set?

You can, but this is discouraged by Microsoft. There is nothing that can
prevent you from doing this. Creat an Mdl, initialize an IRP( set MdlAdress
to the Mdl and UserBuffer as MmGetMdlVirtualAddress( Mdl ) ) , send the IRP,
unlock and free the Mdl in a completion routine, set MdlAddress and
UserBuffer to NULL. That is all.

Or is “can’t” just a way to say “mustn’t”?

Better to say “should not”.


Slava Imameyev, xxxxx@hotmail.com

“Oliver Schneider” wrote in message
news:xxxxx@ntfsd…
> Anton,
>
> sorry to hijack the thread and maybe you want to reply off the list …
>
>> […] and you just cannot send IRPs with IRP_PAGING_IO flag on your own
>> initiative.
>
> why exactly can’t I send my own IRPs with this flag set? Or is “can’t”
> just a way to say “mustn’t”?
>
>
> Cheers,
>
> Oliver
> –
> ---------------------------------------------------
> May the source be with you, stranger :wink:
>
> ICQ: #281645
> URL: http://assarbad.info | http://windirstat.info |
> http://blog.assarbad.info
>
>

>The page frame containing data shared by two or more processes are described by the prototype page table.

To put it more bluntly - Proto PTE is created whenever a page frame( physical page ) can be shared( i.e. only potentially ), even if there is no any process which has any virtual page pointing to this frame. For example, creating a file mapping is enough to create a Proto PTE, so when the real virtual to physical mapping is established by the page fault handler the page frame will point to the Proto PTE.


Slava Imameyev, xxxxx@hotmail.com

“ganesh pashupathi” wrote in message news:xxxxx@ntfsd…
Hi Michal,

The NT VMM divides the RAM into page frames each frame with size 4096 bytes. For each page frame there is an entry in the page frame database. The info stored in each of the the database record contains attributes like the page modified bit, physical address of the page frame, back pointer to page table entry or prototype page table entry [explained below] etc.

A page frame is identified by page table entry in the page table. The page frame containing data shared by two or more processes are described by the prototype page table.

In the non-sharing case the page frame database entry contains the back pointer to the page table entry. In this case when user want to purge the page the VMM marks the page frame database entry as invalid and also marks the page table entry as invalid.

In the sharing case the back pointer points to the prototype page table and hence the VMM does not have a way to finding the page table entries refering to the page. Hence purge will not work here.

This i nicely explained in the Rajeev Nagar book.

~ganesh

On Wed, 03 Oct 2007 xxxxx@fromru.com wrote :
> > so I think the problem is mainly due to these somewhat strange failures of CcPurge…
>
>Actually there is nothing strange in failures of CcPurge…/MmPurge… functions. This is a feature of Windows. Purging always fails if there is at least one virtual page, excepting Cache Manager’s pages, backed by this file. The reason is lacking of reverse mapping in Windows. You can’t circumvent this.
>
>----------
>Slava Imameyev , xxxxx@hotmail.com
>
>—
>NTFSD is sponsored by OSR
>
>For our schedule debugging and file system seminars
>(including our new fs mini-filter seminar) visit:
>http://www.osr.com/seminars
>
>You are currently subscribed to ntfsd as: xxxxx@rediffmail.com
>To unsubscribe send a blank email to xxxxx@lists.osr.com

> There is nothing that can prevent you from doing this. Creat an Mdl, initialize an IRP

( set MdlAdress to the Mdl and UserBuffer as MmGetMdlVirtualAddress( Mdl ) ) , send the IRP,
unlock and free the Mdl in a completion routine, set MdlAddress and UserBuffer to NULL.
That is all.

What about TopLevelIrp??? Once paging IO requests are supposed to be sent only by Cache Manager and Memory Manager, FSD may get “surprized” if TopLevelIrp on paging IO path is NULL. Under these circumstances, bugchecking “just in case” is not that unreasonable move on FSD’s behalf…

Therefore, steps that you have described don’t seem to be sufficient - instead, you have to emulate
top-level component’s request properly, i.e. to make FSD believe that a paging IO request has been originated by the Cache Manager or by Memory Manager…

Anton Bassov