Create section in pre-cleanup, use in post-cleanup

A colleague and I need to do scans on files when they are closed (IRP_MJ_CLEANUP). The scanner is in user mode, and in other places we've been using FltCreateSectionForDataScan with SECTION_MAP_READ.

Creating the section will fail (or just not work) in some cases, for example SMB without FILE_READ_DATA permissions. In these cases, we'll try to reopen the file in post-cleanup, create a section, and issue the scan from there. So, it would be good to always issue the scan from post-cleanup.

But -- we can't create the section in post-cleanup. So, we're considering calling FltCreateSectionForDataScan in pre-cleanup and passing along the section handle into post-cleanup. Are there obvious problems with this idea? What about non-obvious problems? :wink:

We've been bad devs and have been consulting various AI oracles, all of which all seem to be very poor in this area, even when given access to actual decompiled binaries.

Thank you,
Alnoor

Generally you should be able to call this API "whenever" as long as you have a valid File Object. The section conflict processing arbitrated by FltMgr and the file systems should handle it getting in the way of any normal activity. Just make sure you always close the data section and you can use the section conflict callback to back out if what you're doing is going to take a long/unbounded/arbitrary amount of time. So, "create it in PreCleanup and close it later" should be a reasonable usage.

Though why would you want to scan a file when someone closes a HANDLE with no data access?

And what is stopping you from creating the section in PostCleanup? I'm not suggesting it's a good idea but curious...We see Defender doing this all the time, though admittedly it's asynchronously after cleanup and not directly within PostCleanup (they ref the File Object in PostCreate, queue a scan, then do the FltCreateSection later and it sometimes lands after FO_CLEANUP_COMPLETE is set). It's strange because you never could see something like that from user mode so I'd rather they wouldn't, but it definitely happens.

Sorry to answer with more questions :joy:

Thanks Scott! No apologies needed. I'm happy to out of the hellhole of asking AI. I thought if I gave it access to Ghidra + kernel code it would be able to make more reasonable conclusions, but it's still not good enough.

Though why would you want to scan a file when someone closes a HANDLE with no data access?

Roughly, we're trying to scan when someone has written new data to the file. So, someone could open the file over SMB for FILE_WRITE_DATA, write to it, and close the handle. We are able to create a section for this file object but later reading fails. So I think that means we need to re-open the file with FILE_READ DATA access (best effort of course).

And what is stopping you from creating the section in PostCleanup?

My colleague did give it a go and got back STATUS_FILE_CLOSED.

Alnoor

I've spent a lot of (too much?) time automating parts of my research workflow with Fable 5 + IdaLib + HexRays. I'm at the point where I can get very expensive, quite reasonable answers to my questions about how a specific version of something works. But its suggestions on implementations can be quite horrifying :joy:

So, someone could open the file over SMB for FILE_WRITE_DATA, write to it, and close the handle. We are able to create a section for this file object but later reading fails. So I think that means we need to re-open the file with FILE_READ DATA access (best effort of course).

The problem of course if you don't know what security context to use to open the file on the network. Not like you can try to open from Local System and expect that to succeed...

Any chance you can make it a requirement to scan on the server? Or silently add in FILE_READ_DATA to write only opens. The latter does change the oplock requests on the server and could fail if the user only actually had write access, but if it's something you need you're kind of stuck no matter what. Unless you can have control over the endpoint configuration and can require your scan service be granted read access to all network files by the admin...

My colleague did give it a go and got back STATUS_FILE_CLOSED.

Interesting. This is the list of things that FAT lets through:

    //
    //  If the file object has already been cleaned up, and
    //
    //  A) This request is a paging io read or write, or
    //  B) This request is a close operation, or
    //  C) This request is a set or query info call (for Lou)
    //  D) This is an MDL complete
    //
    //  let it pass, otherwise return STATUS_FILE_CLOSED.
    //

    if ( FlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE) ) {

        PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );

        if ( (FlagOn(Irp->Flags, IRP_PAGING_IO)) ||
             (IrpSp->MajorFunction == IRP_MJ_CLOSE ) ||
             (IrpSp->MajorFunction == IRP_MJ_SET_INFORMATION) ||
             (IrpSp->MajorFunction == IRP_MJ_QUERY_INFORMATION) ||
             ( ( (IrpSp->MajorFunction == IRP_MJ_READ) ||
                 (IrpSp->MajorFunction == IRP_MJ_WRITE) ) &&
               FlagOn(IrpSp->MinorFunction, IRP_MN_COMPLETE) ) ) {

            NOTHING;

        } else {

            FatRaiseStatus( IrpContext, STATUS_FILE_CLOSED );
        }
    }

It's probably the FSCTL_SET_PURGE_FAILURE_MODE from FltCreateSection that's failing...I suspect that Defender doing this async makes things race such that it sometimes races the check with the cleanup mid-flight. But note that once you have the section the only thing that's going to come through the file system are the paging reads, which pass that check, so creating in PreCleanup and then scanning after should "just work"

1 Like

Yep, there are definitely still problems to work through. Let's see how we go.

Thanks again!

1 Like