Section sync in a mini-filter

Is there any discussion or documentation on how IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION and IRP_MJ_RELEASE_FOR_SECTION_SYNCHRONIZATION can be filtered in a mini-filter? I am totally unclear about what can be returned.

My filter driver is a bit of a hybrid. It layers over a real file system, but also “virtualizes” additional (read-only) files on specific paths where those files do not actually exist. The filter driver implements all the necessary IRPs to allow access to this virtual content.

The design is 12-13 years old - initially as a legacy filter driver, and about 5 years ago re-worked as a mini-filter. And it generally works well.

But I am now seeing an occasional thread lock-up, which I strongly suspect comes from the implementation of the IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION pre-op on a virtual file. I can find no examples of this usage anywhere and very little documentation.

My current implementation for the pre-op is:

FLT_PREOP_CALLBACK_STATUS
iOraFltFilterSectionSyncPreOp(
IN OUT PFLT_CALLBACK_DATA Data,
IN PCFLT_RELATED_OBJECTS FltObjects,
OUT PVOID *CompletionContext
)
{
PFLT_CONTEXT pContext;

UNREFERENCED_PARAMETER( CompletionContext );

// Is this one of our file objects?
if ( FltGetStreamHandleContext( FltObjects->Instance, FltObjects->FileObject, &pContext ) == STATUS_SUCCESS )
{
// Get our own FCB that contains the resource to acquire
icpt_open_fcb* fcb = GetFcbFromStreamContext(pContext);
FltReleaseContext( pContext );

if (Data->Iopb->MajorFunction == IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION)
{
TRACE_PRINT1( “Section Sync Acquire %08x\n”, h ) ;

ExAcquireResourceExclusiveLite( &fcb->resource, TRUE );

Data->IoStatus.Status =
Data->Iopb->Parameters.AcquireForSectionSynchronization.SyncType == SyncTypeCreateSection ?
STATUS_FILE_LOCKED_WITH_ONLY_READERS : STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY;
}
else
{
TRACE_PRINT1( “Section Sync Release %08x\n”, h ) ;

if ( ExIsResourceAcquiredExclusiveLite( &fcb->resource ) )
{
ExReleaseResourceForThreadLite ( &fcb->resource, ExGetCurrentResourceThread() ) ;

Data->IoStatus.Status = STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY;
}
}
Data->IoStatus.Information = 0;

return FLT_PREOP_COMPLETE;
}

return FLT_PREOP_SUCCESS_NO_CALLBACK;
}

Is a mini-filter allowed to complete these operations like this? Would these be the correct status codes? Am I obliged to pass down the operation as far as the underlying driver? (discussion of FsRtlRegisterFileSystemFilterCallbacks implied this may be necessary for a legacy filter).

The eventual lock-up is on the next IRP_MJ_READ pre-op for virtual content *following* the IRP_MJ_RELEASE_FOR_SECTION_SYNCHRONIZATION, where the filter driver calls a ZwReadFile on a totally diferent (internal real file) kernel handle:
nt!KiSwapContext+0x26 (FPO: [Uses EBP] [0,0,4])
nt!KiSwapThread+0x266
nt!KiCommitThreadWait+0x1df
nt!KeWaitForSingleObject+0x393
nt!IopSynchronousServiceTail+0x270
nt!NtReadFile+0x644
nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ 8c23f59c)
nt!ZwReadFile+0x11 (FPO: [9,0,0])
grFilter!iOraFltUtilReadFile+0x28

All pointers gratefully received. Thanks

Brian

Hi Brian,

Have you confirmed you don’t have an APC deadlock (“!apc” in the kernel debugger)? I’d also suggest taking the IRP from the stuck thread (“!thread” to get the list and then “!irp ” from the outstanding irps for this thread.) If the I/O is completed, then look at the thread itself (“dt nt!_KTHREAD ” - look for the APC disable fields.) If the I/O is not complete, you’ll need to dig and figure out where that IRP is being processed (likely in a different thread context.)

Tony
OSR

Thanks Tony.

APCs were certainly *part* of the problem and the hang went away when I replaced the ZwReadFile with an equivalent FltReadFile. I also replaced the Ex… calls on the resource with the equivalent Flt… calls.

The copy still fails now - though no longer hangs. Explorer reports a 0x80070057 (presumably Win32 Parameter Error) error code on accessing one DLL file only, which is the only file which appears to be being memory mapped!

I am still concerned about the questions in the original post. The pre-op is returning one of STATUS_FILE_LOCKED_WITH_ONLY_READERS or STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY in Data->IoStatus.Status and a result of FLT_PREOP_COMPLETE. A Process Monitor trace of the Explorer copy shows that CreateFileMapping call is returning 0x126 (the value of STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY). This is worrying, as it suggests that these are NOT the values to be returned.

The DDK source samples do not illustrate any filtering of these pseudo-IRPs. FAT and CDFS have an Acquire which *does* return these two values. But Release is defined as returning void - so it is not clear what a pre-op filter should return.

All-in-all, I am not sure what a mini-filter should do with IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION and
IRP_MJ_RELEASE_FOR_SECTION_SYNCHRONIZATION. So I would welcome any guidance.

Brian

Just for closure, I now believe that I have resolved my recent problems.

Although a switch from ZwReadFile to FltReadFile made the deadlock go away, I got failures when I enabled the Driver Vertifier (I know! I know! it should have been on all the time - but as it’s months since I last did driver work, I forgot!). It turns out that FltReadFile also requires APCs to be enabled, though the documentation makes no mention of this requirement. So this was easily addressed by moving my IO to a worker thread when APCs are disabled.

I am not aware of any problems now with IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION and
IRP_MJ_RELEASE_FOR_SECTION_SYNCHRONIZATION filtering, though I am still concerned about the lack of documenation or sample. So I could still have missed something.

And my 0x80070057 seems to be a Win32 Explorer issue. It is suspicious that it only happens with one file alone - which has a Win32 path length of 254 characters starting with the X:\ drive letter. So it’s not a driver issue.

Thanks for the APC suggestion - that sent me in the right direction.

Brian