async FltReadFile

Hi all,

I have a mini filter that uses some code to read files from a preCreate callback. I am reading the file in blocks of 512 bytes, but the Information field at my IO_STATUS_BLOCK structure always is set to 1. I have checked the contents of the buffer where data is stored and the system is storing 512 bytes.

The code is like this:

NTSTATUS TestReadFile(IN CONST PFLT_INSTANCE Instance, IN CONST UNICODE_STRING& File, IN OUT PUCHAR Result)
{
IO_STATUS_BLOCK IoStatus;
PFILE_OBJECT FileObject = NULL;
HANDLE hFile = NULL;

NTSTATUS Status = GetFileObject(Instance, File, hFile, IoStatus, &FileObject);
if (!NT_SUCCESS(Status)) return Status;

PUCHAR ReadBuffer = (PUCHAR)FltAllocatePoolAlignedWithTag(Instance, NonPagedPool, 512, ‘TEST’);
if (!ReadBuffer) Status = STATUS_UNSUCCESSFUL;

KEVENT ReadCompletionEvent;
KeInitializeEvent(&ReadCompletionEvent, SynchronizationEvent, FALSE);

LARGE_INTEGER ByteOffset = { 0 };

while (Status == STATUS_SUCCESS)
{
Status = FltReadFile(Instance, FileObject, &ByteOffset, 512, ReadBuffer,
FLTFL_IO_OPERATION_NON_CACHED, NULL, (PFLT_COMPLETED_ASYNC_IO_CALLBACK)ReadCompletionRoutine,
&ReadCompletionEvent);

if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&ReadCompletionEvent, Executive, KernelMode, FALSE, NULL);
Status = IoStatus.Status;
}

if (Status == STATUS_SUCCESS)
{
ByteOffset.QuadPart += IoStatus.Information;
}
}

if (Status == STATUS_END_OF_FILE)
{
Status = STATUS_SUCCESS;
}

if (ReadBuffer) FltFreePoolAlignedWithTag(Instance, ReadBuffer, ‘TEST’);
if (FileObject) ObDereferenceObject(FileObject);
if (hFile) FltClose(hFile);

return Status;
}

VOID ReadCompletionRoutine(IN PFLT_CALLBACK_DATA CallbackData, IN PFLT_CONTEXT Context)
{
UNREFERENCED_PARAMETER(CallbackData);

if (Context) KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
}

NTSTATUS GetFileObject(IN CONST PFLT_INSTANCE Instance, IN CONST UNICODE_STRING& File,
IN OUT HANDLE& FileHandle, IN OUT IO_STATUS_BLOCK& IoStatus,
IN OUT PFILE_OBJECT* FileObjectResult)
{
if (!m_Flt) return STATUS_UNSUCCESSFUL;
if (!Instance) return STATUS_UNSUCCESSFUL;
if (!FileObjectResult) return STATUS_UNSUCCESSFUL;

OBJECT_ATTRIBUTES Attr;
InitializeObjectAttributes(&Attr, (PUNICODE_STRING)&File, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);

NTSTATUS Status = FltCreateFile(m_Flt, Instance, &FileHandle, FILE_READ_DATA /*| SYNCHRONIZE*/, &Attr, &IoStatus,
NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_VALID_FLAGS, FILE_OPEN,
FILE_NON_DIRECTORY_FILE | FILE_SEQUENTIAL_ONLY , NULL, 0, 0);

if (NT_SUCCESS(Status))
{
PFILE_OBJECT Result = NULL;

Status = ObReferenceObjectByHandle(FileHandle, FILE_READ_DATA, *IoFileObjectType,
KernelMode, reinterpret_cast(&Result), NULL);
if (NT_SUCCESS(Status)) *FileObjectResult = Result;
}
return Status;
}

Thanks in advance.

Eugenio

How big is the file? If it’s 1 byte long then all is working as
designed/expected.

-scott
OSR
@OSRDrivers

Hi Scott,

The file is 120 MB long.

Eugenio

Sorry, I can’t spot the problem. Have you put ProcMon under your filter to
see what’s coming out the bottom? If yes, then try using FileTest on another
system and reading a file with the same arguments. You can then compare
ProcMon traces and try to figure out what’s going on.

My only comment is that I’m not sure why you would bother using the
asynchronous callback if you’re just going to force the operation to be
synchronous anyway?

-scott
OSR
@OSRDrivers

I’d be inclined to set and access breakpoint on Iosb.Information and see
what happens

So reading your code more closely.

  • you setup the IOSB in GetFileObject only. So the Information field is
    something like FILE_OPENED.
  • you never set the IOSB again. If you want to know the length written you
    will need to add the parameter to FltRead

/Rod

You are passing NULL for a callback routine so your operation is performed
synchronously, not asynchronously. Also why not provide the out parameter
for BytesRead? I’ll just guess that if you do that for the synchronous
option (NULL callback) you will get the correct result.

Mark Roddy

On Wed, Aug 1, 2018 at 3:58 AM Rod Widdowson <
xxxxx@lists.osr.com> wrote:

> So reading your code more closely.
>
> - you setup the IOSB in GetFileObject only. So the Information field is
> something like FILE_OPENED.
> - you never set the IOSB again. If you want to know the length written
> you
> will need to add the parameter to FltRead
>
> /Rod
>
>
> —
> NTFSD is sponsored by OSR
>
>
> MONTHLY seminars on crash dump analysis, WDF, Windows internals and
> software drivers!
> Details at http:
>
> To unsubscribe, visit the List Server section of OSR Online at <
> http://www.osronline.com/page.cfm?name=ListServer&gt;
></http:>

Hi all,

The length written to the buffer and the final status of the read operation are at the CallbackData parameter received by the callback function. CallbackData->IoStatus has the status of the operation and the amount readed into the buffer.

Thanks to all of you for your comments.

Eugenio