znsoft
管理员
管理员
  • 注册日期2001-03-23
  • 最后登录2023-10-25
  • 粉丝300
  • 关注6
  • 积分910分
  • 威望14796点
  • 贡献值7点
  • 好评度2410点
  • 原创分5分
  • 专家分100分
  • 社区居民
  • 最爱沙发
  • 社区明星
阅读:2351回复:7

Emerging Issues in IoCancelFileOpen -- 解决iocancelfileopen 与norton 之类过滤驱动冲突

楼主#
更多 发布于:2007-10-11 12:07

The NT Insider, Vol 10, Issue 4, July-August 2003 | Published: 06-May-03| Modified: 27-Aug-03

At the April 2003 Microsoft IFS Plugfest an issue was identified that could arise when two file system filter drivers interact in an unexpected fashion during the processing of IRP_MJ_CREATE.

This situation arises when the lower filter performs an IRP_MJ_READ or IRP_MJ_WRITE operation after the IRP_MJ_CREATE has been satisfied by the underlying file system and then the higher filter calls IoCancelFileOpen because it has decided to disallow the file open.

What actually happens is that the lower filter's call will cause the virtual memory system (cache manager and memory manager) to increment the reference count of the file object passed in the IRP_MJ_READ.  If this is the IRP_MJ_READ from the original IRP_MJ_CREATE, the reference count on that file object is incremented.

When the higher filter calls IoCancelFileOpen the I/O Manager issues an IRP_MJ_CLEANUP and IRP_MJ_CLOSE down to the lower filter and then to the file system - as if the reference count had in fact dropped to zero.  The higher filter then returns an error to the I/O Manager (or other OS component) and that component then discards the file object, even though there is a dangling reference from the virtual memory system.  Thus, later when the virtual memory system releases its reference to the "file object" it is now acting on a potentially arbitrary location in memory.  This can trigger random failures.

In the initial analysis, Microsoft developers indicated that this appears to be a bug in IoCancelFileOpen and the way it is used within Windows. On further investigation, there does not appear to be a fix that can be made that would only affect IoCancelFileOpen to address 100% of the issues that can arise, but Microsoft developers are exploring this issue in search of  a good solution.

OSR developers have suggested that in fact this is a bug in the lower filter because it is never safe to perform a cached I/O call IRP_MJ_READ or IRP_MJ_WRITE with the file object from the IRP_MJ_CREATE.  This is because some paths within the file system create fake (stack based) file objects in order to improve performance for operations that would not invoke the virtual memory system. Note: with NTFS, a non-cached I/O request is not honored in the case of compressed files.  Other (third party) file systems may similarly ignore a request for non-cached I/O.

At the present time our suggested work-around is for the filter to use IoCreateStreamFile, IoCreateStreamFileLite, or IoCreateStreamFileEx to create its own stream file object.  This new stream file object may then be used when setting up the next I/O stack location in the IRP.  The filter should then forward the IRP to the next driver synchoronously (this is normally done by blocking and waiting on a notification event that is set in the completion routine).  The stream file object may then be used for IRP_MJ_READ and IRP_MJ_WRITE operations safely.  When the filter is done using the stream file object, it may be dereferenced (potentially causing an IRP_MJ_CLEANUP and IRP_MJ_CLOSE) and Windows will delete it when appropriate.  If the original create is to be allowed to proceed, the IRP can then be sent (with the original file object) to the underlying driver for further processing.  Initial reports from developers are promising regarding this work around.

Regardless, we know this is an emerging issue.  Stay tuned for further information.

Additional Information (May 9, 2003)

Microsoft has indicated that the following calls may use stack-based file objects:

NtDeleteFile
NtQueryAttributesFile
NtQueryFullAttributesFile
IoFastQueryNetworkAttributes

And that these fake file objects may appear for the following operations:

IRP_MJ_CREATE
IRP_MJ_CLEANUP
IRP_MJ_CLOSE
IRP_MJ_QUERY_INFORMATION
FastIoQueryOpen
FastIoQueryBasicInfo
FastIoQueryStandardInfo
FastIoQueryNetworkOpenInfo

Further, the information from the Microsoft team indicates that this situation is unlikely to change in the forseeable future.

The previously described solution remains OSR's suggested solution.

Additional Information (July 10, 2003)

