静态和动态验证工具
有两种基本类型的验证工具:
静态验证工具 在不运行驱动程序的情况下检查驱动程序代码。 由于这些工具不依赖于执行代码的测试,因此它们可能非常彻底。 从理论上讲,静态验证工具可以检查所有驱动程序代码,包括在实践中很少执行的代码路径。 但是,由于驱动程序实际上未运行,因此它们可能会生成误报结果。 也就是说,它们可能会报告在实践中可能不会发生的代码路径中的错误。
动态验证工具 在驱动程序运行时检查驱动程序代码,通常通过截获对常用驱动程序支持的例程的调用,并将调用替换为同一例程自己的错误检查版本。 由于驱动程序实际上是在动态工具执行验证时运行的,因此很少出现误报结果。 但是,由于动态工具仅检测监视驱动程序时发生的操作,因此如果驱动程序测试覆盖率不足,这些工具可能会错过某些驱动程序缺陷。 同时,通过使用运行时可用的信息,例如,从源代码中静态提取更难的信息,动态验证工具可以检测某些类型的驱动程序错误,而使用静态分析工具更难检测到这些错误。
最佳做法是结合使用静态和动态验证工具。 静态工具允许你检查在实践中难以练习的代码路径,而动态工具则发现驱动程序中发生的严重错误。
重要
Windows 硬件兼容性计划要求在我们的客户端和服务器操作系统上使用 CodeQL 进行静态工具徽标 (STL) 测试。 我们将继续在旧版产品上支持 SDV 和 CA。 我们强烈建议合作伙伴查看 CodeQL 对静态工具徽标测试的要求。 有关使用 CodeQL 的详细信息,请参阅 CodeQL 和静态工具徽标测试。
验证工具调查
WDK 中介绍了以下验证工具,建议供驱动程序开发人员和测试人员使用。 它们按通常使用的顺序列出。
代码编译后立即
- GitHub 的 CodeQL 是一个强大的语义代码分析引擎,它结合了广泛的高价值安全查询套件和强大的平台,是保护驱动程序代码安全的宝贵工具。 有关详细信息,请参阅 CodeQL 和静态工具徽标测试。
其他静态工具
根据要从中生成驱动程序的 Windows 版本,可能需要其他静态工具。
驱动程序 的代码分析是在编译时运行的静态验证工具。 驱动程序的代码分析可以验证使用 C/C++ 和托管代码编写的驱动程序。 它会独立检查驱动程序的每个函数中的代码,以便一旦生成驱动程序即可运行它。 它运行速度相对较快,使用较少的资源。
Visual Studio 中代码分析工具的基本功能可检测常规编码错误,例如不检查返回值。 特定于驱动程序的功能可检测更微妙的驱动程序编码错误,例如在复制的 IRP 中保留未初始化的字段,并在例程结束时未能还原更改的 IRQL。
静态驱动程序验证程序 (SDV)是在编译时运行的静态验证工具,并验证以 C/C++ 编写的内核模式驱动程序代码。 它包含在 WDK 中,可以从 Visual Studio Ultimate 2012 或从使用 MSBuild 的 Visual Studio 命令提示符窗口启动。
静态驱动程序验证程序根据一组接口规则和操作系统模型来确定驱动程序是否与 Windows 操作系统内核正确交互。 静态驱动程序验证程序非常彻底 -- 它探索驱动程序源代码中的所有可访问路径,并象征性地执行它们。 因此,它会发现使用任何其他常规驱动程序测试方法未检测到的 bug。
重要
不再支持 SDV,并且 Windows 24H2 WDK 或 EWDK 版本中不提供 SDV。 它在版本 26017 之前的 WDK 中不可用,并且不包括在 Windows 24H2 RTM WDK 中。
通过从 下载 Windows 驱动程序工具包(WDK)下载 Windows 11 版本 22H2 EWDK(2023 年 10 月 24 日发布)和 Visual Studio 生成工具 17.1.5,仍可使用 SDV。 建议仅使用企业 WDK 运行 SDV。 不建议将旧版标准 WDK 与 Visual Studio 的最新版本结合使用,因为这可能会导致分析失败。
今后,CodeQL 将成为驱动程序的主要静态分析工具。 CodeQL 提供了一种功能强大的查询语言,可将代码视为要查询的数据库,使编写特定行为、模式等查询变得简单。
有关使用 CodeQL 的详细信息,请参阅 CodeQL 和静态工具徽标测试。
驱动程序运行时
在生成驱动程序并运行时立即使用以下动态验证工具,而不会出现明显的错误。
驱动程序验证程序 是专为 Windows 驱动程序编写的动态验证工具。 它包括多个可以同时在多个驱动程序上运行的测试。 驱动程序验证程序在驱动程序中发现严重 bug 时非常有效,经验丰富的驱动程序开发人员和测试人员将驱动程序验证程序配置为在开发或测试环境中运行时运行。 驱动程序验证程序包含在 Windows 中。 为驱动程序启用驱动程序验证程序时,还必须对驱动程序运行多个测试。 驱动程序验证程序可以仅使用静态验证工具检测难以检测的某些驱动程序 bug。 这些类型的 bug 的示例包括:
内核池缓冲区溢出。 当已验证的驱动程序分配池内存缓冲区时,驱动程序验证程序使用不可访问的内存页对其进行保护。 如果驱动程序尝试使用缓冲区末尾的内存,驱动程序验证程序将发出 bug 检查。
释放内存后使用内存。 特殊的池内存块使用自己的内存页,并且不与其他分配共享内存页。 当驱动程序释放池内存块时,相应的内存页将变为不可访问。 如果驱动程序在释放内存后尝试使用该内存,驱动程序将立即崩溃。
在提升的 IRQL 运行时使用可分页内存。 当验证的驱动程序在DISPATCH_LEVEL或更高时引发 IRQL 时,驱动程序验证程序会从系统工作集中剪裁所有可分页内存,从而模拟内存压力下的系统。 如果驱动程序尝试使用这些可分页的虚拟地址之一,驱动程序会崩溃。
资源模拟不足。 若要在资源不足的情况下模拟系统,驱动程序验证程序可能会使驱动程序调用的各种操作系统内核 API 失败。
内存泄漏。 驱动程序验证程序跟踪驱动程序进行的内存分配,并确保在卸载驱动程序之前释放内存。
需要太多时间才能完成或取消的 I/O 操作。 驱动程序验证程序可以测试驱动程序的逻辑,以响应来自 IoCallDriver 的STATUS_PENDING返回值。
DDI 符合性检查。 (从 Windows 8 开始可用)驱动程序验证程序应用一组设备驱动程序接口(DDI)规则,这些规则检查驱动程序与操作系统的内核接口之间的正确交互。 这些规则对应于静态驱动程序验证程序在分析驱动程序源代码时使用的规则。 如果驱动程序验证程序在启用 DDI 符合性检查时发现错误,请运行 静态驱动程序验证程序 并选择导致错误的相同规则。 静态驱动程序验证程序可以帮助你找到驱动程序源代码中缺陷的原因。
内核地址清理器(KASAN)是 Windows 驱动程序支持的 bug 检测技术,可用于检测多个非法内存访问类,例如缓冲区溢出和使用无后事件。
应用程序验证程序 是一种动态验证工具,适用于使用 C/C++ 编写的用户模式应用程序和驱动程序。 它不验证托管代码。