On-the-fly encryption/decryption driver workflow

Seeing so many posts about on-the-fly encryption/decryption filter driver
workflow. I can generalize certain problems that people keep on asking
for:

  1. Which form of data should be kept in cache; encrypted or unencrypted ?
  2. How to deal with memory mapped data (e.g. notepad) ?
  3. How to deal with lazy write ?
  4. Incompatibility with other drivers (probably anti-virus applications),
    is this due to programming bugs or design issues ?

Of course, there is assumption that we should know how to create your own
IRPs.

Would there be any experts are so generous to write the workflow of a
feasible (commerical) encryption filter driver to let the audiences here
to have a better understanding.

Thanks & Regards,

– Philip

>> Seeing so many posts about on-the-fly encryption/decryption filter driver

> workflow.

The actual workflow is something better to be left for the actual
implementation, for its highly dependant
bu design. There are more than one way to design such a file system filter
driver, some very simple,
some very complex. Also the design will impact on many practical solutions
and requirments during
implementation.

> If you have some links, docs or a piece of advise, you’re always welcome
:wink:

Unfortunately, there are no docs , or links or samples or whatever on this
subject.

Since I have nothing better to do in this morning, lemme try to summarize
some questions,
if I make any mistakes , feel free to point them out.

1.How do I identify paging IO ? What are the sources of paging IO ? How do
IRP_PAGING_IO flag modify completion behaviour ? Why cant I
modify the data in the original buffers for a IRP_MJ_WRITE paging IO
operation ? What about an IRP_MJ_READ paging IO ? Can I query the
file system for (your advertising place here) during a paging IO operation?
Why the hell do I see IRP_NOCACHE IO for my cached files ?

Paging IO can be identified by looking at Irp->Flags, for IRP_NOCACHE
and IRP_PAGING_IO flags set. Synchronous paging IO
requests also have IRP_SYNCHRONOUS_PAGING_IO set. The IRP_NOCACHE flag
simply tells the file system that the request
should NOT be satisfied from looking up data in system cache. IRP_PAGING_IO
has a dual role. First, it tells file system that the
request is paging IO. While normal IO is considered illegal on a file object
for which the file system received a IRP_MJ_CLEANUP
operation (Handle count for that file object reached 0), paging IO is. An
important thing to remember, should you build your
own IRPs in the paging IO path. Second it will drasticly modify the IO
completion behaviour. More on this later.

Files which are likely to be subject to paging IO requests:

System paging files.
Any file which is currently used as memory mapped file. This include
executable images, and all cached files. The Cc
manager uses section objects and mapped views to implement caching on file
streams.
Hibernation files

Paging files are easily identified in a filter driver at IRP_MJ_CREATE time
by looking in IrpSp->Flags for
SL_OPEN_PAGING_FILE set. This will instruct the file system to allocate all
in memory representation of the file
stream from nonpaged memory pool. This is an important issue, because the
system cannot afford a recursive page
fault in paging IO path for PAGING files. For a file system filter driver,
since usually paging file path
is the same as the genral paging IO path, this means that none of the
routines which are in paging IO path
can be pagable.

Note that hibernation files are also created as paging files. In Windows XP+
one can differentiate between a paging
file and a hibernation file by using FsRtlIsPagingFile() routine.

Sources of paging IO are:

IRP_MJ_WRITE:
The modified page writer and mapped writer threads –> uses
asynchronous write paging IO
flags set in Irp IRP_NO_CACHE| IRP_PAGING_IO

The lazy writer component of Cc manager –> uses synchronous write
paging IO
flags set in Irp IRP_NO_CACHE| IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO

IRP_MJ_READ:

A inpage operation on behalf of Mm, as the result of a page fault. ->
uses synchronous read
flags set in IRP: IRP_NOCACHE| IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO

The read ahead component of Cc manager: it will bring memory in by
touching the pages subject to
inpage. If the memory is not present, a page fault will occur. The Mm will
kick in, briniging desired pages in memory
from secondary storage.

Non- Mm/Cc requests, such as retrieving a crash dump from the main
system pagefile.

IRP_MJ_SET_INFORMATION / IRP_MJ_QUERY_INFORMATION === set / query size

It is important to note that IRP_PAGING_IO flag will change the behaviour of
IO completion. The significant
changes are the folowing(important to keep in mind if you roll your own
paging IO IRPs):

  1. Normally , MDLs associated with a IRP are freed during IoCompletion
    processing. This is not true
    for paging IO. Usually those MDL are owned by the Mm , and not by Io manager
    as usual, so they are left
    there for the Mm to deal with the.

  2. for a synchronous paging IO the completion will copy the operation status
    into the callers
    IO_STATUS_BLOCK, signal the event on which the caller blocks, and free the
    IRP. For an asynchronous paging
    IO an APC is delivered to the thread which requested the IO operation.

