Reentrancy problem.

I made a function(including ZwReadFile internally) that read contents of
specification file(for example, c:\test.txt or d:\test.txt).
By the way, If i try to call this function in the
FilemonHookRoutine(Dispatch-Routine of “FileMon of sysinternlas.com”),
BSOD appears.
The problem is reentrancy.

My source code is following.


FilemonHookRoutine of Filemon(sysinternals.com)

NTSTATUS
FilemonHookRoutine(
PDEVICE_OBJECT HookDevice,
IN PIRP Irp
)
{
PIO_STACK_LOCATION currentIrpStack =
IoGetCurrentIrpStackLocation(Irp);
PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
PMOVE_FILE_DATA moveFile;
PQUERY_DIRECTORY queryDirectory;
PFILE_OBJECT FileObject;
PHOOK_EXTENSION hookExt;
LARGE_INTEGER dateTime;
LARGE_INTEGER perfTime;
PCHAR fullPathName = NULL;
BOOLEAN hookCompletion, createPath;
CHAR controlCodeBuffer[ERRORLEN];
CHAR attributeString[ERRORLEN];
CHAR optionString[ERRORLEN];
CHAR name[PROCNAMELEN];
ULONG i;
ANSI_STRING directoryFilter;
PCHAR queryFilter;
ULONG seqNum;
KIRQL oldirql;
// Extract the file object from the IRP
FileObject = currentIrpStack->FileObject;
// Point at the device extension, which contains information on which
// file system this IRP is headed for
hookExt = HookDevice->DeviceExtension;
// We note open cases so that when we query the file name
// we don’t ask the file system for the name (since it won’t
// have seen the file object yet).
if( currentIrpStack->MajorFunction == IRP_MJ_CREATE ||
currentIrpStack->MajorFunction == IRP_MJ_CREATE_NAMED_PIPE ||
currentIrpStack->MajorFunction == IRP_MJ_CREATE_MAILSLOT ) {
// Clear any existing fileobject/name association stored in the
// hash table
FilemonFreeHashEntry( FileObject );
createPath = TRUE;
} else if( currentIrpStack->MajorFunction == IRP_MJ_CLOSE ) {
// We treat close as a special case of create for name querying
// since calling into NTFS during a close can result in a
deadlock.
createPath = TRUE;
} else if( currentIrpStack->MajorFunction == IRP_MJ_CLEANUP &&
FileObject->Flags & FO_STREAM_FILE ) {
// Treat cleanup of stream file objects as special create case,
because
// querying them causes NTFS to screwup on NT 4
//
createPath = TRUE;
} else {
createPath = FALSE;
}
// Allocate a buffer and get the name only if we have to
if( FilterOn && hookExt->Hooked ) {

GETPATHNAME( createPath );
}
// Only log it if it passes the filter
if( hookExt->Hooked && fullPathName ) {
// If measuring absolute time go and get the timestamp.
KeQuerySystemTime( &dateTime );
perfTime = KeQueryPerformanceCounter( NULL );
// We want to watch this IRP complete
seqNum = (ULONG) -1;
hookCompletion = FALSE;
// Determine what function we’re dealing with
FilemonGetProcess( name );
switch( currentIrpStack->MajorFunction ) {
case IRP_MJ_CREATE:

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

ReadFunction(); // call a function(read contents of a file)

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

hookCompletion = LogRecord( TRUE, &seqNum,
&dateTime, NULL,
“%s\tIRP_MJ_CREATE\t%s\tAttributes:
%s Options: %s”,
name, fullPathName,
CreateAttributesString(
currentIrpStack->Parameters.Create.FileAttributes,

attributeString ),
CreateOptionsString(
currentIrpStack->Parameters.Create.Options,
optionString ));

if( currentIrpStack->Parameters.Create.Options &
FILE_OPEN_BY_FILE_ID ) {
FilemonFreeHashEntry( FileObject );
}
break;
default:
hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
“%s\t*UNKNOWN* 0x%X\t\t”, name,
currentIrpStack->MajorFunction );
break;
}
} else {
// We don’t care about this IRP’s completion
hookCompletion = FALSE;
// Do name processing for the sake of keeping the hash table
current
switch( currentIrpStack->MajorFunction ) {
case IRP_MJ_CLOSE:
// This fileobject/name association can be discarded now.
FilemonFreeHashEntry( FileObject );
break;
}
}
// Free the buffer if we have one
if( fullPathName && fullPathName != InsufficientResources ) {
ExFreeToNPagedLookasideList( &FullPathLookaside, fullPathName );
}
*nextIrpStack = *currentIrpStack;
#if DBG
KeAcquireSpinLock( &CountMutex, &oldirql );
#endif
if( !UnloadInProgress && hookCompletion ) {
#if DBG
FilemonDriver->DriverUnload = NULL;
OutstandingIRPCount++;
DbgPrint((“+%d: %x\n”, OutstandingIRPCount, Irp ));; #endif // DBG
currentIrpStack->Parameters.Read.ByteOffset = perfTime; #if
defined(IA64)
IoSetCompletionRoutine( Irp, FilemonHookDone, (PVOID) (ULONG_PTR)
seqNum, TRUE, TRUE, TRUE ); #else
IoSetCompletionRoutine( Irp, FilemonHookDone, (PVOID) seqNum, TRUE,
TRUE, TRUE ); #endif
} else {
// Set no completion routine
IoSetCompletionRoutine( Irp, FilemonHookDone, NULL, FALSE, FALSE,
FALSE );
}
#if DBG
KeReleaseSpinLock( &CountMutex, oldirql );
#endif
// Return the results of the call to the caller
return IoCallDriver( hookExt->FileSystem, Irp );
}

