FileContext等的坑?

FileContext等的坑?

  • 问题
  • 场景
  • 具体问题
  • 解决方案

问题

在minifilter中,可以使用CtxGetFileContext,CtxCreateFileContext等函数保存context。

以FileContext为例,新建的文件可以保存一个context进去,然后当这个文件被删除的时候,操作系统会调用minifilter的清理函数来删除相应的context。

那么坑:

如果海量创建文件,那么context就会越来越多,如果文件一直不删除,那么驱动里面的context就会炸掉。

场景

一般保存context如下:


NTSTATUS
CtxFindOrCreateFileContext(
    _In_ PFLT_CALLBACK_DATA Cbd,
    _In_ BOOLEAN CreateIfNotFound,
    _When_(CreateIfNotFound != FALSE, _In_) _When_(CreateIfNotFound == FALSE, _In_opt_) PUNICODE_STRING FileName,
    _Outptr_ PCTX_FILE_CONTEXT *FileContext,
    _Out_opt_ PBOOLEAN ContextCreated
)
/*++

Routine Description:

This routine finds the file context for the target file.
Optionally, if the context does not exist this routing creates
a new one and attaches the context to the file.

Arguments:

Cbd                   - Supplies a pointer to the callbackData which
declares the requested operation.
CreateIfNotFound      - Supplies if the file context must be created if missing
FileName              - Supplies the file name
FileContext           - Returns the file context
ContextCreated        - Returns if a new context was created

Return Value:

Status

--*/
{
    NTSTATUS status;
    PCTX_FILE_CONTEXT fileContext;
    PCTX_FILE_CONTEXT oldFileContext;

    PAGED_CODE();

    *FileContext = NULL;
    if (ContextCreated != NULL) *ContextCreated = FALSE;

    //
    //  First try to get the file context.
    //

    PT_DBG_PRINT(PTDBG_TRACE_ROUTINES,
        ("[hzskxxdlpminimon]: Trying to get file context (FileObject = %p, Instance = %p)\n",
            Cbd->Iopb->TargetFileObject,
            Cbd->Iopb->TargetInstance));

    status = FltGetFileContext(Cbd->Iopb->TargetInstance,
        Cbd->Iopb->TargetFileObject,
        &fileContext);

    //
    //  If the call failed because the context does not exist
    //  and the user wants to creat a new one, the create a
    //  new context
    //

    if (!NT_SUCCESS(status) &&
        (status == STATUS_NOT_FOUND) &&
        CreateIfNotFound) {


        //
        //  Create a file context
        //

        PT_DBG_PRINT(PTDBG_TRACE_ROUTINES,
            ("[hzskxxdlpminimon]: Creating file context (FileObject = %p, Instance = %p)\n",
                Cbd->Iopb->TargetFileObject,
                Cbd->Iopb->TargetInstance));

        status = CtxCreateFileContext(FileName, &fileContext);

        if (!NT_SUCCESS(status)) {

            PT_DBG_PRINT(PTDBG_TRACE_ROUTINES,
                ("[hzskxxdlpminimon]: Failed to create file context with status 0x%x. (FileObject = %p, Instance = %p)\n",
                    status,
                    Cbd->Iopb->TargetFileObject,
                    Cbd->Iopb->TargetInstance));

            return status;
        }


        //
        //  Set the new context we just allocated on the file object
        //

        PT_DBG_PRINT(PTDBG_TRACE_ROUTINES,
            ("[hzskxxdlpminimon]: Setting file context %p (FileObject = %p, Instance = %p)\n",
                fileContext,
                Cbd->Iopb->TargetFileObject,
                Cbd->Iopb->TargetInstance));

        status = FltSetFileContext(Cbd->Iopb->TargetInstance,
            Cbd->Iopb->TargetFileObject,
            FLT_SET_CONTEXT_KEEP_IF_EXISTS,
            fileContext,
            &oldFileContext);

        if (!NT_SUCCESS(status)) {

            PT_DBG_PRINT(PTDBG_TRACE_ROUTINES,
                ("[hzskxxdlpminimon]: Failed to set file context with status 0x%x. (FileObject = %p, Instance = %p)\n",
                    status,
                    Cbd->Iopb->TargetFileObject,
                    Cbd->Iopb->TargetInstance));
            //
            //  We release the context here because FltSetFileContext failed
            //
            //  If FltSetFileContext succeeded then the context will be returned
            //  to the caller. The caller will use the context and then release it
            //  when he is done with the context.
            //

            PT_DBG_PRINT(PTDBG_TRACE_ROUTINES,
                ("[hzskxxdlpminimon]: Releasing file context %p (FileObject = %p, Instance = %p)\n",
                    fileContext,
                    Cbd->Iopb->TargetFileObject,
                    Cbd->Iopb->TargetInstance));

            FltReleaseContext(fileContext);

            if (status != STATUS_FLT_CONTEXT_ALREADY_DEFINED) {

                //
                //  FltSetFileContext failed for a reason other than the context already
                //  existing on the file. So the object now does not have any context set
                //  on it. So we return failure to the caller.
                //

                PT_DBG_PRINT(PTDBG_TRACE_ROUTINES,
                    ("[hzskxxdlpminimon]: Failed to set file context with status 0x%x != STATUS_FLT_CONTEXT_ALREADY_DEFINED. (FileObject = %p, Instance = %p)\n",
                        status,
                        Cbd->Iopb->TargetFileObject,
                        Cbd->Iopb->TargetInstance));

                return status;
            }

            //
            //  Race condition. Someone has set a context after we queried it.
            //  Use the already set context instead
            //

            PT_DBG_PRINT(PTDBG_TRACE_ROUTINES,
                ("[hzskxxdlpminimon]: File context already defined. Retaining old file context %p (FileObject = %p, Instance = %p)\n",
                    oldFileContext,
                    Cbd->Iopb->TargetFileObject,
                    Cbd->Iopb->TargetInstance));

            //
            //  Return the existing context. Note that the new context that we allocated has already been
            //  released above.
            //

            fileContext = oldFileContext;
            status = STATUS_SUCCESS;

        }
        else {

            if (ContextCreated != NULL) *ContextCreated = TRUE;
        }
    }

    *FileContext = fileContext;

    return status;
}


每次调用CreateFile,可以尝试创建一个context,或者找到之前的context,一个文件路径对应一个context。
然后当这个文件被删除的时候,操作系统会调用驱动注册的函数:

{ FLT_FILE_CONTEXT,
    0,
    CtxContextCleanup,
    CTX_FILE_CONTEXT_SIZE,
    CTX_FILE_CONTEXT_TAG },

驱动执行CtxContextCleanup,删除相应context。

具体问题

如果一直创建,很明显,驱动里面的context越来越多,导致:

  1. 每次调用CreateFile的时候,要从已有context里面查找,context越多,速度越慢

  2. 驱动里面的context越来越多,最后的结果可想而知

解决方案

  1. 控制context的量,如果太多,就删除一些,弊端:删除之后,后面的IRP_WRITE_FILE就获取不到路径了(File Mapping情况)

  2. 其他办法?目前没找到更好的

  3. 不要使用context机制。

你可能感兴趣的:(Windows驱动开发)