Oplocks, FltReadFile

I have recently inherited a MiniFilter driver. I have sincerely appreciated the list archives, and found the FAQ extremely helpful in understanding oplocks. However, while working on some changes I have come across a few questions about the behavior of FltReadFile with regard to oplocks that is not explained in the FAQ or any documentation that I’ve found.

First, some brief background.

Previously, I addressed a bug where a user would experience a lengthy delay waiting for a file to save on a network share pointing to a remote machine running an instance of our MiniFilter. The delay was caused by an oplock break initiated by an IoCreateFileSpecifyDeviceObjectHint call timing out our MiniFilter’s post IRP_MJ_SET_INFORMATION callback (FileRenameInformation). The break timed out as the break could only be acknowledged by the same thread that was blocking inside our callback. Once our callback completed, the thread would issue an IRP_MJ_CLEANUP to acknowledge the break (which is what our callback was waiting on). Classic deadlock. Addressing this is pretty straightforward and it is described in documentation and has already been discussed on the list a few times.

Fast forward to today, and I’m thinking about this particular case some more. I’m a bit puzzled about proper MiniFilter behavior for some callbacks that might be issued where the associated FileObject is oplocked. When this issue was encountered, I noticed that FltReadFile was called against the PCFLT_RELATED_OBJECT->FileObject provided to the callback. After contemplating this situation a bit, here’s what’s going through my head:

* While processing an IRP [1] for an oplocked file, the IRP should [2] have originated from a driver owning an appropriate [3] oplock.
* There are probably no clear rules about when the contents of a file (as returned from FltReadFile) that is oplocked would be valid [4] (especially with a level 1 oplock); the only guarantee of consistency with a remote machine would be by forcing and waiting for an oplock break.
* Instead of using FltReadFile to examine a file’s contents, a MiniFilter might need to cause an oplock break (to eliminate any level 1 locks) by opening its own handle to the file in order to perform reads against it.

So, ultimately, callers of FltReadFile on a PCFLT_RELATED_OBJECT->FileObject should be aware that the file in question might have an outstanding Level 1 oplock against it, and as such the contents of the file as retuned from this API might not reflect a remote host’s version of the file (or otherwise) until the oplock is broken.

There doesn’t appear to be a reliable way to check for an existing Level 1 oplock until Windows 7, so a MiniFilter supporting earlier versions of the OS is probably better opening their own handle to the file, dealing with any resulting oplock breaks (by performing processing later in a separate thread that can block on FSCTL_OPLOCK_BREAK_NOTIFY IoControl), rather than trusting that FltReadFile will return valid (again, see [4]) data on the associated FileObject without awareness of any oplocks that might be outstanding on the file.

Can anyone confirm or deny my suspicions, or otherwise share some insights about this?

Cheers,

Jason V. Miller
Technical Leader
Cloud Security Operations
xxxxx@cisco.com

Cisco Systems Canada Co. / Les Systemes Cisco Canada CIE
2424 4th Street SW
Calgary, AB Canada

[1] This does not included IRP_MJ_CREATE, or IRP_MJ_DEVICE_CONTROL (which would be used for FSCTL_OPLOCK_BREAK_NOTIFY?)
[2] By should I mean any driver that handles STATUS_OPLOCK_BREAK_IN_PROGRESS properly. Are there any checks in place to detect/prevent misuse?
[3] Appropriate meaning a given oplock type would only cover a certain set of IRPs; not all oplocks allow writes.
[4] In my particular case, valid probably means “consistent with the remote host.”

My minifilter driver has the need to read the contents of the file in the IRP_MJ_CREATE preop callback. I found that in order to work correctly when another system had an oplock open on the file, you need to request a Filter oplock on the file. Rather than check for the presence of an oplock, just request a Filter oplock prior to opening the file. The Filter oplock is supposedly optimized for use in minifilter drivers.

A couple of relevant links from MS:

http://msdn.microsoft.com/en-us/library/windows/hardware/ff551011(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/hardware/ff547373(v=vs.85).aspx

And here’s the code I am using to safely open the contents of the file in IRP_MJ_CREATE preop callback:

http://www.codingnotebook.com/2014/02/open-file-handle-while-handling.html

Thanks for your reply.

I do not currently use filter oplocks, but they seem helpful in avoiding sharing violations in some cases; I may consider using them.

And here’s the code I am using to safely open the contents of the file in
IRP_MJ_CREATE preop callback:

http://www.codingnotebook.com/2014/02/open-file-handle-while-handling.html

It seems to me that you’d want to keep the original handle (READ_ATTRIBUTES) opened until after you close your second handle (GENERIC_READ) in order for the oplock on the first handle to hold back other (conflicting) open requests long enough for you to close the handle that would result in sharing violations. As it stands that code should prevent you from breaking existing oplocks, but won’t prevent sharing violations if an IRP_MJ_CREATE comes in with conflicting shared access options while you’re processing the file (or inbetween your FltCreateFile and FltFsControlFile calls)?

In the case you receive STATUS_OPLOCK_NOT_GRANTED, I presume you are not issuing any read requests against the handle?

Best Regards,

J.

Yes, if the result is STATUS_OPLOCK_NOT_GRANTED and we have to open with FILE_READ_ATTRIBUTES, then you will not be able to fully read the contents of the file so the rest of the code has to adjust to deal with that.

Interesting idea to keep the first handle open. I haven’t played with that because my primary concern is not breaking any oplocks that others may have open. But it seems like an idea worth trying. I can say that requesting a Filter oplock definitely prevents my opening of the file from breaking oplocks from other processes.