What is the best way to filter non-cached IRP's ?

Hello,

So I have my file system filter driver, it works well… I can filter
any file on any disk on my system, I can replace the IRP’s buffers with
my own (and free them in the completion routine), driver verifier loves
me, the checked build says I’m da man and best of the best women start
to look at me with more insistence (well known side effect of kernel
development).

Let’s say I would like to modify a file, a simple xor 0xff on the whole
data (for testing purposes). The problem is that I want to do it once,
which means that when the file is cached I do not want to xor the data
that will be cached but the data that will be written. xor ff being
involute, I will quickly see if the data is altered twice since it will
end up unaltered (that and my KdBreakPoint() :p).

*Solution 1* could be not to filter the paging io thanks to the
appropriate irp flag. Problem then would be to filter fastio as well
(it’s not hard but it’s more work). Plus I would end up xoring data at
each cache access, resulting in poor performances. And since my goal is
to add persistent data to the disk, it would be more rational to use…

*Solution 2*. Yeah. That’s all about filtering only direct disk writes.
Being merely mundane with FS I decided to do some tests. I made an user
program that use all possible flags for CreateFile() and MapViewOfFile()
and omgWriteThatBloodyData(). I realized that all direct disk writes
were in IRPss with the IRP_NOCACHE flag. I think there is a cleaner,
better approach to ensure that the write is meant for the disk since it
may be very well possible that under stressful conditions this heuristic
turns out to be incorrect.

All my work is meant to work for NTFS. If I’m in the mood perhaps I’ll
make it work for FAT*. I would really appreciate any pointer to a
reliable heuristic to determine if an IRP will end up in the cache or on
the disk (for an NTFS fs).

Another question that is not related to this problem. I can not unload
my driver without crashing the system. My driver is written in C++ with
a framework of my own, and this framework works well for other drivers.
There is no memory leak, no unallocated resource, no nothing. I’ve pin
pointed the problem to the fact that if ever my driver filters a file
system, I can not unload it without crashing the system. Is it normal or
is it the symptom of a tedious bug?

Thanks.

Edouard

> So I have my file system filter driver, it works well… I can filter

any file on any disk on my system, I can replace the IRP’s buffers with
my own (and free them in the completion routine), driver verifier loves
me, the checked build says I’m da man and best of the best women start
to look at me with more insistence (well known side effect of kernel
development).

Well I am afraid that whe women looking at you with insistence
are not as good in FS filter development, because:

It seems you don’t understand the concept of cached/noncached
I/O. You saying that your filter works for most of the files, but I assume
you’ve only tried a testprogram “CreateFile/ReadFile/CloseHandle”.

Have you tried Notepad with your filter ?

You have to intercept only noncached io, because this is the I/O
going from/to disk file. You also should study the mechanism how
Cache Manager works in Windows, because this is ABSOLUTELY
essential for such kind of filter.

Another question that is not related to this problem. I can not unload
my driver without crashing the system. My driver is written in C++ with

No one can. File system filters cannot be unloaded in the case there’s at
least
one volume they are attached to (which is, in praxis, always).

L.

Ladislav Zezula wrote:

It seems you don’t understand the concept of cached/noncached
I/O. You saying that your filter works for most of the files, but I
assume
you’ve only tried a testprogram “CreateFile/ReadFile/CloseHandle”.
My program use mapped file as well (I think I talked about MapViewOfFile
in my first message…)… It uses all possible combinations of flags
for CreateFileMapping() and CreateFile(). I do the read/write modulo the
sector size to get the benefits of non buffered writing.

Have you tried Notepad with your filter ?
My filter works with notepad, what happens is that during IRP_MJ_READ I
have a new PFILE_OBJECT that has got the same FsContext than
PFILE_OBJECTs I’m already filtering. I simply add it to my structure and
I/O will be caught as paging IO later… The only thing I’ve not tried
yet is file going through srv.sys (although I handle IRP_MN_MDL stuff).
Actually my driver currently “works”, but that’s not the point.

