基于Minifilter框架的文件过滤驱动理解
概述
?
Minifilter即File System Minifilter Drivers,是Windows為了簡化第三方開發(fā)人員開發(fā)文件過濾驅動而提供的一套框架,這個框架依賴于一個稱之為Filter Manager(后面簡寫為FltMgr)的傳統(tǒng)文件系統(tǒng)過濾驅動。這套框架應用到內核中的結構如下圖所示:
?
?
FltMgr以傳統(tǒng)文件過濾驅動的形式插入到I/O處理隊列中去接收不同的I/O請求,然后將這個請求遍歷發(fā)布到它所維護的Minifilter對象中,然后根據(jù)各個Minifilter對這個I/O請求的處理結果來決定后續(xù)的操作。
?
這種模式在很多軟件架構中使用,類似于插件一樣,每一個Minifilter遵守一定的接口規(guī)范插入到FltMgr中,然后就能執(zhí)行過濾控制。
?
上面是對整個Minifilter框架進行描述,實際內部需要注意的細節(jié)牽涉到很多內核知識,比如中斷級別、I/O請求被封裝成IRP包和fast I/O請求等相對復雜的概念。這里不做深究,主要以研究Minifilter的開發(fā)過程和相應注意的地方為主。此外還有FltMgr在內核中的位置等相關知識,也只在必要的地方提及一下。
?
Minifilter流程
?
Minifilter通過注冊并啟動后,根據(jù)在注冊表中設置的相應值,插入到對應的FltMgr實例(Frame)隊列中,然后關聯(lián)上需要過濾的卷。FltMgr會根據(jù)Minifilter所注冊的I/O操作類型,調用對應的pre和post操作函數(shù),并根據(jù)對應的返回值執(zhí)行不同的流程。這里假設有A、B、C三個Minifilter從上往下掛載在FltMgr實例上,那么當接收到I/O請求時,執(zhí)行的步驟為A-pre、B-pre、C-pre,一旦某個Minifilter返回了FLT_PREOP_COMPLETE,即表明這個I/O請求被它完成處理了,則立即按照相反的順序調用對應的post函數(shù)(不再繼續(xù)往下調)。
?
注冊和關聯(lián)
?
Minifilter根據(jù)FltRegisterFilter函數(shù)介紹說明,為響應操作設置對應的回調函數(shù)和數(shù)據(jù)結構后,就可以在DriverEntry中調用FltRegisterFilter進行注冊了,然后調用FltStartFiltering來通知FltMgr當前Minifilter已經(jīng)準備好關聯(lián)到要過濾的卷了。
?
FltMgr會在系統(tǒng)啟動時或者接收到手動關聯(lián)命令時,調用Minifilter的InstanceSetupCallback回調函數(shù),當然前提是Minifilter在注冊的時候增設置了這個函數(shù)的地址,這個回調函數(shù)會傳入要關聯(lián)的卷標信息,FltMgr會根據(jù)這個函數(shù)的返回值判斷是否關聯(lián)成功。這里和對應卷相關聯(lián)的Minifilter實例叫做instance。一個卷上可以掛多個instance。只有對指定卷進行關聯(lián)后,才能過濾其I/O請求。
?
取消關聯(lián)的過程可以理解成釋放實例的過程,釋放后就無法繼續(xù)過濾對應卷了。
?
Pre回調函數(shù)(PFLT_PRE_OPERATION_CALLBACK)
?
FLT_PREOP_COMPLETE:表示當前的過濾驅動完成了本次I/O操作,過濾管理器就不再往下發(fā)送本次I/O請求,而是依次向上調用post回調函數(shù)。這種情況下IoStatus.Status的值就是最終I/O操作的執(zhí)行結果(不能是STATUS_PENDING)。
?
FLT_PREOP_SUCCESS_NO_CALLBACK/FLT_PREOP_SUCCESS_WITH_CALLBACK:這個返回值表示處理成功,讓過濾管理器去做自己的事,區(qū)別在于WITH_CALLBACK的返回值會標明需要回調post函數(shù)。而NO_CALLBACK的則標明不需要。
?
FLT_PREOP_PENDING:顧名思義,表明當前過濾驅動將本次I/O操作掛起了,過濾管理器需要等待當前驅動調用FltCompletePendedPreOperation函數(shù)后才會繼續(xù)本次I/0操作處理流程。注意只有對于基于IRP中斷的I/O操作(用FLT_IS_IRP_OPERATION宏測試)才可以掛起。
?
FLT_PREOP_DISALLOW_FASTIO:只有操作是fast I/O操作(用FLT_IS_FASTIO_OPERATION(Data)進行測試)時才可以返回這個值,表明過濾驅動不允許fast I/O操作繼續(xù)執(zhí)行。因此過濾管理器不會再下發(fā)該請求,而是依次向上調用post回調函數(shù)。這種情況下不需要設置IoStatus.Status的值,過濾管理器會自動設置這個值。
?
FLT_PREOP_SYNCHRONIZE:這個返回值表明處理未完成,保持當前過濾驅動上下文線程環(huán)境,交由過濾管理器繼續(xù)下發(fā)后調用post回調函數(shù)后繼續(xù)處理。也只對基于IRP中斷的操作有效,并且必須有post函數(shù),如果不是基于IRP中斷的,就會和FLT_PREOP_SUCCESS_WITH_CALLBACK一樣。注意:對于Create操作,不應該返回這個值,因為文件管理器已經(jīng)為這個操作進行同步了。此外對于同步的讀和寫操作,如果返回這個值會嚴重影響驅動和系統(tǒng)性能。
?
如果在pre和post函數(shù)中更改了Data的內容,必須調用FltSetCallbackDataDirty函數(shù)(更改IoStatus除外)。
?
Post回調函數(shù)(PFLT_POST_OPERATION_CALLBACK)
?
這個回調函數(shù)執(zhí)行的中斷等級為IRQL <= DISPATCH_LEVEL。所以需要注意以下幾點:1、不能安全調用必須低于IRQL級別的任何內核模式的派遣函數(shù)。2、在這個函數(shù)內開辟的任何數(shù)據(jù)結構必須位于非頁內存。3、該函數(shù)不可分頁。4、不能請求資源(resource)、信號量(mutextes)和快速信號量(fast mutexes),只能獲取互斥鎖(spin lock)。5、不能獲取、設置或者刪除上下文,但可以釋放上下文。
?
相對于Pre回調函數(shù)多了最后一個參數(shù)Flags,這個參數(shù)如果存在FLTFL_POST_OPERATION_DRAINING標記位,則表明當前過濾驅動實例正在被取消關聯(lián),本次調用是為了清理pre回調函數(shù)傳入的completion context,返回值必須是FLT_POSTOP_FINISHED_PROCESSING,并且這個回調是在IRQL<=APC_LEVEL執(zhí)行的。
?
FLT_POSTOP_FINISHED_PROCESSING:表明本過濾驅動完成了對I/0操作的處理并將控制交還給過濾管理器。
?
FLT_POSTOP_MORE_PROCESSING_REQUIRED:只有當微過濾驅動將本次I/O操作發(fā)送到工作隊列中時,才能返回這個值,微過濾驅動最后必須負責完成這個I/O操作。過濾管理器會繼續(xù)等待FltCompletePendedPostOperation函數(shù)被調用后才繼續(xù)執(zhí)行控制。注意:這個返回值也必須對基于IRP中斷的操作執(zhí)行。
?
任何要被執(zhí)行在IRQL
?
除了以下情況外,要確保在Flags參數(shù)沒有FLTFL_POST_OPERATION_DRAINING標記位的時候才能調用FltDoCompletionRpocessingWhenSafe函數(shù):
?
1、如果微過濾驅動的pre回調函數(shù)為一個基于IRP中斷的操作返回FLT_PREOP_SYNCHRONIZE,那么對應的post回調要保證和pre回調都處在IRQL<=APC_LEVEL的線程上下文中。
?
2、對于create操作的post回調要保證中斷級別為IRQL_PASSIVE_LEVEL(原始IRP_MJ_CREATE操作所處的線程上下文)。
總結
以上是生活随笔為你收集整理的基于Minifilter框架的文件过滤驱动理解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: overflow 的各种用法
- 下一篇: overflow详解