For write paging IO operation, one must not use the original MDL and buffer
to encrypt / change the data in place.
By doing so you will make imeddiately any changes visible in system cache,
or general system memory. A
page which is in transition can be reclaimed by a process and added to the
process working set. This will cause
inconsistent information. If you dont want your changes to be visible
imediatley, and usually you dont want, you must
use some kind of buffering. In the event you use roll your own IRP for this
purpouse, remember that the current
request can be for a a file object which already received a IRP_MJ_CLEANUP.
So build your IRP acordingly.

In the event you reuse the original Irp, and replace Irp->MdlAddress with
your own MDL, describing your buffer,
remember to always update the Irp->UserBuffer using
MmGetMdlVirtualAddress(). Upon completion, restore original
values in IRP.

For read paging IO operations, you can, however, read the data into the
original provided buffer, and decrypt
in place. It is safe to do so, because the target buffer is considered
invalid by Mm untill the inpage opeartion
is complete. Those pages are not yet part of any working set, beeit system
working set or process working set.
If you wonder how this operates: The pages subject to a inpage operation are
marked as “in transition” && a flag is
set on them that indicates that a inpage operation is in progress. When the
inpage operation is complete with
success, the pages are added to the working sets. If another thread touches
the same memory range while the inpage
operation is not completed yet, the Mm will see this operation as a
transition page fault and that a inpage is pending ,
(remember, the pfn was marked as in transition and a flag to indicate a read
operation is also set) and will block the
thread untill the inpage operation is complete. The Mm will not issue a
inpage operation again in this situation.

One not about memory mapped files. A section object can be backed up on disk
either by the original file which is
memory mapped, either by a pagefile. IO on memory mapped files is performed
by writting/ reading data directly
into the virtual memory representing a mapped view of a section object.
Actual disk IO will take place only
as paging IO. The target file stream can be either a system pagefile, either
the file itself on disk, depending
on how the section object is backed up.

When processing a paging IO you are somewhow limited as what operation you
can request from the file system.
indeed both Cc manager and MmManager might grab(or not =)) (I can describe
actual algorithms if anyone
is interested) FS synchronization objects for the current file stream. Thus,
you might deadlock the system.
The actual limits of what or what you cant do are dependant of underlieing
file system implementation.

  1. How do I disable read ahead / write behind for a file stream ? How can I
    flush cache of a file stream
    Will any write operations resulted from a section / cache flush result in
    anything else than paging IO ?
    Will read ahead result in anything else than paging IO ?

CcSetAdditionalCacheAttributes();
CcFlushCache() … this routine is also used by the lazy writer for
write behind

The IO requested as the result of a flush is always paging IO. Implicitly
IO caused by lazy writer thread
will always be paging IO. Read ahead is peformed , as outlined earlier,
through page faults. You will see
nothing else for read ahead than paging IO requests.

  1. What are stream file objects ? Who uses them and for what?

Stream file objects are file objects created with one of the following 2
APIs: IoCreateStreamFileObject() and
IoCreateStreamFileObjectLite(). Stream file objects can be identified
through FO_STREAM_FILE flag in
FileObject->Flags. Stream file objects are only valid for paging IO. Note
that for stream file objects you
will never see a IRP_MJ_CREATE_OPERATION. For stream files objects created
with IoCreateStreamFileObject()
you will always see as the first operation a IRP_MJ_CLEANUP, followed by any
valid paging IO operations. For
stream file objects created with IoCreateStreamFileObjectLite(), a
IRP_MJ_CLEANUP is never seen. the first
operation performed on them can be any valid paging IO operation.
Stream file objects are ussualy used internally by file systems to map in
mmeory on disk data structures
for easy access (in system cache usually), and possibly to implement caching
of a file stream.
It is important for a filter driver to be prepared to handle those objects
correctly. Absentia of a
IRP_MJ_CREATE makes hard to corectly track state , and has a deep impact
over the reference counting
mechanism used. This hold true especially for the stream file objects
created with IoCreateStreamFileObjectLite()
for which not even a IRP_MJ_CLEANUP is seen by a filter driver.

  1. How should I track state ? What reference model should I use ?

