double fault, GenerateFileName runaway recursion

My simple attempt at a GenerateFileName seems to get involved in
run-away recursion when I call:

status = FltGetDestinationFileNameInformation(…,
FLT_FILE_NAME_REQUEST_FROM_CURRENT_PROVIDER
| FLT_FILE_NAME_NORMALIZED
| FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP

on a the destination name of a file-rename using rename.exe

The backtrace is like this:


fltmgr!FltpCallOpenedFileNameHandler+0x4f
fltmgr!FltpCreateFileNameInformation+0x79
fltmgr!FltpGetFileNameInformation+0x31d
fltmgr!FltGetFileNameInformationUnsafe+0x59
wepcFilter!wepcGenerateFileName+0x5c
… and on and on

and double-fault (stack overlow?) during a debug statement at:
wepcFilter!wepcGenerateFileName+0x28

The function is shown below.

I’m surprised that it is the Unsafe variant that is being followed; but
perhaps during a rename IRP it’s not surprising. I’m puzzled why it is
not missing out my minifilter when it calls FltpCallOpenedFileNameHandler

NTSTATUS wepcGenerateFileName(
IN PFLT_INSTANCE Instance,
IN PFILE_OBJECT FileObject,
IN PFLT_CALLBACK_DATA CallbackData OPTIONAL,
IN FLT_FILE_NAME_OPTIONS NameOptions,
OUT PBOOLEAN CacheFileNameInformation,
OUT PFLT_NAME_CONTROL FileName
)
{
NTSTATUS status;
PFLT_FILE_NAME_INFORMATION FileNameInformation = NULL;
/*+0x28*/ wepcDebug(“********* GenerateFileName\n”);
//FltGetFileNameFormat()
if (CallbackData) {
status = FltGetFileNameInformation(CallbackData,
NameOptions, &FileNameInformation);
} else {
/*+0x5c*/ status = FltGetFileNameInformationUnsafe(FileObject,
Instance, NameOptions, &FileNameInformation);
}
if (! NT_SUCCESS(status)) return status;

CacheFileNameInformation = FALSE;
status = FltCheckAndGrowNameControl(FileName,
FileNameInformation->Name.Length);
if (! NT_SUCCESS(status)) return status;

RtlCopyUnicodeString(&FileName->Name, &FileNameInformation->Name);
wepcDebug(“NAME: %wZ\n”, &FileNameInformation->Name);
FltReleaseFileNameInformation(FileNameInformation);
return STATUS_SUCCESS;
}

The notes on: PFLT_GENERATE_FILE_NAME
http://msdn.microsoft.com/en-us/library/ms793795.aspx
say:
When this callback routine is invoked, the minifilter driver generates
its own file name information, based on the file system’s file name
information for the file. To get the file system’s file name
information for a file, call FltGetFileNameInformation,
FltGetFileNameInformationUnsafe, or
FltGetDestinationFileNameInformation.

I can’t easily call FltGetDestinationFileNameInformation because I can’t
tell if I’m being called for a destination filename anyway.

Sam Liddicott wrote:

My simple attempt at a GenerateFileName seems to get involved in
run-away recursion when I call:

status = FltGetDestinationFileNameInformation(…,
FLT_FILE_NAME_REQUEST_FROM_CURRENT_PROVIDER
| FLT_FILE_NAME_NORMALIZED
| FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP

If you are doing this call in the GenerateFileName name provider call
back you cannot specify to call back into the current provider. Since it
will re-enter your provider and you will call it again … endlessly.
The should clear that flag from the name options in your code below
before calling into the Flt API.

Also, be careful when querying for a normalized name and specifying to
query the current provider, this can also enter a reentrant loop due to
how MSFT implemented the normalization algorithm.

Pete

on a the destination name of a file-rename using rename.exe

The backtrace is like this:


fltmgr!FltpCallOpenedFileNameHandler+0x4f
fltmgr!FltpCreateFileNameInformation+0x79
fltmgr!FltpGetFileNameInformation+0x31d
fltmgr!FltGetFileNameInformationUnsafe+0x59
wepcFilter!wepcGenerateFileName+0x5c
… and on and on

and double-fault (stack overlow?) during a debug statement at:
wepcFilter!wepcGenerateFileName+0x28

The function is shown below.

I’m surprised that it is the Unsafe variant that is being followed; but
perhaps during a rename IRP it’s not surprising. I’m puzzled why it is
not missing out my minifilter when it calls FltpCallOpenedFileNameHandler

NTSTATUS wepcGenerateFileName(
IN PFLT_INSTANCE Instance,
IN PFILE_OBJECT FileObject,
IN PFLT_CALLBACK_DATA CallbackData OPTIONAL,
IN FLT_FILE_NAME_OPTIONS NameOptions,
OUT PBOOLEAN CacheFileNameInformation,
OUT PFLT_NAME_CONTROL FileName
)
{
NTSTATUS status;
PFLT_FILE_NAME_INFORMATION FileNameInformation = NULL;
/*+0x28*/ wepcDebug(“********* GenerateFileName\n”);
//FltGetFileNameFormat()
if (CallbackData) {
status = FltGetFileNameInformation(CallbackData,
NameOptions, &FileNameInformation);
} else {
/*+0x5c*/ status = FltGetFileNameInformationUnsafe(FileObject,
Instance, NameOptions, &FileNameInformation);
}
if (! NT_SUCCESS(status)) return status;

CacheFileNameInformation = FALSE;
status = FltCheckAndGrowNameControl(FileName,
FileNameInformation->Name.Length);
if (! NT_SUCCESS(status)) return status;

RtlCopyUnicodeString(&FileName->Name, &FileNameInformation->Name);
wepcDebug(“NAME: %wZ\n”, &FileNameInformation->Name);
FltReleaseFileNameInformation(FileNameInformation);
return STATUS_SUCCESS;
}

The notes on: PFLT_GENERATE_FILE_NAME
http://msdn.microsoft.com/en-us/library/ms793795.aspx
say:
When this callback routine is invoked, the minifilter driver generates
its own file name information, based on the file system’s file name
information for the file. To get the file system’s file name
information for a file, call FltGetFileNameInformation,
FltGetFileNameInformationUnsafe, or
FltGetDestinationFileNameInformation.

I can’t easily call FltGetDestinationFileNameInformation because I can’t
tell if I’m being called for a destination filename anyway.


NTFSD is sponsored by OSR

For our schedule of debugging and file system seminars
(including our new fs mini-filter seminar) 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

At the last PlugFest MS was handing out sample code for the name callbacks to people who asked. Given that everyone completing creates is now supposed to implement these callbacks (and the code is basically the same for everyone) - I think it would be nice if this code were made available to everyone.

Thanks,
Matt

* Peter Scott wrote, On 29/10/09 16:24:

Sam Liddicott wrote:
> My simple attempt at a GenerateFileName seems to get involved in
> run-away recursion when I call:
>
> status = FltGetDestinationFileNameInformation(…,
> FLT_FILE_NAME_REQUEST_FROM_CURRENT_PROVIDER
> | FLT_FILE_NAME_NORMALIZED
> | FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP
> …

If you are doing this call in the GenerateFileName name provider call
back you cannot specify to call back into the current provider. Since it
will re-enter your provider and you will call it again … endlessly.

I wasn’t doing that there, I was doing that during set information IRP
so I could find out what the rename target was.

The should clear that flag from the name options in your code below
before calling into the Flt API.

Good tip! I’ll bet that’s it!

Also, be careful when querying for a normalized name and specifying to
query the current provider, this can also enter a reentrant loop due to
how MSFT implemented the normalization algorithm.

thanks

Sam

We are working on a sample that implements a simple name provider and it should be out pretty soon, so stay tuned.

Some other rules or general thoughts regarding the name generation callbacks are also (these only apply to name providers):

  1. do not request a normalized name from your name provider in preCreate -> this will most likely lead to recursion (depends on implementation though) and will use up most of the stack
  2. your name provider callbacks can and should call FltGetFileNameInformation, but they should not use FLT_FILE_NAME_REQUEST_FROM_CURRENT_PROVIDER in those callbacks (I’m referring strictly to the GenerateFileNameCallback and NormalizeNameComponentCallback functions)
  3. make sure to not cache the names you don’t intend to cache (if you change names of files on disk then make sure that file “FOO” that filter converts to “BAR” will not be cached as “FOO”). This is very important and I suggest you test heavily with two minifilters one above and one below your filter that query the names in all operations and then make sure the names are properly used.
  4. test with long and deep paths. More than 10 levels of directories.

Regards,
Alex.
This posting is provided “AS IS” with no warranties, and confers no rights.