The Microsoft filter driver team has provided an alternative solution as well:

To work around this issue, the filter doing cached I/O to the file during IRP_MJ_CREATE processing should do the following:

Check to see if the file object address is within the current stack limits (IoGetStackLimits)
If the file object address is within the current stack limits, the filter should allocate its own file object (IoCreateStreamFileObject, or IoCreateStreamFileObjectLite), pass this stream file object down to the file system to be opened, then do the cached I/O against this file object.  This is a well-formed file object which will be cleaned up safely if this is the file object referenced by either the cache manager or the memory manager.
Here is the pseudo code for a filter that cancels create operations.  In your IRP_MJ_CREATE dispatch routine, before the operation has been passed down to the file system, if this is a create that you may wish to cancel, do the following:

//

// Pseudo code assumptions:

//

// Variables:

// NameToOpen ? A WCHAR buffer that contains the name the filter

// wants to open; most likely the same name specified by the

// user in the file object passed into the CREATE operation.

// The filter?s private file object must have its own copy of

// the file name buffer. In the code below, the NameToOpen

// is a full-path from the volume root.

// NameToOpenLength ? The length in bytes of NameToOpen

// IrpSp ? Pointer to the current IRP stack location

// UsersFileObject ? Local to store the file object passed in via

// the CREATE IRP.

//

//

// This API will create a FileObject and then issue the IRP_MJ_CLEANUP

// on this handle. This API is only available on Windows 2000 and later.

// On earlier OS versions, you can use IoCreateStreamFileObject and issue

// your own IRP_MJ_CLEANUP irp.

//

SwapFileObject = IoCreateStreamFileObjectLite( IrpSp->FileObject, NULL );