Is up to you. Pay attention to stream file objects. A file system filter
driver should track state based on
contexts rather than file objects, whenever possible. Check last NT Insider
issue, it has a nice article about
reference counting. Your biggest concern here will be not to free your
tracking structures too early. For Windows XP+
only support and for file systems which support it , the logical choiche
is the new FsRtl context tracking mechanism. This mechanism works only with
active support from the underlieing
file system, and NOT all file systems are required to implement it. So even
if plan to use your driver in XP
only, the new context tracking mechanism might not work on 3rd party file
systems.

  1. Should I worry about FastIoRead , FastIoWrite && brothers ?

Generally speaking , data IO through fast io entry points will always be
satisfied from cache. Fast IO will
not be performed on stream files for which caching havent been initialized.
usually the Cc Copy interface is
used for FastIoRead / FastIoWrite. You will get to see the data written
through those interfaces as paging IO
coming from cache manager, in due time.
More general , the degree at which a filter driver of this kind have to
mess with FastIo path is highly
dependant of the design choosed.

  1. When is cache initialized on a file stream?

Since a file stream can be opened for other purposes than data IO , for
example for delete only, or
query attributtes, many file systems defer cache initialization for a file
stream untill they see the
first data IO operation incoming, beeit a IRP_MJ_READ or a IRP_MJ_WRITE.

Assuming in a filter driver, in post create processing, that cache was
initializaed for a file stream, even for a file created for buffered access,
s a mistake. You can check if the cache was intialized for a file stream by
using
FileObject->PrivateCacheMap

Dan

> One not about memory mapped files. A section object can be backed up on
disk

either by the original file which is
memory mapped, either by a pagefile. IO on memory mapped files is
performed
by writting/ reading data directly
into the virtual memory representing a mapped view of a section object.
Actual disk IO will take place only
as paging IO. The target file stream can be either a system pagefile,
either
the file itself on disk, depending
on how the section object is backed up.
How happens I never see any IRP_MJ_WRITE to a file in FileMon when writing
to that file through a memory map?

When processing a paging IO you are somewhow limited as what operation you
can request from the file system.
indeed both Cc manager and MmManager might grab(or not =)) (I can describe
actual algorithms if anyone
is interested) FS synchronization objects for the current file stream.
Thus,
you might deadlock the system.
The actual limits of what or what you cant do are dependant of underlieing
file system implementation.
I am really interested.

And a question. How do I build a paging IRP. Do I just allocate it with
IoAllocateIrp and set IRP_PAGING_IO flag? How do I free the IRP?

-htfv

You allocate the IRP, then set Irp->Flags to IRP_NOCACHE | IRP_PAGING_IO
or IRP_NOCACHE | IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO,
depending whatever you want an synch or asynch request.

For the rest of your question , I will post a message tommorow detailiating
some aspects of
completion and FCB locking in the case of paging IO. Im too tired now,
sorry

Ciao , Dan

“Alexey Logachyov” wrote in message news:xxxxx@ntfsd…
>
> > One not about memory mapped files. A section object can be backed up on
> disk
> > either by the original file which is
> > memory mapped, either by a pagefile. IO on memory mapped files is
> performed
> > by writting/ reading data directly
> > into the virtual memory representing a mapped view of a section object.
> > Actual disk IO will take place only
> > as paging IO. The target file stream can be either a system pagefile,
> either
> > the file itself on disk, depending
> > on how the section object is backed up.
> How happens I never see any IRP_MJ_WRITE to a file in FileMon when writing
> to that file through a memory map?
>
> > When processing a paging IO you are somewhow limited as what operation
you
> > can request from the file system.
> > indeed both Cc manager and MmManager might grab(or not =)) (I can
describe
> > actual algorithms if anyone
> > is interested) FS synchronization objects for the current file stream.
> Thus,
> > you might deadlock the system.
> > The actual limits of what or what you cant do are dependant of
underlieing
> > file system implementation.
> I am really interested.
>
> And a question. How do I build a paging IRP. Do I just allocate it with
> IoAllocateIrp and set IRP_PAGING_IO flag? How do I free the IRP?
>
> -htfv
>
>
>
>
>
>

Why do you want to initiate paging i/o?
Ravi

-----Original Message-----
From: Dan Partelly [mailto:xxxxx@rdsor.ro]
Sent: Wednesday, July 24, 2002 3:42 PM
To: File Systems Developers
Subject: [ntfsd] Re: On-the-fly encryption/decryption driver workflow

You allocate the IRP, then set Irp->Flags to IRP_NOCACHE | IRP_PAGING_IO
or IRP_NOCACHE | IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO, depending
whatever you want an synch or asynch request.

For the rest of your question , I will post a message tommorow
detailiating some aspects of completion and FCB locking in the case of
paging IO. Im too tired now, sorry

Ciao , Dan

“Alexey Logachyov” wrote in message
news:xxxxx@ntfsd…
>
> > One not about memory mapped files. A section object can be backed up