You have to intercept only noncached io, because this is the I/O
going from/to disk file. You also should study the mechanism how
Cache Manager works in Windows, because this is ABSOLUTELY
essential for such kind of filter.

I think I’ve not explained my problem correctly. I simply want to know
if IRP_NOCACHE is good enough to be sure that the IRP will directly be
written to the disk or :

1/Will sometimes IRP without this flag be written directly to the disk;
2/Will sometimes IRP with this flag be cached anyway.

My problem is to modify the data once, that’s all. I’ve got no problem
of missing I/O or anything else… Well not yet… ^^ If IRP_NOCACHE
doesn’t work I’m afraid I’ll have to go through some obscure
IoGetTopLevelIrp() stuff… :confused:

Thanks for your time.

EA

Maybe I understand it wrong too. Yes, IRP_NOCACHE is enough for
knowing it the file is going to the disk. That’s valid on local file
systems,
though. Network file systems may have their own caching policy
(there is an article about it on OSR online)

Sorry for misunderstanding

L.

> My filter works with notepad, what happens is that during IRP_MJ_READ I

have a new PFILE_OBJECT that has got the same FsContext than
PFILE_OBJECTs I’m already filtering. I simply add it to my structure and
I/O will be caught as paging IO later… The only thing I’ve not tried
yet is file going through srv.sys (although I handle IRP_MN_MDL stuff).
Actually my driver currently “works”, but that’s not the point.

MDL reads/writes are cached I/O, you need not filter them for a local filter.

You will need to filter them should you wish to have data transmitted over
the network encrypted.


Kind regards, Dejan M.
http://www.alfasp.com E-mail: xxxxx@alfasp.com
Alfa Transparent File Encryptor - Transparent file encryption services.
Alfa File Protector - File protection and hiding library for Win32 developers.
Alfa File Monitor - File monitoring library for Win32 developers.

Dejan Maksimovic wrote:

> My filter works with notepad, what happens is that during IRP_MJ_READ I
> have a new PFILE_OBJECT that has got the same FsContext than
> PFILE_OBJECTs I’m already filtering. I simply add it to my structure and
> I/O will be caught as paging IO later… The only thing I’ve not tried
> yet is file going through srv.sys (although I handle IRP_MN_MDL stuff).
> Actually my driver currently “works”, but that’s not the point.

MDL reads/writes are cached I/O, you need not filter them for a local filter.

You will need to filter them should you wish to have data transmitted over
the network encrypted.

Currently my filter simply passes down IRPs with the IRP_MN_MDL minor
flag. If I understood correctly, these IRPs have MDL describing memory
in the cache for performance sakes.

Ideally my driver should be able to filter correctly data from the
network (applying f(x) on the data, f(x) being the data modification
function) and to the network (applying f-1(x)).

I do *not* want the data at the other end to have f(x) applied. Let f(x)
be a ciphering function, if the file is copied over the network I want
it to end up in clear text (which means f-1(x) will be applied during
reading on the local computer). As well, if the file is copied from the
network, it is assumed clear text (which means f(x) will be applied
during writing).

Is there anything special to do, or can I simply filter these IRPs like
the others? I guess I have to be careful with the second IRP_MN_MDL
message which indicates the MDL is about to be released, but is there
any other pitfall?

Thanks.

Edouard

> Currently my filter simply passes down IRPs with the IRP_MN_MDL minor

flag. If I understood correctly, these IRPs have MDL describing memory
in the cache for performance sakes.

Yes.

I do *not* want the data at the other end to have f(x) applied. Let f(x) be a ciphering
function, if the file is copied over the network I want it to end up in clear text (which
means f-1(x) will be applied during reading on the local computer). As well, if the file
is copied from the network, it is assumed clear text (which means f(x) will be applied
during writing).