if (SwapFileObject != NULL) {

//

// We now need to initialize the file object just created. In most

// cases we can just to a full copy of the user?s file object and

// change the name fields.

//

RtlCopyMemory( SwapFileObject,

IrpSp->FileObject,

sizeof( FILE_OBJECT ) );


//

// This copy cleared the FO_STREAM_FILE flag that was set. It also

// cleared the FO_CLEANUP_COMPLETE flag that was set by the

// IoCreateStreamFileObjectLite processing (remember this API will

// send down the IRP_MJ_CLEANUP to the file system for this file object),

// but we want to leave that cleared so that FAT will allow us to

// open this file object.

//

SetFlag( SwapFileObject, FO_STREAM_FILE_OBJECT );


//

// Now setup the new name buffer in the FileObject.

//

SwapFileObject->FileName.Length =

SwapFileObject->FileName.MaximumLength =

NameToOpenLength;

SwapFileObject->FileName.Buffer = NameToOpen;

SwapFileObject->RelatedFileObject = NULL;

//

// Now replace the user?s file object with our new file object

//

UsersFileObject = IrpSp->FileObject;

IrpSp->FileObject = SwapFileObject;

//

// Now is also the time to save off any of the original IRP

// parameters and set your desired IRP parameters.

//

//

// < Insert code here to issue create and synchronize back >

// < to dispatch to process completion. >

//

//

// Post-create processing

//

//

// Remember up above when we didn?t restore this flag to the stream

// file object we allocated? It is now safe to reset it.

//


SetFlag( SwapFileObject->Flags, FO_CLEANUP_COMPLETE );

if (Status = STATUS_SUCCESS) {

//

// < Do whatever processing you need to on this opened file object >

// < before canceling the create. >

//

if (SwapFileObject->PrivateCacheMap != NULL) {

//

// Caching was setup on this file object. Since the

// CLEANUP has already been issued on this FileObject,

// the file system will not uninitialize the cache map

// for us. Do this now.

//

CcUninitializeCacheMap( SwapFileObject );

}

//

// < Reinitialize the IRP. >

//

//

// Now restore the user?s file object into the IRP so that the original

// create can be sent down.

//

IrpSp->FileObject = UsersFileObject;

//

// Finally, reissue the CREATE irp.

//

Status = IoCallDriver( TargetDeviceObject, Irp );

//

// < Insert the desired logic here to do the filter?s desired post- >

// < IoCallDriver processing of a CREATE. >

//

}

//

// We are now finished with our stream file object, so dereference it. The

// IRP_MJ_CLOSE will be issued to the file system when the last

// reference is released.

//

ObDereferenceObject( SwapFileObject );


User Comments
Rate this article and give us feedback. Do you find anything missing? Share your opinion with the community!
 Post Your Comment

"Just a little missprint"
SetFlag( SwapFileObject, FO_STREAM_FILE_OBJECT ); should be SetFlag( SwapFileObject, FO_STREAM_FILE );

10-Jul-05, Alexey Kucher (xxxx@uzhe.net)



--------------------------------------------------------------------------------
"Great article"
I found this solution very useful and it worked well. You may want to add that the user should set the stream file object name buffer to NULL before calling ObDereferenceObject. I spent about 20 minutes trying to figure out why I was getting a special pool access violation on the call to ObDereferenceObject.
Rating:      
02-Dec-04, Daniel Berkich (xxxx@berkich.com)

最新喜欢:

sijinsijin
http://www.zndev.com 免费源码交换网 ----------------------------- 软件创造价值,驱动提供力量! 淡泊以明志,宁静以致远。 ---------------------------------- 勤用搜索,多查资料,先搜再问。
fooegg
驱动小牛
驱动小牛
  • 注册日期2007-08-25
  • 最后登录2008-08-31
  • 粉丝0
  • 关注0
  • 积分1000分
  • 威望111点
  • 贡献值0点
  • 好评度110点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2007-10-11 14:39
班主在写blog,也有可能是灌水,见定完毕
毛主席夸我水灌得好
qdhaiky
驱动牛犊
驱动牛犊
  • 注册日期2005-09-26
  • 最后登录2013-03-15
  • 粉丝0
  • 关注0
  • 积分125分
  • 威望46点
  • 贡献值0点
  • 好评度12点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2007-10-11 16:27
嗯,很好,很关键的问题,好贴,除了看不懂以外
starsrain
驱动牛犊
驱动牛犊
  • 注册日期2005-02-20
  • 最后登录2008-08-08
  • 粉丝0
  • 关注0
  • 积分260分
  • 威望26点
  • 贡献值0点
  • 好评度26点
  • 原创分0分
  • 专家分0分
地板#
发布于:2007-10-16 10:58
不错 又学到东东了
znsoft
管理员
管理员
  • 注册日期2001-03-23
  • 最后登录2023-10-25
  • 粉丝300
  • 关注6
  • 积分910分
  • 威望14796点
  • 贡献值7点
  • 好评度2410点
  • 原创分5分
  • 专家分100分
  • 社区居民
  • 最爱沙发
  • 社区明星
地下室#
发布于:2008-04-10 17:43
冲突...
http://www.zndev.com 免费源码交换网 ----------------------------- 软件创造价值,驱动提供力量! 淡泊以明志,宁静以致远。 ---------------------------------- 勤用搜索,多查资料,先搜再问。
zhsh200
驱动牛犊
驱动牛犊
  • 注册日期2005-01-27
  • 最后登录2013-07-18
  • 粉丝0
  • 关注0
  • 积分25分
  • 威望212点
  • 贡献值1点
  • 好评度54点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2008-04-12 09:40
这贴好啊 ,解决了一个非常棘手的问题, 直接解决了 系统的稳定性问题
dreamsity
驱动小牛
驱动小牛
  • 注册日期2006-09-01
  • 最后登录2013-07-04
  • 粉丝0
  • 关注0
  • 积分40分
  • 威望821点
  • 贡献值1点
  • 好评度68点
  • 原创分1分
  • 专家分0分
6楼#
发布于:2008-05-12 18:34
这个问题还是有一点不是很清楚的地方:
使用CACHEIO的IRP_MJ_READ和IRP_MJ_WRITE会建立CACHE,文章中使用CcUninitializeCacheMap来释放CACHE。这里如果只有一个人访问这个文件则没有任何问题,但如果在多个人同时进入IRP_MJ_READ,调用CcUninitializeCacheMap是否就会需要文件打开计数的判断条件。
一切都是时间问题!
zss2003
驱动牛犊
驱动牛犊
  • 注册日期2010-08-16
  • 最后登录2011-12-14
  • 粉丝0
  • 关注1
  • 积分26分
  • 威望251点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2010-12-20 15:17
看着很晕。谁给翻译下?
游客

返回顶部