文件過濾驅動中的重入處理

While processing an IRP_MJ_CREATE a filter may need to open the file with different attributes/rights, etc. This is often done by using a second call to ZwCreatefile. This then will generate a call back into the FSD filter. Thus, a common filter issue is being able to detect this reentrancy. 

在處理IRP_MJ_CREATE請求時,過濾驅動可能會使用不一樣的屬性/權限等打開這個文件。這種狀況常常發生在第二次調用ZwCreatefile時。這會致使生成一個對FSD 過濾驅動的回調(就是重入了).於是,正常的過濾驅動就要有能力檢測這種重入的問題。

There are several ways of dealing with reentrancy during an IRP_MJ_CREATE operation, and the appropriate solution for your particular driver will depend upon the circumstances. In addition, there are a number of techniques that might work for a single file system filter driver, but that fail when used in a multi-filter environment. 

在處理IRP_MJ_CREATE操做過程當中,有幾種方法能夠處理重入,處理你的驅動(中的重入)的適當方法取決於你的環境。另外,有許多種技術能夠在單個文件系統過濾驅動上工做,但在多層過濾的環境下可能會失效。

For Windows XP and newer versions of Windows, the best mechanism for opening a file within the filter is to use IoCreateFileSpecifyDeviceObjectHint. A filter driver can call this function and specify a given device object. The IRP_MJ_CREATE that is built will be passed to the specified device object. This technique avo
ids reentrancy issues and is the best mechanism available for a filter to open a file. 

對Windows xp或者更新版的Windows來講,在過濾驅動中打開一個文件的最好方法是使用IoCreateFileSpecifyDeviceObjectHint.文件過濾驅動能夠調用這個函數而且指定一個給定的設備對象。

For versions of Windows prior to Windows XP, this mechanism is not available. The best mechanism in this environment is to implement your own functional equivalent of IoCreateFileSpecifyDeviceObjectHint. This can be done by creating a second device object for each device you are filtering. 

對Windows xp之前的Windows操做系統,這種方法無效。在這種環境下最好的方法是實現你本身的與IoCreateFileSpecifyDeviceObjectHint等價的功能。這能夠經過給你要過濾的設備建立第二個設備對象來實現。

For example, suppose you decide to filter some given file system device object, FSDVolumeDeviceObject. You then create a device object MyFilterDeviceObject and attach it using IoAttachDeviceToDeviceStack (of course, in Windows XP you would use IoAttachDeviceToDeviceStackSafe instead). In addition, you create a second device object MyFilterShadowDeviceObject. This device object must be assigned a name ("DeviceMyFilterDevice27", for example). The name can be anything, but it must obviously be unique. In your device extension for your two device objects, you need to track this name, and you need to maintain pointers to the respective device objects (that is, the device extension for MyFilterShadowDeviceObject should point to MyFilterDeviceObject and the device object extension for MyFilterDeviceObject should point to yFilterShadowDeviceObject). Don't forget to set the StackSize field of the device object correctly!) 

