FltReadFile Issues

Hey. Im trying to block image mappings based on hash, I filter on IRP_MJ_AQUIRE_SECTION_SYNCHRONIZATION . Here’s my preop routine

FLT_PREOP_CALLBACK_STATUS
RattleEyePreOperation(
    _Inout_ PFLT_CALLBACK_DATA Data,
    _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _Flt_CompletionContext_Outptr_ PVOID* CompletionContext
)

{
    NTSTATUS status;
    ULONG MappedImageHash;
    ULONG BytesRead = 0;
    FILE_STANDARD_INFORMATION FileInfo;
    PVOID DiskContent;
    LARGE_INTEGER ByteOffset;
    ByteOffset.QuadPart = 0;
    UNREFERENCED_PARAMETER(CompletionContext);

    // get file size
    status = FltQueryInformationFile(FltObjects->Instance, FltObjects->FileObject, &FileInfo, sizeof(FileInfo), FileStandardInformation, NULL);
    if (!NT_SUCCESS(status))
        return FLT_PREOP_SUCCESS_NO_CALLBACK;
    if (&FltObjects->FileObject->FileName && FltObjects->FileObject)
    {
        DiskContent = FltAllocatePoolAlignedWithTag(FltObjects->Instance, NonPagedPool, FileInfo.EndOfFile.QuadPart, TAG);
        if (!DiskContent)
            return FLT_PREOP_SUCCESS_NO_CALLBACK;
        status = FltReadFile(FltObjects->Instance, FltObjects->FileObject, &ByteOffset, FileInfo.EndOfFile.QuadPart, DiskContent, FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET | FLTFL_IO_OPERATION_NON_CACHED, &BytesRead, NULL, NULL);
        if (!NT_SUCCESS(status))
        {
            FltFreePoolAlignedWithTag(FltObjects->Instance, DiskContent, TAG);
            return FLT_PREOP_SUCCESS_NO_CALLBACK;
        }
        MappedImageHash = Djb2HashFile(DiskContent, (SIZE_T)FileInfo.EndOfFile.QuadPart);

        if (MappedImageHash == 0x389ae136)
        {
            DbgPrint("[*] Blocking loading of image %wZ !\n", FltObjects->FileObject->FileName);
            FltFreePoolAlignedWithTag(FltObjects->Instance, DiskContent, TAG);
            Data->IoStatus.Status = STATUS_INVALID_IMAGE_HASH;
            return FLT_PREOP_COMPLETE;
        }
            FltFreePoolAlignedWithTag(FltObjects->Instance, DiskContent, TAG);
    }
    return FLT_PREOP_SUCCESS_NO_CALLBACK;
}

I get a BSOD after a few seconds or minutes
EXCEPTION_RECORD: fffffe0581b8dc48 – (.exr 0xfffffe0581b8dc48)
ExceptionAddress: fffff8040b189bae (Ntfs!NtfsAcquirePagingShared+0x000000000000004a)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 0000000000000000
Parameter[1]: 0000000000000010
Attempt to read from address 0000000000000010

anyone has a clue what did I do wrong here ?

Stop code often being CACHE_MANAGER

What’s the stack?

My instinct is that you are confusing Cc and NTFS by causing some sort of reentrancy. Possibly creating a section while creating a section? I know your io is non cached but NTFS is at liberty to do what it wants when it gets told to do a read and that might involve refreshing the SOP.

I’d also poke around for transactions (my go to blame point for ‘that’s weird’).

@rod_widdowson said:
What’s the stack?

My instinct is that you are confusing Cc and NTFS by causing some sort of reentrancy. Possibly creating a section while creating a section? I know your io is non cached but NTFS is at liberty to do what it wants when it gets told to do a read and that might involve refreshing the SOP.

I’d also poke around for transactions (my go to blame point for ‘that’s weird’).
The Stack: ( It works if I ignore requests from kernel mode… still curious what the issue is tho)

