Isolation filter causing crash in IoGetTransactionParameterBlock

I have an encryption isolation filter and it’s causing a crash (PAGE_FAULT_IN_FREED_SPECIAL_POOL) when I try to browse for a file through the new Edge browser. The crash happens in IoGetTransactionParameterBlock with the stack below.

07 ffffd00023117528 fffff8000d5044e3 nt!IoGetTransactionParameterBlock+0x18
08 ffffd00023117530 fffff8000d5041dc FLTMGR!FltpPerformPreCallbacks+0x1b3
09 ffffd00023117640 fffff8000d503c03 FLTMGR!FltpPassThroughInternal+0x8c
0a ffffd00023117670 fffff8000d532d10 FLTMGR!FltpPassThrough+0x173
0b ffffd00023117700 fffff802985ab044 FLTMGR!FltpFsControl+0xd0
0c ffffd00023117760 fffff80297f0f252 nt!IovCallDriver+0x3d8
0d ffffd000231177c0 fffff802982ab17d nt!IofCallDriver+0x72
0e ffffd00023117800 fffff802982fc6da nt!IopXxxControlFile+0x71d
0f ffffd00023117a20 fffff80297fd4263 nt!NtFsControlFile+0x56
10 ffffd00023117a90 00007ffbed7238da nt!KiSystemServiceCopyEnd+0x13
11 000000e35e718178 00007ffbeab9ed3a ntdll!NtFsControlFile+0xa
12 000000e35e718180 00007ffbeab91f8b KERNELBASE!DeviceIoControl+0x1aa
13 000000e35e7181f0 00007ffbeab933e0 KERNELBASE!BasepGetVolumeNameFromReparsePoint+0xa7
14 000000e35e7182b0 00007ffbeabb4c9b KERNELBASE!GetDriveTypeW+0x1f0
15 000000e35e7187e0 00007ffbea624cb1 KERNELBASE!GetVolumePathNameInternalW+0x1ab

My filter is not in the stack so I’m stuck on how to really debug it. Doing a little digging in IoGetTransactionParameterBlock (which is a small function), a FILE_OBJECT is passed in and it references the FileObjectExtension. Then if that is not null, it looks for something at an offset but the actual FileObjectExtension is opaque so not exactly sure what. In this case, it doesn’t really matter though because the FILE_OBJECT that is being passed is no longer valid. It is one of my filter’s FILE_OBJECTS (the upper one) but looking at my debug output, I can see that the FILE_OBJECT referenced by IoGetTransactionParameterBlock is closed right before this crash occurs.

The stack trace is consistent and it’s also interesting because the user mode functions in the stack are related to drives whereas the FILE_OBJECT was for a regular directory.

Seeing how the crashing function is related to transactions, I made some changes to see if it would stop the crash. I added a check in PreCreate to deny any transactions operations (FltObjects->Transaction != NULL) and I commented out some code in NormalizeName that deals with transactions. Neither helped because it still crashes.

So, like I said I’m stuck on where else to look or how to solve this. Any thoughts on the root cause or other areas to investigate would be appreciated.

To state the obvious you are obviously missing a path down to the file system. Name Providers and structures which take handles are a good place to look (there are a bunch of FSCTLs out there like MOVE_FILE - and the stack is indicative of that. Indeed a !irp will tell you a great deal.

I’m worried about this statement

it doesn’t really matter though because the FILE_OBJECT that is being passed is no longer valid

The only time a file object is no longer valid is when the reference count goes to zero and you get an MJ_CLOSE. I hope that’s what you mean…

Thanks Rod.

One piece I left out is that I have stacked isolation filters running, one right on top of the other altitude-wise. The lower one does encryption while the higher one does other things. Doing some more testing, it appears there is a conflict between the shadow objects. In this case, the higher filter is closing it’s file objects but the lower file object is actually the upper file object for the lower altitude filter. That upper file object is the one being referenced by IoGetTransactionParameterBlock and causing the crash because it is no longer valid.

So, I guess the obvious question is, are stacked isolation filters allowed (or a good idea)? Will adding checks for FsContext2 in the lower object of the upper filter be enough to indicate whether it is actually the upper object of the lower filter and if so, just pass the request through?

Took me two days but figured out the root cause. When the upper filter created the lower object, the lower filter set FileContextSupportPointer in the FCB header to NULL. When the upper filter went to set a file context, it failed which in turn caused the pre-create to branch to a different path that did not clean things up properly (hence the invalid file object). So that is solved but my next issue is how to properly setup FileContextSupportPointer so that my lower filter does support file contexts. I’m trying to understand what is written about this pointer here (https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-fsrtlsetupadvancedheaderex) but it doesn’t make a lot of sense to me.

“FileContextSupportPointer must be a pointer to a PVOID variable inside a per-file structure for the file system that created the structure.”

I just allocated a PVOID and assigned it to that pointer and it seems to work but I’m wondering if that’s correct and all that needs to be done.

“FileContextSupportPointer must be a pointer to a PVOID variable inside a per-file structure for the file system that created the structure.”

If you are a filter (any structure) your “per file structure” is the FILE Context. In your case it is for the lower file system. Then you use the life cycle of that to drive the life cycle of the upper one (yours)