Thanks again, Scott. The name provider has fixed the issue with ProcMon.
Unfortunately, even after changing my code to steal the SOP from the lower file object, I am still getting the same crash in CcFlushCache after the the file has been written to and the last IRP_MJ_CLOSE has been seen. I think it’s the SharedCacheMap member of the SOP although that doesn’t make sense now that I’m using the lower FO’s SOP. There must be something wrong with the upper FILE_OBJECT but I can’t see what. From what I have read, the links between the FILE_OBJECT and the Cache Manager are the SOP and PrivateCacheMap, both of which I initialise. My PostCreate code is below. Is there anything obvious I’m doing wrong? Any thoughts about the best way to go about diagnosing this?
FLT_POSTOP_CALLBACK_STATUS PostCreate(Inout PFLT_CALLBACK_DATA pData, In PCFLT_RELATED_OBJECTS pFltObjects, In_opt PVOID CompletionContext, In FLT_POST_OPERATION_FLAGS Flags)
{
NTSTATUS status = STATUS_SUCCESS;
FLT_POSTOP_CALLBACK_STATUS returnStatus = FLT_POSTOP_FINISHED_PROCESSING;
UNICODE_STRING strFullPath = { 0, 0, 0 };
UNICODE_STRING strSid = { 0, 0, 0 };
UNREFERENCED_PARAMETER(CompletionContext);
UNREFERENCED_PARAMETER(Flags);
// Ignore kernel activity
if (ExGetPreviousMode() == KernelMode || pData->RequestorMode == KernelMode)
{
return FLT_POSTOP_FINISHED_PROCESSING;
}
// Unconfigured?
if (!gFsFilterData.bConfigured)
{
return FLT_POSTOP_FINISHED_PROCESSING;
}
// Unsuccessful create attempt?
if (!NT_SUCCESS(pData->IoStatus.Status))
{
status = ConstructFullPath(pData, pFltObjects->Volume, &(pData->Iopb->TargetFileObject->FileName), NULL, &strFullPath);
if (!NT_SUCCESS(status))
{
return FLT_POSTOP_FINISHED_PROCESSING;
}
status = GetRequestSid(pData->Iopb->Parameters.Create.SecurityContext, &strSid);
if (NT_SUCCESS(status))
{
DbgPrint(“Status 0x%08x\n”, status);
goto cleanup;
}
// Match Rule
if (Rule_Find(&strSid, &strFullPath, AllowList, bDirectory, pData->Iopb->Parameters.Create.SecurityContext->DesiredAccess))
{
DbgPrint(“Post IRP_MJ_CREATE [%wZ] FO:%p FsC:%p\n”, &(pData->Iopb->TargetFileObject->FileName), pData->Iopb->TargetFileObject, pData->Iopb->TargetFileObject->FsContext);
ULONG createDisposition = (pData->Iopb->Parameters.Create.Options & 0xff000000) >> 24;
ULONG createOptions = pData->Iopb->Parameters.Create.Options & 0x00ffffff;
ULONG attributes = OBJ_KERNEL_HANDLE;
ULONG createFileFlags = IO_IGNORE_SHARE_ACCESS_CHECK;
if (createDisposition & FILE_OPEN_IF)
{
attributes |= OBJ_OPENIF;
}
if (!(pData->Iopb->OperationFlags & SL_CASE_SENSITIVE))
{
attributes |= OBJ_CASE_INSENSITIVE;
}
DbgPrint(“Disposition:0x%08x Options:0x%08x OperationFlags:0x%08x\n”, createDisposition, createOptions, (pData->Iopb->OperationFlags));
OBJECT_ATTRIBUTES ObjectAttributes;
InitializeObjectAttributes(&ObjectAttributes, &strFullPath, attributes, NULL, NULL);
HANDLE hFile;
IO_STATUS_BLOCK IoStatusBlock;
PFILE_OBJECT pShadowFileObject;
status = FltCreateFileEx(
pFltObjects->Filter,
pFltObjects->Instance,
&hFile,
&pShadowFileObject,
pData->Iopb->Parameters.Create.SecurityContext->DesiredAccess,
&ObjectAttributes,
&IoStatusBlock,
&(pData->Iopb->Parameters.Create.AllocationSize),
pData->Iopb->Parameters.Create.FileAttributes,
pData->Iopb->Parameters.Create.ShareAccess,
createDisposition,
createOptions,
pData->Iopb->Parameters.Create.EaBuffer,
pData->Iopb->Parameters.Create.EaLength,
createFileFlags);
if (NT_SUCCESS(status))
{
DbgPrint(“pShadowFileObject %p\n”, pShadowFileObject);
PFSRTL_COMMON_FCB_HEADER pFsContext = (PFSRTL_COMMON_FCB_HEADER)pShadowFileObject->FsContext;
PFSRTL_ADVANCED_FCB_HEADER pShadowFsContext = NULL;
PSECTION_OBJECT_POINTERS pSectionObjectPointer = NULL;
PSTREAM_CONTEXT pStreamContext = NULL;
BOOLEAN bCreateContext = !NT_SUCCESS(FltGetStreamContext(pFltObjects->Instance, pFltObjects->FileObject, &pStreamContext));
// Create a context if necessary
if (bCreateContext)
{
pShadowFsContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(FSRTL_ADVANCED_FCB_HEADER), FSFILTER_TAG);
RtlZeroMemory(pShadowFsContext, sizeof(FSRTL_ADVANCED_FCB_HEADER));
PFAST_MUTEX pMutext = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), FSFILTER_TAG);
ExInitializeFastMutex(pMutext);
PVOID pFileContextSupportPointer = NULL;
FsRtlSetupAdvancedHeaderEx(pShadowFsContext, pMutext, pFileContextSupportPointer);
DbgPrint(“Creating FsContext %p\n”, pShadowFsContext);
pShadowFsContext->Resource = ExAllocatePoolWithTag(NonPagedPool, sizeof(ERESOURCE), FSFILTER_TAG);
pShadowFsContext->PagingIoResource = ExAllocatePoolWithTag(NonPagedPool, sizeof(ERESOURCE), FSFILTER_TAG);
ExInitializeResourceLite(pShadowFsContext->Resource);
ExInitializeResourceLite(pShadowFsContext->PagingIoResource);
pShadowFsContext->AllocationSize = pFsContext->AllocationSize;
pShadowFsContext->FileSize = pFsContext->FileSize;
pShadowFsContext->ValidDataLength = pFsContext->ValidDataLength;
pSectionObjectPointer = pShadowFileObject->SectionObjectPointer;
}
else
{
pShadowFsContext = pStreamContext->pShadowFsContext;
pSectionObjectPointer = pStreamContext->pSectionObjectPointer;
FltReleaseContext(pStreamContext);
}
DbgPrint(“Setting FsContext %p\n”, pShadowFsContext);
DbgPrint(“SectionObjectPointers %p\n”, pSectionObjectPointer);
pData->Iopb->TargetFileObject->FsContext = pShadowFsContext;
pData->Iopb->TargetFileObject->SectionObjectPointer = pSectionObjectPointer;
pData->Iopb->TargetFileObject->Flags = pShadowFileObject->Flags;
pData->Iopb->TargetFileObject->PrivateCacheMap = NULL;
pData->IoStatus = IoStatusBlock;
FltSetCallbackDataDirty(pData);
// Add a STREAMHANDLE context to the patched up FILE_OBJECT so we can clean up the new FILE_OBJECT when it is deleted
PSTREAM_HANDLE_CONTEXT pStreamHandleContext;
status = FltAllocateContext(pFltObjects->Filter, FLT_STREAMHANDLE_CONTEXT, sizeof(STREAM_HANDLE_CONTEXT), NonPagedPool, &pStreamHandleContext);
if (NT_SUCCESS(status))
{
// Set the context on the file object
status = FltSetStreamHandleContext(pFltObjects->Instance, pFltObjects->FileObject, FLT_SET_CONTEXT_KEEP_IF_EXISTS, pStreamHandleContext, NULL);
if (NT_SUCCESS(status))
{
// Initialise the context
pStreamHandleContext->pShadowFileObject = pShadowFileObject;
pStreamHandleContext->hFile = hFile;
}
FltReleaseContext(pStreamHandleContext);
}
if (bCreateContext)
{
// Add a STREAM context to the patched up FILE_OBJECT so we can clean up the new FsContent when the last reference is deleted
status = FltAllocateContext(pFltObjects->Filter, FLT_STREAM_CONTEXT, sizeof(STREAM_CONTEXT), NonPagedPool, &pStreamContext);
if (NT_SUCCESS(status))
{
// Set the context on the file object
status = FltSetStreamContext(pFltObjects->Instance, pFltObjects->FileObject, FLT_SET_CONTEXT_KEEP_IF_EXISTS, pStreamContext, NULL);
if (NT_SUCCESS(status))
{
// Initialise the context
pStreamContext->pShadowFsContext = pShadowFsContext;
pStreamContext->pSectionObjectPointer = pSectionObjectPointer;
}
FltReleaseContext(pStreamContext);
}
}
}
else
{
DbgPrint(“Status 0x%08x\n”, status);
pData->IoStatus.Status = status;
}
}
}
cleanup:
if (strFullPath.Buffer)
{
ExFreePoolWithTag(strFullPath.Buffer, FSFILTER_TAG);
}
RtlFreeUnicodeString(&strSid);
return returnStatus;
}