> > on
> disk
> > either by the original file which is
> > memory mapped, either by a pagefile. IO on memory mapped files is
> performed
> > by writting/ reading data directly
> > into the virtual memory representing a mapped view of a section
> > object. Actual disk IO will take place only as paging IO. The target

> > file stream can be either a system pagefile,
> either
> > the file itself on disk, depending
> > on how the section object is backed up.
> How happens I never see any IRP_MJ_WRITE to a file in FileMon when
> writing to that file through a memory map?
>
> > When processing a paging IO you are somewhow limited as what
> > operation
you
> > can request from the file system.
> > indeed both Cc manager and MmManager might grab(or not =)) (I can
describe
> > actual algorithms if anyone
> > is interested) FS synchronization objects for the current file
> > stream.
> Thus,
> > you might deadlock the system.
> > The actual limits of what or what you cant do are dependant of
underlieing
> > file system implementation.
> I am really interested.
>
> And a question. How do I build a paging IRP. Do I just allocate it
> with IoAllocateIrp and set IRP_PAGING_IO flag? How do I free the IRP?
>
> -htfv
>
>
>
>
>
>


You are currently subscribed to ntfsd as: xxxxx@windows.microsoft.com
To unsubscribe send a blank email to %%email.unsub%%

One example would be if you dont use the original IRP to write modified data
on disk and you roll your own. But one can have multiple reasons to
initiate paging IO. I know i had to doit sometimes.

Dan

----- Original Message -----
From: “Ravisankar Pudipeddi”
To: “File Systems Developers”
Sent: Thursday, July 25, 2002 8:26 PM
Subject: [ntfsd] Re: On-the-fly encryption/decryption driver workflow

Why do you want to initiate paging i/o?
Ravi

-----Original Message-----
From: Dan Partelly [mailto:xxxxx@rdsor.ro]
Sent: Wednesday, July 24, 2002 3:42 PM
To: File Systems Developers
Subject: [ntfsd] Re: On-the-fly encryption/decryption driver workflow

You allocate the IRP, then set Irp->Flags to IRP_NOCACHE | IRP_PAGING_IO
or IRP_NOCACHE | IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO, depending
whatever you want an synch or asynch request.

For the rest of your question , I will post a message tommorow
detailiating some aspects of completion and FCB locking in the case of
paging IO. Im too tired now, sorry

Ciao , Dan

“Alexey Logachyov” wrote in message
news:xxxxx@ntfsd…
>
> > One not about memory mapped files. A section object can be backed up

> > on
> disk
> > either by the original file which is
> > memory mapped, either by a pagefile. IO on memory mapped files is
> performed
> > by writting/ reading data directly
> > into the virtual memory representing a mapped view of a section
> > object. Actual disk IO will take place only as paging IO. The target

> > file stream can be either a system pagefile,
> either
> > the file itself on disk, depending
> > on how the section object is backed up.
> How happens I never see any IRP_MJ_WRITE to a file in FileMon when
> writing to that file through a memory map?
>
> > When processing a paging IO you are somewhow limited as what
> > operation
you
> > can request from the file system.
> > indeed both Cc manager and MmManager might grab(or not =)) (I can
describe
> > actual algorithms if anyone
> > is interested) FS synchronization objects for the current file
> > stream.
> Thus,
> > you might deadlock the system.
> > The actual limits of what or what you cant do are dependant of
underlieing
> > file system implementation.
> I am really interested.
>
> And a question. How do I build a paging IRP. Do I just allocate it
> with IoAllocateIrp and set IRP_PAGING_IO flag? How do I free the IRP?
>
> -htfv
>
>
>
>
>
>


You are currently subscribed to ntfsd as: xxxxx@windows.microsoft.com
To unsubscribe send a blank email to %%email.unsub%%


You are currently subscribed to ntfsd as: xxxxx@rdsor.ro
To unsubscribe send a blank email to %%email.unsub%%

Hello, Dan! Pretty long time passed and still no answers :wink:

-htfv

----- Original Message -----
From: “Dan Partelly”
Newsgroups: ntfsd
To: “File Systems Developers”
Sent: Thursday, July 25, 2002 1:41 AM
Subject: [ntfsd] Re: On-the-fly encryption/decryption driver workflow

