Handling relative opens in a shadow file object minifilter

Hi all,

This may be a beginner’s question, so please bear with me! I’ve just began to write a shadow file object minifilter that filters a selected subset of files - it’ll create SFOs for files that match a certain criteria, but operations on files that don’t match this criteria will simply be passed through to the underlying FSD.

Essentially, I’ve run into a snag while implementing my IRP_MJ_CREATE callbacks - I’m unsure how to handle relative opens in my minifilter. (I.e. RelatedFileObject != NULL) There are 3 ways I can think of, but all of them seem to be plagued with their own problems:

  1. Use ObOpenObjectByPointer(RelatedFileObject) to obtain a handle to the related file object. Use this handle as the RootDirectory argument in InitializeObjectAttributes, and use FltCreateFileEx to obtain the SFO.

Problem: ObOpenObjectByPointer can cause a deadlock. As I understand it, this occurs when the calling thread has already acquired a lock on the file object. The only scenario where I can think of where deadlock might occur in pre-create is in the reopen case. (I.e. TargetFileObject->FileName.Buffer == NULL and RelatedFileObject points to the file object some driver wants to re-open.) I’m probably wrong though - does anyone know if ObOpenObjectByPointer is safe to use in the pre-create path?

Problem 2: ObOpenObjectByPointer may send QUERY_SECURITY. Some network FSDs might not like that.

  1. Use IoCreateFileStreamObject(Ex/Lite) to create the SFO. Copy RelatedFileObject to the SFO and swap TargetFileObject with the SFO in pre-create.

Problem: The file object extension is a nightmare to deal with; I’d rather avoid it if I can. In addition, flag acrobatics with FO_STREAM_OBJECT and maybe FO_HANDLE_CREATED (since NTFS doesn’t like those flags set in a TargetFileObject) sounds like a disaster waiting to happen.

  1. Filter every single file and store a handle for each file object that I see in IRP_MJ_CREATE. (I.e. create a SFO for every CREATE request.) This means that in theory, I should have my own handle for any RelatedFileObject, so I can use FltCreateFileEx without any of the problems associated with ObOpenObjectByPointer.

Problem: What if some driver performs a relative open on a stream file object? Then this reduces to the problems that occur in solution #1 again.

I’d appreciate any insight on how a minifilter handle a relative open correctly!

Thanks and cheers!
Kuan

#3

A relative open of a stream file object doesn’t make much sense. The idea
with a stream file object is that it is internal to your driver, the outside
world doesn’t understand it. By sending it down as the related file object
you’re giving the lower driver an unsolvable problem (“open Thing Two
relative to Thing One, but you don’t know anything about Thing One and have
actually never even seen it before”). FAT/NTFS/REFS/etc. would actually
crash in this case.

-scott
OSR
@OSRDrivers

wrote in message news:xxxxx@ntfsd…

Hi all,

This may be a beginner’s question, so please bear with me! I’ve just began
to write a shadow file object minifilter that filters a selected subset of
files - it’ll create SFOs for files that match a certain criteria, but
operations on files that don’t match this criteria will simply be passed
through to the underlying FSD.

Essentially, I’ve run into a snag while implementing my IRP_MJ_CREATE
callbacks - I’m unsure how to handle relative opens in my minifilter. (I.e.
RelatedFileObject != NULL) There are 3 ways I can think of, but all of them
seem to be plagued with their own problems:

  1. Use ObOpenObjectByPointer(RelatedFileObject) to obtain a handle to the
    related file object. Use this handle as the RootDirectory argument in
    InitializeObjectAttributes, and use FltCreateFileEx to obtain the SFO.

Problem: ObOpenObjectByPointer can cause a deadlock. As I understand it,
this occurs when the calling thread has already acquired a lock on the file
object. The only scenario where I can think of where deadlock might occur in
pre-create is in the reopen case. (I.e. TargetFileObject->FileName.Buffer ==
NULL and RelatedFileObject points to the file object some driver wants to
re-open.) I’m probably wrong though - does anyone know if
ObOpenObjectByPointer is safe to use in the pre-create path?

Problem 2: ObOpenObjectByPointer may send QUERY_SECURITY. Some network FSDs
might not like that.

  1. Use IoCreateFileStreamObject(Ex/Lite) to create the SFO. Copy
    RelatedFileObject to the SFO and swap TargetFileObject with the SFO in
    pre-create.

Problem: The file object extension is a nightmare to deal with; I’d rather
avoid it if I can. In addition, flag acrobatics with FO_STREAM_OBJECT and
maybe FO_HANDLE_CREATED (since NTFS doesn’t like those flags set in a
TargetFileObject) sounds like a disaster waiting to happen.

  1. Filter every single file and store a handle for each file object that I
    see in IRP_MJ_CREATE. (I.e. create a SFO for every CREATE request.) This
    means that in theory, I should have my own handle for any RelatedFileObject,
    so I can use FltCreateFileEx without any of the problems associated with
    ObOpenObjectByPointer.

Problem: What if some driver performs a relative open on a stream file
object? Then this reduces to the problems that occur in solution #1 again.

I’d appreciate any insight on how a minifilter handle a relative open
correctly!

Thanks and cheers!
Kuan

> ObOpenObjectByPointer(RelatedFileObject)

This is not safe. A handle for RelatedFileObject might have been closed or being closed concurrently with IRP_MJ_CREATE. There is no “documented” way to synchronize with handle closure from a filter/driver. Opening a handle for a file object for which IRP_MJ_CLEANUP has been sent usually results in a BSOD or some sort of corruption.

While not all operations are permitted at that point, the only time it is safe to use the RelatedFileObject is in the IRP_MJ_CREATE path. At that point, it’s been referenced so it won’t go away. However, there is no requirement that the related file object still be open - just valid. In most cases it will be open because it comes from the OBJECT_ATTRIBUTES structure as the root directory handle. In theory, that handle could go invalid after that point, though that’s not terribly likely either.

In addition, the RelatedFileObject is not transitive - that is, you cannot use RelatedFileObject->RelatedFileObject because the OS doesn’t guarantee to hold a reference more than one level deep (so FileObject->RelatedFileObject is referenced, but no more than that).

The underlying file system driver used the RelatedFileObject to figure out what is being opened, so the RelatedFileObject *must* be valid to the file system driver. Otherwise, it will not work properly.

Tony
OSR

> Essentially, I’ve run into a snag while implementing my IRP_MJ_CREATE

callbacks - I’m unsure how to handle relative opens
in my minifilter. (I.e. RelatedFileObject != NULL) There are 3 ways I can
think of, but all of them seem to be plagued with
their own problems:

In general this is a non-problem. If there is a RelatedFileObject then you
must have handled the create for that file object. So you have a handle.
If you are doing an open relative to a file object that you didn’t shadow
then there has to be a really good reason that you didn’t handle that open
and it applies to your related open.

If you think that you have a counter example (like “I don’t do relative
opens on directories”), then you need to think about how you are going to
handle oplocks (which you probably now own).

Thank you all for the insights!

With regards to approach #3 - could it not be possible that RelatedFileObject is a stream file object that belongs to a driver lower on the stack? One example that comes to mind is how filter drivers may see stream file objects from NTFS during paging IO.

It will have the same stream context.

Tony
OSR