IoQueryFileDosDeviceName() Assert in FltMgr

With the checked build of the fltmgr, I’m now seeing this assert in a Pre IRP_MJ_CREATE:

*** Assertion failed: FsRtlIsPagingFile(((fileObject))) || (((fileObject))->FsContext == NULL && FlagOn(((fileObject))->Flags, FO_STREAM_FILE | FO_DIRECT_DEVICE_OPEN)) || FltpIsWellKnownPagingFileName((fileObject))
*** Source File: d:\srvrtm\base\fs\filtermgr\filter\fltmgr.c, line 2057

So I guess I’m calling this routine under circumstances that I shouldn’t be, but the documentation doesn’t state anything to this degree.

I’m kind of stumped, could someone provide any clarification as to exactly what’s going on?

Thanks in advance!

What does the stack look like ?

Thanks,
Alex.

I created a test driver to track this down, but I realized I’m using the checked 2003 SP1 fltmgr.sys with SP2 of 2003. This is all my test driver does and it still asserts:

FLT_PREOP_CALLBACK_STATUS TriMonPreCreate(__inout PFLT_CALLBACK_DATA Data, __in PCFLT_RELATED_OBJECTS FltObjects, __deref_out_opt PVOID *CompletionContext)
{
NTSTATUS Status;
ULONG CreateDisposition;
PFLT_FILE_NAME_INFORMATION pNameInfo = NULL;
POBJECT_NAME_INFORMATION pObjectNameInfo = NULL;

*CompletionContext = NULL;

if(!Data || !FltObjects || !FltObjects->FileObject)
{
return FLT_PREOP_SUCCESS_NO_CALLBACK;
}

// Make sure we’re only trying to open the file or directory (Not create it)
CreateDisposition = (Data->Iopb->Parameters.Create.Options >> 24) & 0x000000ff;
if(CreateDisposition != FILE_OPEN && CreateDisposition != FILE_OPEN_IF)
{
return FLT_PREOP_SUCCESS_NO_CALLBACK;
}

KdPrintEx((DPFLTR_IHVDRIVER_ID , DPFLTR_ERROR_LEVEL, “\n”));
KdPrintEx((DPFLTR_IHVDRIVER_ID , DPFLTR_ERROR_LEVEL, “— Pre IRP_MJ_CREATE —\n”));
KdPrintEx((DPFLTR_IHVDRIVER_ID , DPFLTR_ERROR_LEVEL, “FileName = [%wZ]\n”, &FltObjects->FileObject->FileName));

Status = IoQueryFileDosDeviceName(FltObjects->FileObject, &pObjectNameInfo);
if(NT_SUCCESS(Status))
{
KdPrintEx((DPFLTR_IHVDRIVER_ID , DPFLTR_ERROR_LEVEL, “Drive Letter = [%wZ]\n”, &pObjectNameInfo->Name));

ExFreePool(pObjectNameInfo);
pObjectNameInfo = NULL;
}

return FLT_PREOP_SUCCESS_NO_CALLBACK;
}

I’m having a hard time believing this should be asserting under proper circumstances, so I’m going to match up the correct service packs and see if that makes a difference.

The stack looks like this:

kd> !thread 858cfa80
THREAD 858cfa80 Cid 099c.09a0 Teb: 7ffdf000 Win32Thread: e1e1b800 RUNNING on processor 0
IRP List:
85dd2e20: (0006,01b4) Flags: 00001014 Mdl: 00000000
85de5280: (0006,01b4) Flags: 00000884 Mdl: 00000000
Not impersonating
DeviceMap e1ac88e0
Owning Process 85fa7d88 Image: VMwareTray.exe
Attached Process N/A Image: N/A
Wait Start TickCount 38086 Ticks: 0
Context Switch Count 922 LargeStack
UserTime 00:00:00.000
KernelTime 00:00:00.078
*** ERROR: Module load completed but symbols could not be loaded for VMwareTray.exe
Win32 Start Address VMwareTray (0x0040246a)
Start Address kernel32!BaseProcessStartThunk (0x77e617f8)
Stack Init f4e4c000 Current f4e4b418 Base f4e4c000 Limit f4e48000 Call 0
Priority 10 BasePriority 8 PriorityDecrement 0
*** ERROR: Symbol file could not be found. Defaulted to export symbols for glib-2.0.dll -
*** ERROR: Symbol file could not be found. Defaulted to export symbols for vmtools.dll -
ChildEBP RetAddr Args to Child
f4e4b550 8086e94e 8588dee8 809545ec f4e4b874 nt!DbgBreakPoint (FPO: [0,0,0])
f4e4b838 f71f366d f71f2fd8 f71f2fa8 00000809 nt!RtlAssert+0xba (FPO: [4,181,4])
f4e4b85c f71f4d66 85dd2fb0 85de5290 85ddbb20 fltMgr!FltpPassThrough+0x1d5 (FPO: [1,0,4])
f4e4b890 8081d5c3 858c5858 85dd2e20 85dd2e20 fltMgr!FltpDispatch+0x166 (FPO: [2,7,4])
f4e4b8a4 808ed14b f4e4b964 8588dee8 e1d1ba50 nt!IofCallDriver+0x45 (FPO: [0,0,4])
f4e4b8d0 808f0377 858c5858 000000be 00000009 nt!IopGetFileInformation+0xd9 (FPO: [5,6,4])
f4e4b934 808e227a 8588dee8 00000001 00000001 nt!IopQueryNameInternal+0x1df (FPO: [SEH])
f4e4b968 f79c371a 8588dee8 f4e4b978 00000000 nt!IoQueryFileDosDeviceName+0x30 (FPO: [2,2,0])
f4e4b988 f71e50be 86081bfc f4e4b9a8 f4e4b9cc triMon!TriMonPreCreate+0xba (FPO: [Non-Fpo]) (CONV: stdcall) [c:\projects\tests\drivers\trimon2\trimon.c @ 211]
f4e4b9f0 f71f05a5 f4e4ba3c 8086e894 86081ba0 fltMgr!FltpPerformPreCallbacks+0x694 (FPO: [1,18,4])
f4e4ba08 f7222bec f4e4ba3c f721c8a4 00000000 fltMgr!FltpPassThroughInternal+0xdb (FPO: [2,0,4])
f4e4ba24 f7224c2c f4e4ba3c 8588dee8 85ddbb20 fltMgr!FltpCreateInternal+0x176 (FPO: [1,0,4])
f4e4ba5c 8081d5c3 858c5858 85de5410 85de5280 fltMgr!FltpCreate+0x394 (FPO: [2,8,4])
f4e4ba70 808f100b f4e4bc18 85d1bde8 00000000 nt!IofCallDriver+0x45 (FPO: [0,0,4])
f4e4bb58 8092f806 85d1be00 00000000 85dc1b30 nt!IopParseDevice+0xa35 (FPO: [SEH])
f4e4bbd8 8092b946 00000000 f4e4bc18 00000040 nt!ObpLookupObjectName+0x5b0 (FPO: [11,17,4])
f4e4bc2c 808e2ed7 00000000 00000000 00000001 nt!ObOpenObjectByName+0xea (FPO: [7,5,4])
f4e4bca8 808e4171 0012f5cc 00100001 0012f584 nt!IopCreateFile+0x447 (FPO: [SEH])
f4e4bd04 808e7d01 0012f5cc 00100001 0012f584 nt!IoCreateFile+0xa3 (FPO: [14,3,0])
f4e4bd44 80883948 0012f5cc 00100001 0012f584 nt!NtOpenFile+0x27 (FPO: [6,0,0])
f4e4bd44 7c82860c 0012f5cc 00100001 0012f584 nt!KiFastCallEntry+0xf8 (FPO: [0,0] TrapFrame @ f4e4bd64)
0012f554 7c827339 77e6b974 0012f5cc 00100001 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
0012f558 77e6b974 0012f5cc 00100001 0012f584 ntdll!NtOpenFile+0xc (FPO: [6,0,0])
0012f84c 77e6bb5f 00d4b610 00000000 0012f8a8 kernel32!FindFirstFileExW+0x1c3 (FPO: [6,178,4])
0012f86c 78156f10 00d4b610 0012f8a8 00d4bdb8 kernel32!FindFirstFileW+0x16 (FPO: [2,0,0])
0012fd04 003847de 00d4b610 0012fd38 00d4bdb8 MSVCR80!_wstat64i32+0xb9 (FPO: [Non-Fpo]) (CONV: cdecl) [f:\sp\vctools\crt_bld\self_x86\crt\src\stat64.c @ 135]
WARNING: Stack unwind information not available. Following frames may be wrong.
0012fd20 005c7ef7 00d4bdb8 0012fd38 00000113 glib_2_0!g_stat+0x9e
0012fd68 0040181b 00d4bdb8 00000000 00405044 vmtools!VMTools_ReloadConfig+0x67
0012fda0 7739b6e3 000300b4 00000113 00000000 VMwareTray+0x181b
0012fdcc 7739b874 00401880 000300b4 00000113 USER32!InternalCallWinProc+0x28
0012fe44 7739ba92 00000000 00401880 000300b4 USER32!UserCallWinProcCheckWow+0x151 (FPO: [SEH])
0012feac 7739bad0 0012fed4 00000000 0012fef0 USER32!DispatchMessageWorker+0x327 (FPO: [SEH])
0012febc 00401331 0012fed4 004035d9 00000001 USER32!DispatchMessageW+0xf (FPO: [1,0,0])
0012fef0 00401eb9 004053e4 001524c6 00000000 VMwareTray+0x1331
0012ff30 004022e9 00400000 00000000 001524c6 VMwareTray+0x1eb9
0012ffc0 77e6f23b 00000000 00000000 7ffd7000 VMwareTray+0x22e9
0012fff0 00000000 0040246a 00000000 78746341 kernel32!BaseProcessStart+0x23 (FPO: [SEH])