> You allocate the IRP, then set Irp->Flags to IRP_NOCACHE | IRP_PAGING_IO
> or IRP_NOCACHE | IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO,
> depending whatever you want an synch or asynch request.
>
> For the rest of your question , I will post a message tommorow
detailiating
> some aspects of
> completion and FCB locking in the case of paging IO. Im too tired now,
> sorry
>
> Ciao , Dan
>
>
>
> “Alexey Logachyov” wrote in message news:xxxxx@ntfsd…
> >
> > > One not about memory mapped files. A section object can be backed up
on
> > disk
> > > either by the original file which is
> > > memory mapped, either by a pagefile. IO on memory mapped files is
> > performed
> > > by writting/ reading data directly
> > > into the virtual memory representing a mapped view of a section
object.
> > > Actual disk IO will take place only
> > > as paging IO. The target file stream can be either a system pagefile,
> > either
> > > the file itself on disk, depending
> > > on how the section object is backed up.
> > How happens I never see any IRP_MJ_WRITE to a file in FileMon when
writing
> > to that file through a memory map?
> >
> > > When processing a paging IO you are somewhow limited as what operation
> you
> > > can request from the file system.
> > > indeed both Cc manager and MmManager might grab(or not =)) (I can
> describe
> > > actual algorithms if anyone
> > > is interested) FS synchronization objects for the current file stream.
> > Thus,
> > > you might deadlock the system.
> > > The actual limits of what or what you cant do are dependant of
> underlieing
> > > file system implementation.
> > I am really interested.
> >
> > And a question. How do I build a paging IRP. Do I just allocate it with
> > IoAllocateIrp and set IRP_PAGING_IO flag? How do I free the IRP?
> >
> > -htfv
> >
> >
> >
> >
> >
> >
>
>
>
> —
> You are currently subscribed to ntfsd as: xxxxx@vba.com.by
> To unsubscribe send a blank email to %%email.unsub%%
>

Hi Alexey,

Ya, life was pretty bussy last days, sorry for delay but I did not had
enough time to focus my toughts on this. Bare with me one or two days more
and Ill post the info I promissed.

Ciao

----- Original Message -----
From: “Alexey Logachyov”
To: “File Systems Developers”
Sent: Wednesday, August 07, 2002 2:36 PM
Subject: [ntfsd] Re: On-the-fly encryption/decryption driver workflow

> Hello, Dan! Pretty long time passed and still no answers :wink:
>
> -htfv
>
> ----- Original Message -----
> From: “Dan Partelly”
> Newsgroups: ntfsd
> To: “File Systems Developers”
> Sent: Thursday, July 25, 2002 1:41 AM
> Subject: [ntfsd] Re: On-the-fly encryption/decryption driver workflow
>
>
> > You allocate the IRP, then set Irp->Flags to IRP_NOCACHE | IRP_PAGING_IO
> > or IRP_NOCACHE | IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO,
> > depending whatever you want an synch or asynch request.
> >
> > For the rest of your question , I will post a message tommorow
> detailiating
> > some aspects of
> > completion and FCB locking in the case of paging IO. Im too tired now,
> > sorry
> >
> > Ciao , Dan
> >
> >
> >
> > “Alexey Logachyov” wrote in message
news:xxxxx@ntfsd…
> > >
> > > > One not about memory mapped files. A section object can be backed up
> on
> > > disk
> > > > either by the original file which is
> > > > memory mapped, either by a pagefile. IO on memory mapped files is
> > > performed
> > > > by writting/ reading data directly
> > > > into the virtual memory representing a mapped view of a section
> object.
> > > > Actual disk IO will take place only
> > > > as paging IO. The target file stream can be either a system
pagefile,
> > > either
> > > > the file itself on disk, depending
> > > > on how the section object is backed up.
> > > How happens I never see any IRP_MJ_WRITE to a file in FileMon when
> writing
> > > to that file through a memory map?
> > >
> > > > When processing a paging IO you are somewhow limited as what
operation
> > you
> > > > can request from the file system.
> > > > indeed both Cc manager and MmManager might grab(or not =)) (I can
> > describe
> > > > actual algorithms if anyone
> > > > is interested) FS synchronization objects for the current file
stream.
> > > Thus,
> > > > you might deadlock the system.
> > > > The actual limits of what or what you cant do are dependant of
> > underlieing
> > > > file system implementation.
> > > I am really interested.
> > >
> > > And a question. How do I build a paging IRP. Do I just allocate it
with
> > > IoAllocateIrp and set IRP_PAGING_IO flag? How do I free the IRP?
> > >
> > > -htfv
> > >
> > >
> > >
> > >
> > >
> > >
> >
> >
> >
> > —
> > You are currently subscribed to ntfsd as: xxxxx@vba.com.by
> > To unsubscribe send a blank email to %%email.unsub%%
> >
>
>
>
>
> —
> You are currently subscribed to ntfsd as: xxxxx@rdsor.ro
> To unsubscribe send a blank email to %%email.unsub%%
>