STATUS_SHARING_VIOLATION in work item

Hi
My minifilters inspects the content of a file after a write , due to IRQL restrictions in the post write callback I queue a work item and in the worker thread , the call to ZwCreateFile ( rarely ) returns STATUS_SHARING_VIOLATION

assuming I don’t have control over the usermode service that interacts with files I want to filter , how can I inspect the content?

  1. You should not be calling ZwCreateFile it will break things under interop testing. Call FltCreateFile instead
  2. Look at using IO_IGNORE_SHARE_ACCESS_CHECK

I call this from my work item, still sharing violation :

    IO_STATUS_BLOCK ioStatusBlock;
    HANDLE FileHandle = nullptr;
    NTSTATUS status;
    ULONG BytesRead = 0;
    LARGE_INTEGER ByteOffset;
    ByteOffset.QuadPart = 0;

    InitializeObjectAttributes(&objAttr, &FileName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);

    status = FltCreateFile(Filter, Instance, &FileHandle, FILE_ALL_ACCESS, &objAttr, &ioStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL,0, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0, IO_IGNORE_SHARE_ACCESS_CHECK);

    if (!NT_SUCCESS(status) || FileHandle == nullptr)
    {
        DbgPrint("[*] failed create file 0x%x\n", status);
        return INVALID_ENTROPY;
    }
    PVOID Object = nullptr;
    status = ObReferenceObjectByHandle(FileHandle, GENERIC_ALL, *IoFileObjectType, KernelMode, (PVOID*)&Object, NULL);
    if (!NT_SUCCESS(status))
    {
        DbgPrint("[*] failed to reference file object by handle 0x%x\n", status);
        ZwClose(FileHandle);
        return INVALID_ENTROPY;

    }

    PFILE_OBJECT FileObject = (PFILE_OBJECT)Object;
    FILE_STANDARD_INFORMATION FileInfo;

    status = FltQueryInformationFile(Instance, FileObject, &FileInfo, sizeof(FileInfo), FileStandardInformation, NULL);
    if (!NT_SUCCESS(status))
    {
        DbgPrint("[*] failed to query information file 0x % x\n",status);
        ObfDereferenceObject(Object);
        ZwClose(FileHandle);
        return INVALID_ENTROPY;
    }


    ULONG Size = (ULONG)FileInfo.EndOfFile.QuadPart;
    if (Size == 0)
    {
        ObfDereferenceObject(Object);
        ZwClose(FileHandle);
        return INVALID_ENTROPY;
    }
    PVOID Buffer = ExAllocatePoolWithTag(NonPagedPool,Size,TAG);
    if (!Buffer)
    {
        DbgPrint("[*] failed allocating read buffer\n");
        ObfDereferenceObject(Object);
        ZwClose(FileHandle);
        return INVALID_ENTROPY;
    }

    status = FltReadFile(Instance, FileObject, &ByteOffset, FileInfo.EndOfFile.QuadPart, Buffer, FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET | FLTFL_IO_OPERATION_NON_CACHED | FLTFL_IO_OPERATION_PAGING | FLTFL_IO_OPERATION_SYNCHRONOUS_PAGING, &BytesRead, NULL, NULL);
    if (!NT_SUCCESS(status))
    {
        DbgPrint("[*] failed read  file 0x%x\n", status);
        ObDereferenceObject(Object);
        ExFreePoolWithTag(Buffer, TAG);
        ZwClose(FileHandle);
        return INVALID_ENTROPY;
    }

still sharing violation

I'd grep FAT for sharing violation (it can happen for things like image sections), better still reproduce it in FAT then build a debug version and step though the create in the debugger.

If it has to be NTFS then there are things you can set in NTFS to make it break into the debugger on certain status settings (but it gets noisy real fast)

Not sure why you are asking for ALL_ACCESS when you are just going to read; GENERIC_READ will do (and in kernel mode you don't even need that)

Also - ZwClose() needs to be FltClose()

Hmmm, even when asking only for generic read , and specifying file share read in a usermode app I get the same sharing violation (as I mentioned initially I shouldn’t assume the file was open with share read , just for testing here)

I figured it only happens for paging operations, surely there’s a way to read it regardless of the state of a usermode handle ?

Hang on, lets wind this back.

I missed a lot of context in you initial note.

You are in a paging write and you want to see what is being written? Just look at the buffer.

You probably don’t want to being doing it (because you wont get what you expect - you’ll get what is on disk, not what is in cache) but if you want to see what else is in the file: just read the data using the fileobject you have. It will need to be a paging read of course.

But just don’t try to do anything in the paging path beyond paging read, paging write and paging set info (which will probably fail)

Also: why? in post paging write the data is on disk and you cannot put the toothpaste back in the tube.

here from my account at work - I need the entire file's content after the paging write : )
"just read the data using the fileobject you have" - IRQL in post wont allow that , that's why I queue a generic work item , and try to obtain a new handle
you also cant pend a paging postop which might have been useful to do I guess - in order to use the file object I have before the handle is closed , but yea - not possible here

Post yes, but dont open a handle. Reference the fileobject before you post and use that.

But I am pretty sure you would be better doing this all in the pre call (again, not with a create, just use the FO you are given). You know what is there now, you know what is about to be written.

That’s a good idea, swapbuffers is a good sample to look at for using the buffer / mdl correctly , right? Thanks!

I’ve been attempting this , I think I have a misunderstanding regarding file sizes

first, I read the entire file from disk
then, I check if ByteOffset + WriteLength exceeds FileSize(FltQueryInformationFile)

based on that , I allocate either ByteOffset + WriteLength bytes for my copy , or just FileSize num of bytes.

to simulate the write in pre write, I copy FileSize bytes from the original content to the allocation , and then copy WriteLength bytes to the allocation + ByteOffset

Is it the correct way to do it? to simulate the write ?

Because I’m not getting the results I’m expecting

What I’m seeing is ByteOffset + WriteLength gives me the “size on disk” property, whilst FileSize gives me the size property , I’m afraid this might be related

Also , the size of the file in pre write is the size after modification , when I Track this in procmon I see set information IRP sent before the actual mapped page writer write, so when trying to inspect the content in pre write is it trivial to read that size of bytes? since write hasn’t occurred yet

Edit : I assume mapped page writer writes AllocationSize number of bytes regardless of the EOF, so I should allocate AllocationSize bytes to avoid corrupting pool when copying the write data , but when analyzing the actual content inspect only FileSize bytes , because that’s the EOF with the write taken into it?

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.