Note that the process makes little difference, this assert always occurs.

In preCreate the FILE_OBJECT is not initialized (the file system and the
filters below yours haven’t seen the operation yet and haven’t had a chance
to set up whatever they need to set up). IoQueryFileDosDeviceName internally
gets the IO manager to call IopGetFileInformation on that FILE_OBJECT and
that gets translated into an IRP that goes into FltMgr, which being the only
checked component in the io path, asserts. I think you may have seen an
assert before this if you had a checked kernel.

Anyway, FltMgr doesn’t expect to see an uninitialized FILE_OBJECT in any IO
request except IRP_MJ_CREATE.

The assert you’re looking at (FsRtlIsPagingFile(((fileObject))) ||
(((fileObject))->FsContext == NULL && FlagOn(((fileObject))->Flags,
FO_STREAM_FILE | FO_DIRECT_DEVICE_OPEN)) ||
FltpIsWellKnownPagingFileName((fileObject))) can be translated into :
file is paging file or, if FsContext is NULL then this must be either a
stream file object or a direct device open.

My suggestion would be to move this request to postCreate (and only issue it
if the IRP_MJ_CREATE was successful, of course), when the FILE_OBJECT would
be initialized.

Does this make sense ?

Thanks,
Alex.

Yeah, this makes sense, thanks for the info.

The reason I was using the IoQueryFileDosDeviceName() call was to get the drive letter as I’m only interested in file operations from certain locations. This location is passed to the driver via an initialization message from the user-mode service. (Ex: C:\Users). As we know, the driver gets things like “\Device\HarddiskVolume1” so I was trying to map that to a drive letter.

I need to handle this in the pre IRP_MJ_CREATE, so I need figure out another way to handle this mapping. I’ll have to look into this (again) - perhaps the service can handle it by realizing C: translates to “\Device\HarddiskVolume1” and that’s what it sends down.

That makes sense. In this case you definitely want to set up some global
state that allows you to decide without calling an IO function like
IoQueryFileDosDeviceName() on each create (in general calling anything for
each operation is a pretty big perf hit and should be avoided if possible).
Also, if you want to filter whole volumes (as suggested by your drive letter
approach) then you might be better off not attaching the filter at all to
volumes you don’t care about. You can try a couple of different approaches
for this as well, for example you can try either automatic attachment and
then in your instance setup callback you could see if this is a volume you
want to attach to (and if not, tell FltMgr not to attach to it) or better
yet you could set your filter for manual attachment, and in that case your
minifilter won’t be attached to anything automatically and it is up to your
user mode service (or you can do it in an app or another kernel mode driver)
to attach your filter to the right volume by using something like
FilterAttach (which is nice because you can call FilterAttach with drive
letters directly and you don’t have to bother with converting the drive
letter to a volume device name at all).

In general you should avoid doing to many things in preCreate if the
architecture of your filter allows it (for example, if your filter simply
ignores creates for files from other locations then you should make the
decision about whether you care about the file in postCreate; however, if
your minifilter needs to prevent the IRP_MJ_CREATE from reaching the file
system for certain files then postCreate might be too late.).

Thanks,
Alex.