00 fffff8057ad17f82 : ffffbf86e6d44430 fffff8057ab7df60 0000000000000000 0000000000000000 : nt!DbgBreakPointWithStatus 01 fffff8057ad17566 : 0000000000000003 ffffbf86e6d44430 fffff8057ac14a40 0000000000000034 : nt!KiBugCheckDebugBreak+0x12
02 fffff8057abfd747 : ffffffc3ee0071e3 ffffbf86e6d45760 fffff8057a871f40 ffffbf86e6d41000 : nt!KeBugCheck2+0x946 03 fffff8057ac1a5db : 0000000000000034 0000000000051384 ffffbf86e6d45aa8 ffffbf86e6d452e0 : nt!KeBugCheckEx+0x107
04 fffff8057abd01bf : ffffbf8600000003 fffff8057a871f50 ffffbf86e6d41000 ffffbf86e6d47000 : nt!CcCachemapUninitWorkerThread$filt$0+0x42 05 fffff8057abf927e : fffff8057a871f50 ffffbf86e6d45aa8 ffffbf86e6d46a90 ffffbf86e6d450e0 : nt!_C_specific_handler+0x9f
06 fffff8057ac07d2f : fffff8057a8d3c2c ffffbf86e6d450d0 fffff8057abf9214 fffff8057ab02fe1 : nt!_GSHandlerCheck_SEH+0x6a 07 fffff8057aaca3c7 : ffffbf86e6d450d0 0000000000000000 ffffbf86e6d46a90 fffff8057ab02fe1 : nt!RtlpExecuteHandlerForException+0xf
08 fffff8057aac94e6 : ffffbf86e6d45aa8 ffffbf86e6d457e0 ffffbf86e6d45aa8 ffffaf8294458d00 : nt!RtlDispatchException+0x297 09 fffff8057ac1186c : 0000000000001000 ffffbf86e6d45b50 ffff800000000000 0000000000000000 : nt!KiDispatchException+0x186
0a fffff8057ac0d2bd : 0000000000000003 0000000000000000 000004e8fffffb30 000004d0fffffb30 : nt!KiExceptionDispatch+0x12c 0b fffff8057f8d090e : ffffe4879aa4d6d0 fffff8057aaa3b85 8000000000000000 0000000000000000 : nt!KiPageFault+0x43d
0c fffff8057f8c7964 : 0000000000000000 ffffbf86e6d45f60 ffffe4879ab03100 0000000000000000 : Ntfs!NtfsAcquirePagingResourceExclusive+0x36 0d fffff8057f8c926c : ffffe487a023e4e8 ffffe487a3bf2a20 ffffe48710000000 0000000000000000 : Ntfs!NtfsCommonRead+0xf44
0e fffff8057aa10665 : ffffe4879ff7fa20 ffffe487a3bf2a20 ffffe487a3bf2a20 ffffe4879a9a1d60 : Ntfs!NtfsFsdRead+0x1fc 0f fffff805796c710f : ffffe4879ff7fa20 ffffbf86e6d460d0 0000000000000000 fffff805796c5f7a : nt!IofCallDriver+0x55
10 fffff805796c879d : ffffbf86e6d460d0 ffffe487a24d5b18 ffffe4879ff7fb08 ffffe4879ff7fb08 : FLTMGR!FltpLegacyProcessingAfterPreCallbacksCompleted+0x28f 11 fffff805796cf3ce : ffffe4879ff7fa20 ffffe4879ff7fb08 0000000000000000 ffffe48798103f70 : FLTMGR!FltPerformSynchronousIo+0x3dd
12 fffff805796c1111 : 0000000072746579 0000000010000000 ffffab7200000000 ffffab55b921e920 : FLTMGR!FltReadFileEx+0xe2ae 13 fffff805962210f9 : ffffbf86e6d463e8 ffffe4879fe8fc10 ffffbf86e6d463e8 0000000000000000 : FLTMGR!FltReadFile+0x51
14 fffff805796c64cc : ffffe487a0158a20 0000000000000000 ffffe487a0158b08 0000000000000008 : RattleEye+0x10f9 15 fffff805796c2844 : 0000000000000000 00000000000000ff ffffbf86e6d46500 ffffbf8600000000 : FLTMGR!FltpPerformPreCallbacksWorker+0x36c
16 fffff8057aa64e47 : ffffbf86e6d47000 ffffe4879ab03180 ffffbf86e6d41000 ffffaf8294458ef0 : FLTMGR!FltpPreFsFilterOperation+0x184 17 fffff8057ae21d31 : fffff805796c8eb0 0000000000000000 ffffbf86e6d46890 fffff805796c26c0 : nt!FsFilterPerformCallbacks+0xe7
18 fffff8057ae21a27 : ffffe4879fcaf010 fffff8057aa06d7a ffffe4879fcaf010 ffffbf8600000000 : nt!FsRtlAcquireFileExclusiveCommon+0x121 19 fffff8057aa57bcb : ffffe487a4831170 7fffffff00000000 ffffe48700000000 ffffe487987d2b00 : nt!FsRtlAcquireFileExclusive+0x17
1a fffff8057ab057b1 : ffffe487a581d8a0 0000000000000000 ffffe487987d2b00 ffffe48700000000 : nt!CcWriteBehindInternal+0x31b 1b fffff8057ab02fe1 : ffffe48798715080 ffffe48798674560 ffffe487a581d8a0 ffffe4879c565000 : nt!CcWriteBehind+0x91
1c fffff8057aa50545 : ffffe48798715080 ffffe48798702ab0 ffffe48798674560 0000000000000000 : nt!CcCachemapUninitWorkerThread+0xf1 1d fffff8057ab0e6f5 : ffffe48798715080 0000000000000080 ffffe4879867b040 0000000000000000 : nt!ExpWorkerThread+0x105
1e fffff8057ac06278 : ffff9981eb1a0180 ffffe48798715080 fffff8057ab0e6a0 0000000000000000 : nt!PspSystemThreadStartup+0x55 1f 0000000000000000 : ffffbf86e6d47000 ffffbf86e6d41000 0000000000000000 0000000000000000 : nt!KiStartSystemThread+0x28

The cache is dirty, so the section has already been created. When you issue the non cached read you are therefor causing a flush and NTFS is making some weird assumption).

You are working well outside the bounds of “normal” at this stage. The Cache Manager is subtle and quick to anger.

@rod_widdowson said:
The cache is dirty, so the section has already been created. When you issue the non cached read you are therefor causing a flush and NTFS is making some weird assumption).

You are working well outside the bounds of “normal” at this stage. The Cache Manager is subtle and quick to anger.

hmm probably a noob question here but this confused me a bit : when does the IRP_MJ_AQUIRE_FOR_SECTION_SYNCHRONIZATION pre operation gets called ? I thought it’s for creation of shareable section objects but seems like as you said it was triggered after the section has already been created?

I Thought it’s for creation of shareable section objects
Actually - it rather looks like it is being called to tear down the (non existent) section.

Certainly NTFS doesn’t like you doing IO at that stage,

@rod_widdowson said:

I Thought it’s for creation of shareable section objects
Actually - it rather looks like it is being called to tear down the (non existent) section.

Certainly NTFS doesn’t like you doing IO at that stage,

It works by removing the the noncached flag in the FltReadFile. I’m pretty sure it’s called for creation of section objects since BattleEye (anti cheat) is blocking image loads this way and It indeed works. maybe its called under other conditions which is what im not sure about