This how your current solution will behave.

Is there anything special to do, or can I simply filter these IRPs like the others? I
guess I have to be careful with the second IRP_MN_MDL message which indicates the MDL is
about to be released, but is there any other pitfall?

I must be misinterpreting you, since the last three paragraphs of yours seem to
contradict each other… in one, you do want to filter data going through the network, the
second not, here yes :wink:

IRP_MN_MDL gets the MDLs from the cache manager - if the required pages are not
present in the cache, the cache manager will issue paging I/O to read them from the disk.
Since more than one MDL may describe these pages (one for each in the worst case scenario),
the cache manager will use linked MDLs (lpMdl->Next).
Here’s what happens for each MDL request:

  • IRP_MJ_READ/IRP_MN_MDL, MDLs with the read data are given to the caller (I am not
    sure if the file region asked for is locked or not! Anyone?)
  • IRP_MJ_READ/IRP_MN_COMPLETE_MDL releases the MDLs
    If you would need to have data going encrypted through the network, you need to
    encrypt the MDLs in the IRP_MJ_READ/IRP_MN_MDL and decrypt in IRP_MN_COMPLETE_MDL. Yes, the
    data would be in cipher-text in cache, which is why I think the file region is locked
    between the two MDL calls.
  • IRP_MJ_WRITE/IRP_MN_MDL same as IRP_MJ_READ/IRP_MN_MDL really. However, the data
    “Read” this way does not go through the network.
  • IRP_MJ_WRITE/IRP_MN_COMPLETE_MDL releases the MDLs. The cache manager will
    eventually perform paging I/O to write the changes back to the disk.
    Again, if you need to have data going encrypted through the network, encrypt during
    IRP_MJ_WRITE/IRP_MN_COMPLETE_MDL.


Kind regards, Dejan M.
http://www.alfasp.com E-mail: xxxxx@alfasp.com
Alfa Transparent File Encryptor - Transparent file encryption services.
Alfa File Protector - File protection and hiding library for Win32 developers.
Alfa File Monitor - File monitoring library for Win32 developers.

Dejan Maksimovic wrote:

I must be misinterpreting you, since the last three paragraphs of yours seem to
contradict each other… in one, you do want to filter data going through the network, the
second not, here yes :wink:

Well I feared I might have to do some processing in order to be sure the
data was deciphered correctly to be transmitted in clear through the
network.

IRP_MN_MDL gets the MDLs from the cache manager - if the required pages are not
present in the cache, the cache manager will issue paging I/O to read them from the disk.
Since more than one MDL may describe these pages (one for each in the worst case scenario),
the cache manager will use linked MDLs (lpMdl->Next).
Here’s what happens for each MDL request:

  • IRP_MJ_READ/IRP_MN_MDL, MDLs with the read data are given to the caller (I am not
    sure if the file region asked for is locked or not! Anyone?)
  • IRP_MJ_READ/IRP_MN_COMPLETE_MDL releases the MDLs
    If you would need to have data going encrypted through the network, you need to
    encrypt the MDLs in the IRP_MJ_READ/IRP_MN_MDL and decrypt in IRP_MN_COMPLETE_MDL. Yes, the
    data would be in cipher-text in cache, which is why I think the file region is locked
    between the two MDL calls.
  • IRP_MJ_WRITE/IRP_MN_MDL same as IRP_MJ_READ/IRP_MN_MDL really. However, the data
    “Read” this way does not go through the network.
  • IRP_MJ_WRITE/IRP_MN_COMPLETE_MDL releases the MDLs. The cache manager will
    eventually perform paging I/O to write the changes back to the disk.
    Again, if you need to have data going encrypted through the network, encrypt during
    IRP_MJ_WRITE/IRP_MN_COMPLETE_MDL.

Ah thanks, that wasn’t clear! Well, yes, it seems not doing anything
with those IRPs will produce the desired result.

Thanks again.

Edouard