ReadFunction

VOID ReadFunction()
{
IO_STATUS_BLOCK ioStatus;
HANDLE ntFileHandle;
OBJECT_ATTRIBUTES objectAttributes;
UNICODE_STRING fileNameUnicodeString;
WCHAR filename =
L"\DosDevices\C:\test.txt";
NTSTATUS ntStatus;
FILE_STANDARD_INFORMATION eof;
char *FileBuffer = 0;
ULONG FileSize = 0;
RtlInitUnicodeString( &fileNameUnicodeString, filename );
InitializeObjectAttributes( &objectAttributes,
&fileNameUnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL );
ntStatus = ZwOpenFile( &ntFileHandle,
SYNCHRONIZE | GENERIC_READ,
&objectAttributes,
&ioStatus,
0,
FILE_SYNCHRONOUS_IO_ALERT );
ntStatus = ZwQueryInformationFile(ntFileHandle, &ioStatus,
(void*)&eof, sizeof(eof), FileStandardInformation);
FileSize=eof.EndOfFile.LowPart;

FileBuffer=(char*)ExAllocatePool(NonPagedPool,eof.EndOfFile.LowPart+1);
((char*)(FileBuffer))[FileSize]=0; // make the buffer ASCIIZ
ZwReadFile(ntFileHandle,
NULL,
NULL,
NULL,
&ioStatus,
FileBuffer,
FileSize,
NULL,
NULL);
DbgPrint((“*****File Content = %s File Size = %d\n”, FileBuffer,
FileSize));
ZwClose(ntFileHandle);
ExFreePool(FileBuffer); // F should be malloc-ed!!
return 0;
}

End of source code.

How can i solve this problem?

Thanks for any suggestions!
Sincerely!

Chang Sung, Jung.

Any file filter re-entrancy issue involving calls to Zw* functions can
be solved by rolling your own IRP and sending it directly down to the
lower device. This is relatively easy to do (except for
ZwCreate/OpenFile), and code to do this can be found in the ntfsd
archives.

  • Nicholas Ryan

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Chang
Sung, Jung.
Sent: Friday, October 18, 2002 8:37 PM
To: File Systems Developers
Subject: [ntfsd] Reentrancy problem.

