Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results

Home NTFSD

Before Posting...

Please check out the Community Guidelines in the Announcements and Administration Category.

More Info on Driver Writing and Debugging


The free OSR Learning Library has more than 50 articles on a wide variety of topics about writing and debugging device drivers and Minifilters. From introductory level to advanced. All the articles have been recently reviewed and updated, and are written using the clear and definitive style you've come to expect from OSR over the years.


Check out The OSR Learning Library at: https://www.osr.com/osr-learning-library/


The context structure was over-dereferenced

0mWindyBug0mWindyBug Member Posts: 29
edited February 6 in NTFSD

Hey , I'm working on a backup filter driver , my first time working with file contexts so I clearly do something wrong maybe you guys can help me identify it
Basically I want to have a context structure per-file (I filter "interesting" files to backup , doesnt matter tho ) that will not be per handle , so I will be able to tell if the file was ever backed up by the driver and if not back it on pre write.
The design mainly involves the post create routine:
check if file already has an allocated context , if not allocate it and init it
add a pointer to the context to a linked list of "contexts to release" on unload
for every get/set context I release it , the reason I think we need to release it once more on unload because docs suggest allocate = +1 on the refcount as well , and without it the filter hangs on unload

but... well, I get the BSOD suggested in the title with "context structure was over dereferenced" in unload when trying to release it , bit more info is " the context structure was dereferenced too many times, this means that the reference count on the Filter Manager's CONTEXT_NODE structure went to 0 while it was still attached to its acossiated object"
any clear issues with my design ?

there's the Post Create filter routine :
`FLT_POSTOP_CALLBACK_STATUS
BackupFilterPostCreate(
Inout PFLT_CALLBACK_DATA Data,
In PCFLT_RELATED_OBJECTS FltObjects,
In_opt PVOID CompletionContext,
In FLT_POST_OPERATION_FLAGS Flags
)

{
UNREFERENCED_PARAMETER(CompletionContext);
if (Flags & FLTFL_POST_OPERATION_DRAINING)
return FLT_POSTOP_FINISHED_PROCESSING;

const auto& params = Data->Iopb->Parameters.Create;
if (Data->RequestorMode == KernelMode
    || (params.SecurityContext->DesiredAccess & FILE_WRITE_DATA) == 0
    || Data->IoStatus.Information == FILE_DOES_NOT_EXIST) {
    // kernel caller, not write access or a new file - we do not care 
    return FLT_POSTOP_FINISHED_PROCESSING;
}

// get file name
FilterFileNameInformation fileNameInfo(Data);
if (!fileNameInfo) {
    return FLT_POSTOP_FINISHED_PROCESSING;
}

if (!NT_SUCCESS(fileNameInfo.Parse()))
    return FLT_POSTOP_FINISHED_PROCESSING;


if (!IsBackupDirectory(&fileNameInfo->ParentDir))
    return FLT_POSTOP_FINISHED_PROCESSING;

// if it's not the default stream, we don't care
if (fileNameInfo->Stream.Length > 0)
    return FLT_POSTOP_FINISHED_PROCESSING;

// if the file has a state already just return 
FileStateContext* CheckContext;   // if i change this to "FileStateContext CheckContext" clean unload, but the context is not useful and displaying blank info, which makes sense..
auto status = FltGetFileContext(FltObjects->Instance, FltObjects->FileObject, (PFLT_CONTEXT*)&CheckContext);
if (NT_SUCCESS(status)) {
    DbgPrint("[*] already allocated context for file :%wZ\n", CheckContext->FileName);
    FltReleaseContext((PFLT_CONTEXT)CheckContext);
    return FLT_POSTOP_FINISHED_PROCESSING;
}



// allocate and initialize a file context
FileStateContext* context;

 status = FltAllocateContext(FltObjects->Filter,
    FLT_FILE_CONTEXT, sizeof(FileStateContext), PagedPool,
    (PFLT_CONTEXT*)&context);
if (!NT_SUCCESS(status)) {
    DbgPrint("[*] failed to allocate file state context\n");
    return FLT_POSTOP_FINISHED_PROCESSING;
}
// for clean unload we need to keep track of those contexts as we dont release them on cleanup/close
SaveFileStateContextToDelete(context);
context->IsBacked = FALSE;
context->FileName.MaximumLength = fileNameInfo->Name.Length;
context->FileName.Buffer = (WCHAR*)ExAllocatePoolWithTag(PagedPool, fileNameInfo->Name.Length, TAG);
if (!context->FileName.Buffer) {
    FltReleaseContext(context);
    return FLT_POSTOP_FINISHED_PROCESSING;
}
RtlCopyUnicodeString(&context->FileName, &fileNameInfo->Name);
DbgPrint("[*] built context for file :%wZ\n", context->FileName);
context->Lock.Init();
status = FltSetFileContext(FltObjects->Instance,
    FltObjects->FileObject,
    FLT_SET_CONTEXT_KEEP_IF_EXISTS,
    context, nullptr);
if (!NT_SUCCESS(status)) {
    DbgPrint("[*] failed to set file context\n");
    ExFreePool(context->FileName.Buffer);
}
FltReleaseContext(context);


DbgPrint("[*] allocated and set file context for file\n");
return FLT_POSTOP_FINISHED_PROCESSING;

}`

and the unload called function that causes the BSOD (without it filter hangs)
`
void ReleaseFileStateContexts()
{
AutoLock locker(FileStateContextsMutex);
if (ContextsToDelete)
{
PContextToDelete current = ContextsToDelete;
while (current != nullptr)
{
FltReleaseContext((PFLT_CONTEXT)current->Context); // that is -1 on the refcount to make it 0
ExFreePoolWithTag(current, TAG);
current = (PContextToDelete)current->Next;
}
}

}`

Comments

  • 0mWindyBug0mWindyBug Member Posts: 29

    solved , that was quick lol. I wrongly called the function before FltUnregisterFilter during unload, swapping the order and now unload is clean : )

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. Sign in or register to get started.

Upcoming OSR Seminars
OSR has suspended in-person seminars due to the Covid-19 outbreak. But, don't miss your training! Attend via the internet instead!
Kernel Debugging 13-17 May 2024 Live, Online
Developing Minifilters 1-5 Apr 2024 Live, Online
Internals & Software Drivers 11-15 Mar 2024 Live, Online
Writing WDF Drivers 20-24 May 2024 Live, Online