Saved FILE_OBJECT pointer is bad

Our file system driver maintains a list of objects of our own type which represent information about opened files. Each one of these objects holds a reference to the corresponding FILE_OBJECT which is captured when the request is made to open the file. We have a user process which talks to the driver. When the user mode process is being shut down the driver is sent a request to close a device which causes it to iterate through that list of open files, close the handles, and call methods like MmForceSectionClosed on the FILE_OBJECT (using the address we had saved when the file was opened) SectionObjectPointer.

It turns out that under certain circumstances which I don?t yet fully understand, we are experiencing a BSOD with the error PAGE_FAULT_IN_NONPAGED_AREA when trying to read from address fffff88003f3fa62. The address fffffa8007f50358 corresponds to the SectionObjectPointer (P->fo->SectionObjectPointer) and the code at this point is just checking to see if SectionObjectPointer is NULL. There is a possibility that the SectionObjectPointer address was bad because the parent object’s (the file object) address was bad.

So my question is, “Is it bad to be storing a reference to a FILE_OBJECT that is obtained via an IRP for use later on to perform some cleanup operations during the shutdown of our application?” Any thoughts on what could be going on here?

One question would be are you correctly removing the file objects from
your list when they are closed? It would seem maybe your algorithm for
removing the entries is awry and causing the problem.

Pete

On 9/20/2012 12:09 PM, xxxxx@globalscape.com wrote:

Our file system driver maintains a list of objects of our own type which represent information about opened files. Each one of these objects holds a reference to the corresponding FILE_OBJECT which is captured when the request is made to open the file. We have a user process which talks to the driver. When the user mode process is being shut down the driver is sent a request to close a device which causes it to iterate through that list of open files, close the handles, and call methods like MmForceSectionClosed on the FILE_OBJECT (using the address we had saved when the file was opened) SectionObjectPointer.

It turns out that under certain circumstances which I don?t yet fully understand, we are experiencing a BSOD with the error PAGE_FAULT_IN_NONPAGED_AREA when trying to read from address fffff88003f3fa62. The address fffffa8007f50358 corresponds to the SectionObjectPointer (P->fo->SectionObjectPointer) and the code at this point is just checking to see if SectionObjectPointer is NULL. There is a possibility that the SectionObjectPointer address was bad because the parent object’s (the file object) address was bad.

So my question is, “Is it bad to be storing a reference to a FILE_OBJECT that is obtained via an IRP for use later on to perform some cleanup operations during the shutdown of our application?” Any thoughts on what could be going on here?


NTFSD is sponsored by OSR

For our schedule of debugging and file system seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer


Kernel Drivers
Windows File System and Device Driver Consulting
www.KernelDrivers.com
866.263.9295

fffff88003f3fa62

The first question is if this address is the correct one. It seems really high though. Could it be a casting problem? Are you storing the values in 32-bit values and casting them to 64-bit back?

> fffff88003f3fa62 The first question is if this address is the correct one. It seems really high though.

I can assure you that the value if pretty normal, especially on 64-bit Windows :slight_smile:

As Pete says, make sure that you drop a reference to the FO when you get the
close. The other thing to lookout for might be stack based File Objects, it
is unsafe to do an ObReferenceObject on them.

It seems that FILE_OBJECTs are being reused by the operating system. For instance, if during a file open, I capture the address of the FILE_OBJECT, and then later on when I receive a close on the file I do nothing but return a successful status, then the FILE_OBJECT at that original address may be updated to reflect information (like the FileName) for a different file/directory in the next request. So is it true that FILE_OBJECTs are only valid for the duration of the request in which they are made, and then later on, the FILE_OBJECT may be reused or that the FILE_OBJECT address may no longer be valid?

Well, if you don’t reference the FILE_OBJECT then it’s just a piece of memory that will be reused by the system. If you add a reference then the memory won’t be released and so it’s safe to use the pointer. Due to the way the IO manager is implemented, if you do take a reference you should not ever receive an IRP_MJ_CLOSE (which is sent when the IO manager sees that there are no more references to the object). So as far as I can tell the behavior you’re describing in this last post makes sense.

However, your original question was “Is it bad to be storing a reference to a FILE_OBJECT that is
obtained via an IRP for use later on to perform some cleanup operations during the shutdown of our application”. If by “reference” you mean actually calling ObReferenceObject() then it should pretty much work (see rob’s post for an example where it wouldn’t work). If, on the other hand, you mean “copy a pointer” then that’s not going to be enough since the OS will definitely reuse the FOs.

Thanks,
Alex.

Thank you. The driver was just maintaining a pointer to each FILE_OBJECT that it had in the “open file” list and was not calling ObReferenceObject. I just now put a call in to ObReferenceObject passing in the FILE_OBJECT pointer immediately after adding an item to the list. That seemed to stabilize the issue. However, as you mentioned, I no longer am getting the IRP_MJ_CLOSE requests.