I made a function(including ZwReadFile internally) that read
contents of specification file(for example, c:\test.txt or
d:\test.txt). By the way, If i try to call this function in
the FilemonHookRoutine(Dispatch-Routine of “FileMon of
sysinternlas.com”), BSOD appears. The problem is reentrancy.

My source code is following.



FilemonHookRoutine of Filemon(sysinternals.com)


NTSTATUS
FilemonHookRoutine(
PDEVICE_OBJECT HookDevice,
IN PIRP Irp
)
{
PIO_STACK_LOCATION currentIrpStack =
IoGetCurrentIrpStackLocation(Irp);
PIO_STACK_LOCATION nextIrpStack =
IoGetNextIrpStackLocation(Irp);
PMOVE_FILE_DATA moveFile;
PQUERY_DIRECTORY queryDirectory;
PFILE_OBJECT FileObject;
PHOOK_EXTENSION hookExt;
LARGE_INTEGER dateTime;
LARGE_INTEGER perfTime;
PCHAR fullPathName = NULL;
BOOLEAN hookCompletion, createPath;
CHAR controlCodeBuffer[ERRORLEN];
CHAR attributeString[ERRORLEN];
CHAR optionString[ERRORLEN];
CHAR name[PROCNAMELEN];
ULONG i;
ANSI_STRING directoryFilter;
PCHAR queryFilter;
ULONG seqNum;
KIRQL oldirql;
// Extract the file object from the IRP
FileObject = currentIrpStack->FileObject;
// Point at the device extension, which contains
information on which
// file system this IRP is headed for
hookExt = HookDevice->DeviceExtension;
// We note open cases so that when we query the file name
// we don’t ask the file system for the name (since it won’t
// have seen the file object yet).
if( currentIrpStack->MajorFunction == IRP_MJ_CREATE ||
currentIrpStack->MajorFunction == IRP_MJ_CREATE_NAMED_PIPE ||
currentIrpStack->MajorFunction == IRP_MJ_CREATE_MAILSLOT ) {
// Clear any existing fileobject/name association
stored in the
// hash table
FilemonFreeHashEntry( FileObject );
createPath = TRUE;
} else if( currentIrpStack->MajorFunction == IRP_MJ_CLOSE ) {
// We treat close as a special case of create for
name querying
// since calling into NTFS during a close can result
in a deadlock.
createPath = TRUE;
} else if( currentIrpStack->MajorFunction == IRP_MJ_CLEANUP &&
FileObject->Flags & FO_STREAM_FILE ) {
// Treat cleanup of stream file objects as special
create case, because
// querying them causes NTFS to screwup on NT 4
//
createPath = TRUE;
} else {
createPath = FALSE;
}
// Allocate a buffer and get the name only if we have to
if( FilterOn && hookExt->Hooked ) {

GETPATHNAME( createPath );
}
// Only log it if it passes the filter
if( hookExt->Hooked && fullPathName ) {
// If measuring absolute time go and get the timestamp.
KeQuerySystemTime( &dateTime );
perfTime = KeQueryPerformanceCounter( NULL );
// We want to watch this IRP complete
seqNum = (ULONG) -1;
hookCompletion = FALSE;
// Determine what function we’re dealing with
FilemonGetProcess( name );
switch( currentIrpStack->MajorFunction ) {
case IRP_MJ_CREATE:

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++

ReadFunction(); // call a function(read contents of a file)

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++

hookCompletion = LogRecord( TRUE, &seqNum,
&dateTime, NULL,
“%s\tIRP_MJ_CREATE\t%s\tAttributes:
%s Options: %s”,
name, fullPathName,
CreateAttributesString(
currentIrpStack->Parameters.Create.FileAttributes,

attributeString ),
CreateOptionsString(
currentIrpStack->Parameters.Create.Options,
optionString ));

if( currentIrpStack->Parameters.Create.Options &
FILE_OPEN_BY_FILE_ID ) {
FilemonFreeHashEntry( FileObject );
}
break;
default:
hookCompletion = LogRecord( TRUE, &seqNum,
&dateTime, NULL,
“%s\t*UNKNOWN* 0x%X\t\t”, name,
currentIrpStack->MajorFunction );
break;
}
} else {
// We don’t care about this IRP’s completion
hookCompletion = FALSE;
// Do name processing for the sake of keeping the
hash table current
switch( currentIrpStack->MajorFunction ) {
case IRP_MJ_CLOSE:
// This fileobject/name association can be discarded now.
FilemonFreeHashEntry( FileObject );
break;
}
}
// Free the buffer if we have one
if( fullPathName && fullPathName != InsufficientResources ) {
ExFreeToNPagedLookasideList( &FullPathLookaside,
fullPathName );
}
*nextIrpStack = *currentIrpStack;
#if DBG
KeAcquireSpinLock( &CountMutex, &oldirql );
#endif
if( !UnloadInProgress && hookCompletion ) {
#if DBG
FilemonDriver->DriverUnload = NULL;
OutstandingIRPCount++;
DbgPrint((“+%d: %x\n”, OutstandingIRPCount, Irp ));;
#endif // DBG
currentIrpStack->Parameters.Read.ByteOffset = perfTime; #if
defined(IA64)
IoSetCompletionRoutine( Irp, FilemonHookDone, (PVOID)
(ULONG_PTR) seqNum, TRUE, TRUE, TRUE ); #else
IoSetCompletionRoutine( Irp, FilemonHookDone, (PVOID)
seqNum, TRUE, TRUE, TRUE ); #endif
} else {
// Set no completion routine
IoSetCompletionRoutine( Irp, FilemonHookDone, NULL,
FALSE, FALSE, FALSE );
}
#if DBG
KeReleaseSpinLock( &CountMutex, oldirql );
#endif
// Return the results of the call to the caller
return IoCallDriver( hookExt->FileSystem, Irp );
}


