Run-Down 保护

Run-Down 保护

https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/run-down-protection

*       从Windows XP 开始,内核可以使用 run-down 保护。驱动可以使用run-down 保护来安全访问另一个内核模式驱动在共享系统内存中创建和删除的对象。(这里“删除”的意思是,在这种机制的保护下使用者正常访问对象即可,不用担心对象被删除)。
       当一个对象的所有未完成的访问都已经完成而且没有任何新的对于该对象的访问请求被满足的时候,一个对象被称为 run down。比如,当一个对象需要被删除并用一个新的对象替换的时候,它需要被run down。
       拥有该共享对象的驱动可以赋予其它驱动“获得和释放run down 保护”的能力。当 run-down 保护实施的时候,对象的拥有者外的驱动可以访问该对象,而不用担心对象拥有者将在操作完成之前删除对象。 在访问对象之前,驱动请求run-down 保护。对于一个生命周期长的对象来说,这个请求几乎总是被满足的。 访问完成后,访问驱动释放它之前获得的run-down 保护。

主要run-down 保护例程

       开始分享一个对象之前,拥有该对象的驱动调用 ExInitializeRundownProtection 函数来初始化对象的run-down 保护。这个调用之后,其它访问对象的驱动可以在该对象上执行获得和释放run-down 保护的操作。
       一个访问共享对象的驱动应该调用 ExAcquireRundownProtection 函数请求对象的run-down 保护,访问完成后,驱动调用ExReleaseRundownProtection 函数来释放对象的run-down 保护。
       如果对象拥有者驱动决定共享对象必须被删除,该驱动必须等待所有的未完成的访问都完成了才能删除该对象。在准备删除该驱动的时候,拥有者驱动调用ExWaitForRundownProtectionRelease 函数等待对象变为run down 状态,这个函数调用期间,ExWaitForRundownProtectionRelease 等待所有之前授予的对于该对象的run-down 保护被释放,并禁止新的对于该对象的run-down 保护请求。在最后一个对于该对象的保护访问完成,且所有的run-down 保护实例被释放之后ExWaitForRundownProtectionRelease 返回,拥有者驱动可以安全地删除该对象。
       为了避免 ExWaitForRundownProtectionRelease 阻塞太长时间,拥有对象的run-down保护的线程应该避免被APC中断。因此,应该在一个关键区(这个不是只能禁止普通内核APC???)或者守护区或者IRQL >=APC的块中调用 ExAcquireRundownProtection 和ExReleaseRundownProtection 函数。

run-down 保护的用处

       有些对象经常是可以获得的,但是偶尔需要被删除和被替换,Run-down 保护在为这样的共享对象提供访问的时候是非常有用的。访问数据或者调用这个对象的函数的驱动不能在对象被删除之后再去访问它。否则,将导致不可预测的错误。
       例如,一个典型的反病毒驱动在操作系统运行的时候是常驻内存的。 偶尔,这个驱动可能需要被卸载并替换成一个更新的驱动的发行版本。在发送一个I/O 请求之前,一个内核组件,比如说文件系统过滤管理器,可以获得一个run-down 保护来防止在反病毒驱动处理I/O 请求的受过早的被卸载。在I/O 请求完成后,run-down 保护可以被释放。
       Run-down 保护并不会序列化对于共享对象的访问。如果有两个或者更多的驱动可以同时拥有一个对象的run-down 保护,对于该对象的访问必须被序列化,使用其它的一些同步机制,比如互斥锁,以同步对于对象的访问。

EX_RUNDOWN_REF 结构

       一个EX_RUNDOWN_REF 结构跟踪一个共享对象的run-down 保护的状态。结构对于驱动是透明的。系统提供的run-down 保护函数使用这个结构记录当前影响对象的run-down 保护的实例的计数。另外,这些函数也使用这个结构来跟踪是否这个对象是run-down 状态或者是否正在进行run-down 的相关处理。
       拥有对象的驱动调用ExInitializeRundownProtection 来初始对象绑定的EX_RUNDOWN_REF 结构以开始共享一个对象。在初始化完毕之后,拥有者驱动使这个结构体可以被其它想要获得对象访问权限的驱动获得。访问进程以这个结构体为参数调用ExAcquireRundownProtection 和ExReleaseRundownProtection 分别获得和释放对象的run-down 保护。拥有者驱动将此结构作为参数传递给 ExWaitForRundownProtectionRelease 函数以等待对象run-down并删除对象。

与锁的比较

       Run-down 保护是保证安全访问共享对象的多种机制之一。 另一种方法是使用互斥软件锁。如果一个驱动请求访问一个已经被另一个驱动锁住的对象,它必须等待拥有的锁的驱动释放锁。获取和释放锁将降低系统性能,而且锁会消耗大量内存。不当使用还可能导致死锁。检测和避免死锁通常需要大量计算资源的转移。
       相比于锁, run-down 保护需要相对少的计算时间和内存。对象有一个简单的引用计数,以保证对象的删除操作延迟到所有的未完成的访问都结束之后。有了这个功能,原子的、互锁的硬件指令可以替代互斥软件锁来保证对于一个对象的安全访问。获取和释放run-down 保护的函数执行起来通常比较快速。在一个比较长寿命的,有许多驱动访问的共享 对象上,使用一个轻量的机制所能带来的好处是比较有效和有意义的。

其它的 run-down 保护函数

       除了前面提到的几个run-down 保护函数,还有几个可能被其它驱动调用的函数。
       ExReInitializeRundownProtection 函数使得之前使用过的 EX_RUNDOWN_REF 结构与一个新的对象绑定,并对其进行初始化。
       ExRundownCompleted 函数更新 EX_RUNDOWN_REF 结构以提示绑定的对象的run-down 已经完成。
       ExAcquireRundownProtectionEx 与ExReleaseRundownProtectionEx函数和 ExAcquireRundownProtection 与ExReleaseRundownProtection. 相似。但是 ExAcquireRundownProtection 和ExReleaseRundownProtection影响计数时仅仅影响“1”,而 ExAcquireRundownProtectionEx 和ExReleaseRundownProtectionEx 以任意指定的数值影响计数。

猜你喜欢

转载自blog.csdn.net/qq_18218335/article/details/78187919