The original intention of this “open file” list was to maintain information about files that are open, so that when the device is closed, if there are open files, we close their handles, and call methods like CcUninitializeCacheMap and MmForceSectionClosed using the FILE_OBJECT pointer that was stored in the item in the list. If IRP_MJ_CLOSE had been called previously, then this was all performed then and the item was removed from the “open file” list. So do you have any recommendations on how I could handle situations where we need to close our device, and there are files that are still open for which we haven?t yet received an IRP_MJ_CLOSE?

You will get an IRP_MJ_CLOSE when the last reference to the
FILE_OBJECT is released, since you didn’t explicitly mention that you
are releasing your references for file_objects, I will assume that
your driver’s reference is the one that is stopping IRP_MJ_CLOSE from
happening.

See MSDN for IRP_MJ_CLEANUP and IRP_MJ_CLOSE.

On Tue, Sep 25, 2012 at 6:56 AM, wrote:
> Thank you. The driver was just maintaining a pointer to each FILE_OBJECT that it had in the “open file” list and was not calling ObReferenceObject. I just now put a call in to ObReferenceObject passing in the FILE_OBJECT pointer immediately after adding an item to the list. That seemed to stabilize the issue. However, as you mentioned, I no longer am getting the IRP_MJ_CLOSE requests.
>
> The original intention of this “open file” list was to maintain information about files that are open, so that when the device is closed, if there are open files, we close their handles, and call methods like CcUninitializeCacheMap and MmForceSectionClosed using the FILE_OBJECT pointer that was stored in the item in the list. If IRP_MJ_CLOSE had been called previously, then this was all performed then and the item was removed from the “open file” list. So do you have any recommendations on how I could handle situations where we need to close our device, and there are files that are still open for which we haven?t yet received an IRP_MJ_CLOSE?
>
>
> —
> NTFSD is sponsored by OSR
>
> For our schedule of debugging and file system seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

If I receive an IRP_MJ_CREATE request, get the FILE_OBJECT from the IRP, capture the pointer to that FILE_OBJECT, and do not call ObReferenceObject, how long am I guaranteed that the FILE_OBJECT pointer will be valid (not be reused or deleted) and still refer to the same file/directory? Is it only until I return from the IRP_MJ_CREATE request, or is it until I return from the IRP_MJ_CLOSE request and does the return code impact it (e.g. like will the FILE_OBJECT remain valid until we return STATUS_SUCCESS for a IRP_MJ_CLOSE request)?

This is a tricky question. If you keep a reference then object won’t be ever freed (the memory will remain allocated and it is safe for you to access). I don’t believe deleted doesn’t really have meaning here (what does deleted mean when applied to a structure ?).
In general a FILE_OBJECT points to the same underlying structure (the FILE_OBJECT is simply the link between OB manager and the NT namespace and the file system’s internal structure representing a file (generally called an SCB or FCB)) between postCreate till postClose. I think about it this way: the IRP_MJ_CREATE is a message where the object manager (OB) says to the file system “here is this FILE_OBJECT, associate it with the file i indicate (by name, fileID and so on)”. So this is only valid after the file system sees the message (before that time there is no connection between the FO and the SCB). IRP_MJ_CLOSE is a different message where the OB tell the file system “this FO is not really used by anyone (since nobody has a reference) so you can break the association”. This allows the file system to free the SCB for example. This means that postClose the FILE_OBJECT isn’t really linked to anything in the file system and can’t be used anyway. Even in preClose one should not use the FILE_OBJECT for IO because it’s possible that some filter below will try to take a reference on the FILE_OBJECT, which would increase the refcount from 0 to 1, which is bad.

Even if you close the handles (which doesn’t really make much sense since you don’t own the handles so I’m not sure how you’d be able to do that; moreover closed handles can be reused so you could end up with huge security problems so I would avoid this) the FILE_OBJECTs will remain, allocated and referenced. You will likely still get requests on them.

If you are the file system I’m not sure you actually need to keep a list of FILE_OBJECTs because you control the structures the FILE_OBJECTs are connected to (SCBs). When you need to sutdown you don’t need to keep a list of FILE_OBJECts that are still open because you can look at the SCBs that you still have open and figure that out from the list of SCBs.

What are you trying to do ? Are you trying to implement something like a forced dismount of a volume ? I recommend really looking at the FastFat sample to see how they do this, because it sounds very similar.

Thanks,
Alex.

Thank you for the information. Yes, we are essentially doing a forced dismount / unload of the file system. Thus after this dismount, any requests targeted to our driver will get a status code of STATUS_VOLUME_DISMOUNTED. My goal is to not overhaul our design right now. I can avoid the bug check by not using the stored FILE_OBJECT pointers, but then I give up the ability to call CcUninitializeCacheMap and MmForceSectionClosed on these FILE_OBJECTs during the dismount. I don?t fully understand what the implications are to not making these call other than a file (or part of a file) remaining cached and possibly not getting flushed, and sections remaining open.

