I/O 验证
驱动程序验证程序有两个级别的 I/O 验证:
选择 I/O 验证时,级别 1 I/O 验证 始终处于活动状态。
每当在 Windows XP 及更高版本中选择 I/O 验证时,级别 2 I/O 验证 始终处于活动状态。
另请参阅:在 Windows 7 及更高版本的 Windows 操作系统中增强的 I/O 验证,选择“I/O 验证”时,将自动激活增强的 I/O 验证。 它不可用或需要将其选为单独的选项。
级别 1 I/O 验证
启用级别 1 I/O 验证后,将从特殊池分配通过 IoAllocateIrp 获取的所有 IRP ,并跟踪其使用。
此外,驱动程序验证程序检查无效的 I/O 调用,包括:
尝试释放类型不IO_TYPE_IRP的 IRP
将无效设备对象传递到 IoCallDriver
将 IRP 传递到 IoCompleteRequest ,其中包含无效状态或仍具有取消例程集
通过调用驱动程序调度例程更改 IRQL
尝试释放与线程关联的 IRP
将设备对象传递给已包含已初始化计时器的 IoInitializeTimer
将无效缓冲区传递到 IoBuildAsynchronousFsdRequest 或 IoBuildDeviceIoControlRequest
将 I/O 状态块传递到 IRP,当此 I/O 状态块在已取消部署太远的堆栈上分配时
将事件对象传递到 IRP,当此事件对象在已取消部署太远的堆栈上分配时
由于特殊 IRP 池的大小有限,因此 I/O 验证在一次仅在一个驱动程序上使用时最有效。
I/O 验证级别 1 失败会导致发出 bug 检查0xC9。 此 bug 检查的第一个参数指示发生了冲突。 有关完整参数列表,请参阅 Bug 检查0xC9 (DRIVER_VERIFIER_IOMANAGER_VIOLATION)。
级别 2 I/O 验证
I/O 验证级别 2 错误以不同的方式显示:在蓝屏、故障转储文件中和内核调试器中。
在蓝屏上,这些错误由消息 IO 系统验证错误和字符串 WDM DRIVER ERRORXXX 指出,其中 XXX 是 I/O 错误代码。
在故障转储文件中,大多数错误都由 消息 BugCheck 0xC9(DRIVER_VERIFIER_IOMANAGER_VIOLATION)以及 I/O 错误代码记录。 在这种情况下,I/O 错误代码显示为 bug 检查的第一个参数0xC9。 其余部分由消息 Bug 检查0xC4(DRIVER_VERIFIER_DETECTED_VIOLATION)以及驱动程序验证程序错误代码记录。 在这种情况下,驱动程序验证程序错误代码显示为 bug 检查的第一个参数0xC4。
在内核调试器(KD 或 WinDbg)中,这些错误由消息 WDM DRIVER ERROR 和描述性文本字符串记录。 当内核调试器处于活动状态时,可以忽略级别 2 错误并恢复系统操作。 (无法进行任何其他 bug 检查。
蓝屏、故障转储文件和内核调试器也显示其他信息。 有关大多数 I/O 验证级别 2 错误消息的完整说明,请参阅 bug 检查0xC9。 有关其余部分,请参阅 bug 检查0xC4。
从 Window Vista 开始,I/O 验证选项将检查以下驱动程序错误:
需要很长时间才能完成和取消源自用户模式应用程序的 IRP。
释放尚未获取的删除锁。
使用与相应 IoAcquireRemoveLock 调用中使用的标记参数不同的标记参数调用 IoReleaseRemoveLock 或 IoReleaseRemoveLockAndWait。
在 IRQL 上调用大于 DISPATCH_LEVEL 的 IoCallDriver。
从禁用中断的驱动程序调度例程返回。
从具有已更改 IRQL 的驱动程序调度例程返回。
从禁用 APC 的驱动程序调度例程返回。 在这种情况下,驱动程序可能比 KeLeaveCriticalRegion 多次调用 KeEnterCriticalRegion,这是 Bug 检查0x20(KERNEL_APC_PENDING_DURING_EXIT)和 Bug 检查0x1(APC_INDEX_MISMATCH)的主要原因。
从 Windows 7 开始,I/O 验证选项将检查以下驱动程序错误:
- 尝试通过调用 ExFreePool 来释放 IRP。 必须使用 IoFreeIrp 释放 IRP。
此外,可以使用此选项检测另一个常见的驱动程序 bug - 重新初始化删除锁。 删除锁数据结构应在设备扩展内分配。 这可确保 I/O 管理器仅在删除设备对象时释放保存IO_REMOVE_LOCK结构的内存。 如果驱动程序执行以下三个步骤,那么在步骤 2 之后,应用程序或驱动程序仍保留对 Device1 的引用:
- 分配与 Device1 对应的IO_REMOVE_LOCK结构,但在 Device1 扩展之外进行分配。
- 删除 Device1 时调用 IoReleaseRemoveLockAndWait。
- 为同一锁调用 IoInitializeRemoveLock ,以将其重用为 Device2 的删除锁。
在步骤 2 之后,应用程序或驱动程序仍保留对 Device1 的引用。 即使删除了此设备,应用程序或驱动程序仍可将请求发送到 Device1。 因此,在 I/O 管理器删除 Device1 之前,重复使用与新删除锁相同的内存是不安全的。 当另一个线程尝试获取锁时重新初始化同一锁可能会导致锁损坏,驱动程序和整个系统的结果不可预知。
在 Windows 7 及更高版本的 Windows 操作系统中,选择“I/O 验证”时, 将自动激活增强的 I/O 验证 。
激活此选项
可以使用驱动程序验证程序管理器或Verifier.exe命令行为一个或多个驱动程序激活 I/O 验证功能。 有关详细信息,请参阅 “选择驱动程序验证程序选项”。
在命令行。
在命令行中,I/O 验证选项由 位 4 (0x10) 表示。 若要激活 I/O 验证,请使用标志值0x10或向标志值添加0x10。 例如:
verifier /flags 0x10 /driver MyDriver.sys
下一次启动后,该功能将处于活动状态。
还可以通过将 /volatile 参数添加到命令来激活和停用 I/O 验证,而无需重新启动计算机。 例如:
verifier /volatile /flags 0x10 /adddriver MyDriver.sys
此设置立即生效,但在关闭或重新启动计算机时会丢失。 有关详细信息,请参阅 “使用易失性设置”。
标准设置中还包括 I/O 验证功能。 例如:
verifier /standard /driver MyDriver.sys
使用驱动程序验证程序管理器
- 选择“ 创建自定义设置”(面向代码开发人员), 然后单击“ 下一步”。
- 从完整列表中选择单个设置。
- 选择(检查) I/O 验证。
标准设置中还包括 I/O 验证功能。 若要使用此功能,请在驱动程序验证程序管理器中,单击“ 创建标准设置”。