例如,假設你要過濾某個特定的文件系統設備對象,FSDVolumeDeviceObject(文件系統卷設備對象).這時你要建立一個設備對象 MyFilterDeviceObject 而且使用IoAttachDeviceToDeviceStack 函數(在windows xp下使用 IoAttachDeviceToDeviceStackSafe)來掛接它。另外,你還要建立第二個設備對象 yFilterShadowDeviceObject.這個設備對象必須被指定一個名字(例如"DeviceMyFilterDevice27",注: 這裏指的第二個設備對象,即Shadow device object )。名字能夠是任意的,但必須惟一的。在這兩個設備的設備擴展結構中,你須要跟蹤這個名字
(注,其實就是作標誌,你要知道你當前是處在哪一個設備 中,是第一個設備對象仍是Shadow object )你須要維護一些指向相應的設備對象的指針(也就是說,MyFilterShadowDeviceObject的設備擴展要指向 MyFilterDeviceObject,MyFilterDeviceObject的設備擴展對象要指向 MyFilterShadowDeviceObject.不要忘了正確設置設備對象的StackSize成員變量。

Now, an IRP_MJ_CREATE request arrives in your filter, specifying MyFilterDeviceObject. To open the file without experiencing reentrancy problems, you call IoCreateFile (or ZwCreateFile). Since you must pass the name of the file being opened, you construct that by using both the name you gave MyFilterShadowDeviceObject and the name that is in the FileObject of the I/O stack Location (IoGetCurrentIr
pStackLocation(Irp)->FileObject). 

如今,當IRP_MJ_CREATE 請求到達你的過濾驅動時,指定了 MyFilterDeviceObject.你調用IoCreateFile(或ZwCreateFile) 打開文件就沒有重入的問題了.之後,你必須傳遞這個打開的文件的名字,這個名字是用你設置在MyFilterShadowDeviceObject中的名 字和從I/O 堆棧區域中獲得的文件對象中的名字一塊兒構造的。

Since you are passing a name in that points to your second device object, the I/O Manager will build the IRP_MJ_CREATE and pass the resulting I/O request packet to your driver, but specifying MyFilterShadowDeviceObject. 

當你傳遞一個指向你的第二個設備對象的名字,I/O管理器會構建IRP_MJ_CREATE 而且傳遞I/O請求的結果到你的驅動,但指定了MyFilterShadowDeviceObject.

In your IRP_MJ_CREATE dispatch handler you must detect that this is a "shadow" device object, rather than a typical filter device object. In this case, you should send the IRP_MJ_CREATE operation down to the device being filtered by MyFilterDeviceObject. Indeed, since you should not need to do any further processing, you can use IoSkipCurrentIrpStackLocation (rather than IoCopyCurrentIrpStackLocationToNext).

在你的IRP_MJ_CREATE 分發例程處理函數中,你必須檢測它是一個"Sahdow"設備對象而不是是一個典型的過濾設備對象。在這種狀況下,你必須將IRP_MJ_CREATE操 做下傳到已經被 MyFilterDeviceObject過濾了的設備中。確實,此後你不須要做進一步的處理,你能夠用 IoSkipCurrentIrpStackLocation函數(不是IoCopyCurrentIrpStackLocationToNext).

The original filter (where the IoCreateFile call was made) will receive back a file handle that can then be used for subsequent operations (using the Zw API routines). 

原始的過濾器(調用IoCreateFile的設備對象)會收到一個能夠用於後續操做的文件句柄(使用Zw API 例程)。

Typically, filter drivers that attempt to use IoCreateFile or ZwCreateFile with the same file/device name as the original request experience reentrancy into their driver. A number of techniques for dealing with this have been tried in the past, but they exhibit various problems when combined with other filters. These i
nclude: 

· Appending a "special string" to the end of the file name. This will not work when two filters using this technique are loaded onto the same system (since each one appends its "special string" onto the previous filter's "special string").

· Track thread identifiers to detect reentrancy. This technique fails when combined with a filter that utilizes a separate service for opening the file; filters sometimes must switch to a different thread context in order to eliminate stack overflow conditions.
· Building create IRPs within a filter. This technique does work properly, but is completely unsupported and quite difficult to implement correctly. Because of this, it is a fragile solution that should not be used given the availability of alternative mechanisms.
· Re-using the file object from the current IRP_MJ_CREATE. In this sequence, the filter allows the create operation to complete and then uses the file object subsequently. When done, the filter then sends a cleanup and close operation to the underlying file system. It then sends the original IRP_MJ_CREATE operation to the underlying FSD. There are several potential issues with this approach. First, in this technique the filter does not have a file handle for the file object and thus cannot use the Zw API calls. Second, the file object must be restored to its original state - otherwise, there are fields within it that are not set up properly. Third, because the file object has not yet been "properly referenced" the filter may find that the OS deletes the object because its reference count drops to zero during its use. Used carefully, this technique has been successful in the past.

一般,試圖使用與原始的請求相同的文件/設備名來調用IoCreateFile或ZwCreateFile都會遇到重入。過去已經有不少種用於處理重入的技術被試驗,但當它和其它過濾器協同工做時會表現出各類各樣的問題。
這些技術包括:

1. 添加一個特殊的串到文件名尾部。當兩個使用這種技術的過濾器被加載到相同的系統時會不能工做(此後,每一個過濾器都會添加它的特殊串到先前的特殊串後面。

2. 跟蹤線程ID來檢測重入. 這種技術在過濾驅動使用一個單獨的服務來打開文件時會失敗。過濾器驅動有時必須切換到不一樣的線程上下文來消除堆棧溢出的狀況。

3.在過濾器內部建立IRP請求。這種技術會正常工做,但它徹底沒有支持而且很難正確地實現。所以,這是種脆弱的方案,在有可選擇的機制的狀況下不會被使用。

4 重用當前IRP_MJ_CREATE請求的文件對象.在這種狀況下,過濾驅動容許建立(文件)的操做完成,而且能夠在隨後使用這個文件對象。在操做完成 後,過濾驅動會向下層文件系統發送Cleanup和Close操做。它接着會發送原始的IRP_MJ_CREATE操做到下層的FSD.這種方法有幾個潛 在的問題。首先,在這種技術中過濾器驅動沒有文件對象的句柄,於是不能使用Zw API調用。其實,文件對象必須存貯它原始的狀態,不然在它內部的一些數據成員就沒有被正確設置.最後,由於文件對象尚未被"正確地引用",過濾驅動會 發現操做系統刪除這個對象,由於它的引用計數在它的使用過程當中被減到0.當心地使用,這種技術在過去有成功的案例。

Regardless of the technique used, the filter driver must be cognizant of the issues involving oplocks (and the FILE_COMPLETE_IF_OPLOCKED option). If an oplock break occurs during an IRP_MJ_CREATE, whether from an original application, or from a filter driver attempting to open the file, the filter must be able to handle it gracefully. 

無論使用哪一種技術,過濾驅動必須能識別陷於OpLocks的問題(FILE_COMPLETE_IF_OPLOCKED 選項)。在一個IRP_MJ_CREATE中發生oplock 打斷,不管是從原始的應用程序仍是過濾驅動中的打開文件操做,過濾驅動必須可以溫和地處理它. 

Finally, the filter must be aware of the fact that even though it is calling from kernel mode, the underlying FSD will continue to enforce sharing access against the file. 

最後,過濾驅動必須能知道這種狀況:雖然調用來自內核模式,下層的FSD會對這個文件強制進行共享存取。windows

 

來源:網絡網絡

相關文章
相關標籤/搜索