I could update the code that handles IRP_MJ_CLOSE requests to not just return STATUS_VOLUME_DISMOUNTED but to call CcUninitializeCacheMap and MmForceSectionClosed beforehand if we are in a dismounted state. In other words, try to make the calls when the file gets closed rather than during the dismount. Would that work? I would assume that I would need to call these only for FILE_OBJECTs that are actual files. Is there an easy way to tell if a FILE_OBJECT passed along with an IRP_MJ_CLOSE request pertains to a file, versus a device, directory, or volume? Sorry for the novice questions.

Another question I had is, “During the dismount would it be possible to call ObReferenceObjectByHandle with FILE_ANY_ACCESS passing in the handle to get a new FILE_OBJECT for which we could call CcUninitializeCacheMap and MmForceSectionClosed, or would that not have the same effect as using the original FILE_OBJECT?”

I’m sorry but I don’t have any experience with how force dismount works in a file system and I will once again point you to the FastFat source.

To answer some of your questions:
"I could update the code that handles IRP_MJ_CLOSE requests to not just return STATUS_VOLUME_DISMOUNTED but to call CcUninitializeCacheMap and MmForceSectionClosed beforehand if we are in a dismounted state. " -> what good would that do ? The volume is already dismounted and therefore if there was any write happening as a result of those calls you wouldn’t be able to successfully complete it anyway.

“Is there an easy way to tell if a FILE_OBJECT passed along with an IRP_MJ_CLOSE request pertains to a file, versus a device, directory, or volume?” -> well, in general file systems keep track of this internally (again, see the FastFat source code). There is a special FILE_OBJECT flag for volume opens, but nothing for directories or files.

ObReferenceObjectByHandle requires a handle parameter. You don’t normally have handles in a filesystem. Where would you get these handles ?

Thanks,
Alex.

Our driver is able to make requests to our win32 process to obtain handles, and then the driver can duplicate handles into its own address space.

Let’s assume that a file system driver has a FILE_OBJECT from an IRP and then the driver is also able to use ObReferenceObjectByHandle to obtain a FILE_OBJECT for the same file. My final question is, “Would calling MmForceSectionClosed or CcUninitializeCacheMap on the FILE_OBJECT obtained via ObReferenceObjectByHandle have the same effect as calling those methods on the FILE_OBJECT obtained from the IRP?”

I created a test program which memory maps a file that is managed by our file system and then used ObReferenceObjectByHandle in the driver to obtain a FILE_OBJECT for that file. That file object showed that there were non-NULL addresses for SectionObjectPointer->DataSectionObject and SectionObjectPointer->SharedCacheMap. After calling MmForceSectionClosed on that FILE_OBJECT the file still appeared to be mapped in Process Explorer by the test program. I then allowed the test program to unmap the view of the file, which seemed to work properly as Process Explorer showed that the file was no longer mapped by the process. I would have thought that the driver’s MmForceSectionClosed call would have unmapped the file, but that didn’t seem to be the case. Anyone know why that is?

> Our driver is able to make requests to our win32 process to obtain

handles, and then the driver can duplicate handles into its own address
space.

Since a driver cannot “call” an application, I’m not sure what you mean here.

And I remain amazed at the fascination people have for passing handles
into the kernel. Why, exactly, does the driver have to “call” an
application to get a handle?

Let’s assume that a file system driver has a FILE_OBJECT from an IRP and
then the driver is also able to use ObReferenceObjectByHandle to obtain a
FILE_OBJECT for the same file. My final question is, “Would calling
MmForceSectionClosed or CcUninitializeCacheMap on the FILE_OBJECT obtained
via ObReferenceObjectByHandle have the same effect as calling those
methods on the FILE_OBJECT obtained from the IRP?”

I created a test program which memory maps a file that is managed by our
file system and then used ObReferenceObjectByHandle in the driver to
obtain a FILE_OBJECT for that file. That file object showed that there
were non-NULL addresses for SectionObjectPointer->DataSectionObject and
SectionObjectPointer->SharedCacheMap. After calling MmForceSectionClosed
on that FILE_OBJECT the file still appeared to be mapped in Process
Explorer by the test program. I then allowed the test program to unmap
the view of the file, which seemed to work properly as Process Explorer
showed that the file was no longer mapped by the process. I would have
thought that the driver’s MmForceSectionClosed call would have unmapped
the file, but that didn’t seem to be the case. Anyone know why that is?

I would think it was because the kernel still had a reference to the
handle, so it would not be unmapped because the FILE_OBJECT’s reference
count had not gone to zero. That’s just a guess.
joe


NTFSD is sponsored by OSR

For our schedule of debugging and file system seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

I do have a lot of experience with forced dismount - it’s a rats nest of annoying problems for file systems as it is a special case that you have to be able to handle essentially everywhere, so it usually requires some sort of “removal” lock to properly handle synchronizing tear-down. The only blessing is that for most paths this is a shared lock, and for the forced teardown paths you grab it exclusive.

FastFat’s implementation of it is a reasonable model (and demonstrates the complexity). You can also learn about all the historical oddities, like the global VPB spin lock, the fact that VPBs are allocated by both the I/O Manager and the FSDs, etc.

Tony
OSR