ReadFunction


VOID ReadFunction()
{
IO_STATUS_BLOCK ioStatus;
HANDLE ntFileHandle;
OBJECT_ATTRIBUTES objectAttributes;
UNICODE_STRING fileNameUnicodeString;
WCHAR filename =
L"\DosDevices\C:\test.txt";
NTSTATUS ntStatus;
FILE_STANDARD_INFORMATION eof;
char *FileBuffer = 0;
ULONG FileSize = 0;
RtlInitUnicodeString( &fileNameUnicodeString, filename );
InitializeObjectAttributes( &objectAttributes,
&fileNameUnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL );
ntStatus = ZwOpenFile( &ntFileHandle,
SYNCHRONIZE | GENERIC_READ,
&objectAttributes,
&ioStatus,
0,
FILE_SYNCHRONOUS_IO_ALERT );
ntStatus = ZwQueryInformationFile(ntFileHandle,
&ioStatus, (void*)&eof, sizeof(eof), FileStandardInformation);
FileSize=eof.EndOfFile.LowPart;

FileBuffer=(char*)ExAllocatePool(NonPagedPool,eof.EndOfFile.Lo
wPart+1);
((char*)(FileBuffer))[FileSize]=0; // make the buffer ASCIIZ
ZwReadFile(ntFileHandle,
NULL,
NULL,
NULL,
&ioStatus,
FileBuffer,
FileSize,
NULL,
NULL);
DbgPrint((“*****File Content = %s File Size = %d\n”,
FileBuffer, FileSize));
ZwClose(ntFileHandle);
ExFreePool(FileBuffer); // F should be malloc-ed!!
return 0;
}


End of source code.


How can i solve this problem?

Thanks for any suggestions!
Sincerely!

Chang Sung, Jung.


You are currently subscribed to ntfsd as: xxxxx@nryan.com
To unsubscribe send a blank email to %%email.unsub%%