First, as I'm sure you've noticed if you looked at the actual flag values in the wdm.h file, there seems to be a flag missing, with the value 0x00800000, which would put it between FO_VOLUME_OPEN and FO_REMOTE_ORIGIN. Well, the easiest way to solve this mystery is to look at an older DDK where you'll find the missing flag:
- FO_FILE_OBJECT_HAS_EXTENSION - 0x00800000
Anyway, this FILE_OBJECT extension seems to have been used to implement the same functionality that FsRtlInsertPerFileObjectContext provides today. FltMgr's designers had a goal to make sure that everything that FltMgr does can be implemented by a 3rd party filter and so since they couldn't expect 3rd party filters to modify private OS structures they had exposed the same functionality through the FSRTL_PER_FILEOBJECT_CONTEXT structure and related functions (FsRtlInitPerFileObjectContext, FsRtlInsertPerFileObjectContext, FsRtlLookupPerFileObjectContext, FsRtlRemovePerFileObjectContext). Since this is implemented in a different way today it makes sense that this flag is obsolete for now. Please do note, however, that it's entirely possible that it will be reused at some point in the future.
Another thing I wanted to do was to take a closer look at how the FO_DISALLOW_EXCLUSIVE flag can be used, since as I mentioned in my previous post in the series I wasn't sure what it does. Well, after some investigation I have some idea what it does but I'm not sure why exactly this behavior would be desired. So first I'd like to mention that this flag doesn't seem to be used anywhere in the WDK, neither FastFat nor CDFS seem to need it. I couldn't find anything about it online. Naturally I searched for both FO_DISALLOW_EXCLUSIVE and FILE_DISALLOW_EXCLUSIVE but there was really no mention about what they might do or where they might be used. However, there was one bit of information in the WDK that helped a lot: the fact that FO_DISALLOW_EXCLUSIVE is the only flag defined for FO_FLAGS_VALID_ONLY_DURING_CREATE. So I decided to take a very close look at Ntfs' IRP_MJ_CREATE processing in the hope that I might be able to figure out where this flag might be used.
So after some debugging and using my favorite disassembler, IDA, I've been able to find a couple of places where this flag might be checked. In particular the Ntfs!NtfsOpenAttribute function looked very promising since it had code that checked for that exact value, and moreover it was using the same offset into a structure that the FILE_OBJECT->Flags are at:
So I figured I had a pretty good shot at finding out how this is used by looking at when these flags are checked (the path that leads to the checks). That involved a lot of debugging and backtracking, good thing VMWare makes it so easy to retry exactly the same code path over and over again :). Anyway, this is the piece of code that turned out to be relevant:1: kd> dt nt!_FILE_OBJECT +0x000 Type : Int2B +0x002 Size : Int2B ... +0x02c Flags : Uint4B ... +0x07c FileObjectExtension : Ptr32 Void 1: kd> u 960e7c14 L1 Ntfs!NtfsOpenAttribute+0x1f0: 960e7c14 f7402c00000002 test dword ptr [eax+2Ch],2000000h 1: kd> u 960e7ded L1 Ntfs!NtfsOpenAttribute+0x3ca: 960e7ded f7402c00000002 test dword ptr [eax+2Ch],2000000h
What this piece of code checks is that if the file is not writable and this flag is set and the user wants to open the file exclusively (doesn't share READ, WRITE and DELETE; this particular check happens a bit further up in the code, not pictured here…) then the IRP_MJ_CREATE will fail with error 0xC0000022, STATUS_ACCESS_DENIED. I've been able to validate that this is the case using FileTest (during debugging I resorted to nasty tricks to get the thread to take that path I wanted, so I had to validate that this can be done by regular creates too), by creating a file with a Deny Write DACL for EVERYONE (so that Ntfs!NtfsWriteCheck would fail) and then opening it exclusively. It works fine if I don't specify FILE_DISALLOW_EXCLUSIVE but fails with STATUS_ACCESS_DENIED when I add FILE_DISALLOW_EXCLUSIVE to the options.1: kd> u Ntfs!NtfsOpenAttribute+0x3af L0x10 Ntfs!NtfsOpenAttribute+0x3b0: 960e7dd3 7328 jae Ntfs!NtfsOpenAttribute+0x3da (960e7dfd) 960e7dd5 ff7518 push dword ptr [ebp+18h] 960e7dd8 50 push eax 960e7dd9 53 push ebx 960e7dda e8e9d70100 call Ntfs!NtfsWriteCheck (961055c8) 960e7ddf 8845e7 mov byte ptr [ebp-19h],al 960e7de2 c645e601 mov byte ptr [ebp-1Ah],1 960e7de6 84c0 test al,al 960e7de8 7535 jne Ntfs!NtfsOpenAttribute+0x3fc (960e7e1f) 960e7dea 8b4618 mov eax,dword ptr [esi+18h] 960e7ded f7402c00000002 test dword ptr [eax+2Ch],2000000h 960e7df4 7429 je Ntfs!NtfsOpenAttribute+0x3fc (960e7e1f) 960e7df6 a0187c0996 mov al,byte ptr [Ntfs!NtfsStatusDebugEnabled (96097c18)] 960e7dfb 84c0 test al,al 960e7dfd 7414 je Ntfs!NtfsOpenAttribute+0x3f0 (960e7e13) 960e7dff 681f3a0000 push 3A1Fh 1: kd> u 960e7e13 Ntfs!NtfsOpenAttribute+0x3f0: 960e7e13 c745e0220000c0 mov dword ptr [ebp-20h],0C0000022h 960e7e1a e98f040000 jmp Ntfs!NtfsOpenAttribute+0x88a (960e82ae)
As I said before I'm not sure why this is useful, so if you know a scenario where this might be useful please add a comment and enlighten me :). Anyway, this is what I've been to figure out about this flag so I hope it helps...