驱动程序验证程序中的特殊池内存损坏检测

内存损坏是一个常见的驱动程序问题。 驱动程序错误可能会导致在发生错误后很长时间内发生崩溃。 其中最常见的错误是访问已释放的内存,分配 n 个字节,然后访问 n+1 个字节。

若要检测内存损坏,驱动程序验证程序可以从特殊池分配驱动程序内存,并监视该池是否存在不正确的访问。 为内核模式系统提供的例程(例如 ExAllocatePoolWithTag )和 GDI 系统提供的例程(如 EngAllocMem)提供特殊池支持。

按对齐方式的特殊池

特殊池的两种对齐方式可用:

  • 验证“开始”对齐方式在检测访问不足时效果更好。
  • 验证结束对齐方式在检测访问溢出时效果更好。

有关如何使用 “验证开始” 和“ 验证结束 ”选项的详细信息,请参阅 检测溢出和不足。 请注意,绝大多数内存损坏是由于 溢出而不是不足造成的。

当“特殊池”功能处于活动状态并且已选择 “验证结束” 时,驱动程序请求的每个内存分配将放在单独的页上。 返回允许分配适合页面的最高地址,以便内存与页的末尾对齐。 页面的上一部分是用特殊模式编写的。 上一页和下一页标记为不可访问。

如果驱动程序在分配结束后尝试访问内存,驱动程序验证程序将立即检测到此情况,并将 0xCD发出 Bug 检查。 如果驱动程序在缓冲区开始之前在内存中写入,这 (大概) 更改模式。 释放缓冲区后,驱动程序验证程序将检测更改并发出 bug 检查0xC1

如果驱动程序在释放缓冲区后读取或写入缓冲区,驱动程序验证程序将 0xCC发出 Bug 检查

选择 “验证开始 ”时,内存缓冲区与页面开头对齐。 使用此设置时,不足会导致立即检查 bug,而溢出会导致在释放内存时检查 bug。 否则,此选项与 “验证结束” 选项相同。

验证 End 是默认对齐方式,因为溢出错误在驱动程序中比不足错误更常见。

单个内存分配可以替代这些设置,并通过调用 ExAllocatePoolWithTagPriority 并将 Priority 参数设置为 XxxSpecialPoolOverrun 或 XxxSpecialPoolUnderrun 来选择其对齐方式。 (此例程无法激活或停用特殊池功能,或请求特殊池进行内存分配,否则将从普通池中分配。只能从此例程控制对齐。)

在 Windows 7 及更高版本的 Windows 操作系统中,“特殊池”选项支持使用以下内核 API 分配的内存:

按池标记或分配大小划分的特殊池

除了驱动程序验证程序的特殊池功能(用于请求指定 驱动程序分配的特殊池)外,还有两种其他方法可以使用特殊池:

  • 池标记。 为具有指定池标记的所有分配请求特殊池。

  • 大小。 为指定大小范围内的所有分配请求特殊池。

若要请求池标记或大小范围的特殊池,请使用 Gflags,这是 Windows 调试工具中包含的工具。 有关详细信息,请参阅 使用全局标志实用工具

可以同时使用驱动程序验证程序的特殊池功能和 Gflags 的特殊池功能。 如果这样做,请记住,特殊池是有限的,并非所有从特殊池进行分配的尝试都成功,并且 Windows 将返回从常规内存池分配满足的特殊池分配失败的尝试成功状态。

特殊池效率

并非所有特殊池请求都得到满足。 来自特殊池的每个分配都使用一页不可分页的物理内存和两页虚拟地址空间。 如果池已用尽,则以标准方式分配内存,直到特殊池再次可用。 当从标准池填充特殊池请求时,请求函数不会返回错误,因为池请求已成功。 因此,如果激活了特殊池功能,则不建议同时验证多个驱动程序。

发出许多小内存请求的单个驱动程序也可能耗尽此池。 如果发生这种情况,最好将池标记分配给驱动程序的内存分配,并将特殊池一次专用于一个池标记。

特殊池的大小随着系统上的物理内存量而增加;理想情况下,这至少应为 1 GB (GB) 。 在 x86 计算机上,由于虚拟 (除了占用物理) 空间外,请勿使用 /3GB 启动选项。 最好将页面文件最小/最大数量增加 2 或 3 个因子。

为了确保所有驱动程序的分配都经过测试,建议长时间强调驱动程序。

监视特殊池

可以监视与池分配相关的统计信息。 这些可由驱动程序验证程序管理器、Verifier.exe 命令行或日志文件显示。 有关详细信息 ,请参阅监视全局计数器

如果 “特殊池中的池分配成功 ”计数器等于 “池分配成功 ”计数器,则特殊池已足以涵盖所有内存分配。 如果前一个计数器低于后者,则特殊池已用尽至少一次。

这些计数器不跟踪大小为一页或更大的分配,因为特殊池不适用于它们。

如果启用了特殊池功能,但只有不到 95% 的池分配已从特殊池分配,驱动程序验证程序管理器中将显示警告。 在 Windows 2000 中,此警告将显示在 “驱动程序状态” 屏幕上。 在 Windows XP 及更高版本中,此警告将显示在 全局计数器 屏幕上。 如果发生这种情况,应验证较短的驱动程序列表、按池标记验证单个池,或向系统添加更多物理内存。

内核调试器扩展 !验证程序 也可用于监视特殊池使用情况。 它提供与驱动程序验证程序管理器类似的信息。 有关调试器扩展的信息,请参阅 Windows 调试

激活特殊池选项

可以使用驱动程序验证程序管理器或 Verifier.exe 命令行为一个或多个驱动程序激活特殊池功能。 有关详细信息,请参阅 选择驱动程序验证程序选项

注意

若要按池标记或分配大小激活特殊池功能,或者要设置 “验证开始” (检测不足) 和 验证结束 (检测溢出) 对齐方式,请使用 全局标志实用工具;这些对齐设置适用于所有特殊池分配。

  • 在命令行

    在命令行中,“特殊池”选项由 位 0 (0x1) 表示。 若要激活特殊池,请使用标志值0x1或向标志值添加0x1。 例如:

    verifier /flags 0x1 /driver MyDriver.sys
    

    下次启动后,该功能将处于活动状态。

    Y 还可以通过将 /volatile 参数添加到 命令来激活和停用特殊池,而无需重启计算机。 例如:

    verifier /volatile /flags 0x1 /adddriver MyDriver.sys
    

    此设置会立即生效,但在关闭或重启计算机时会丢失。 有关详细信息,请参阅 使用易失性设置

    特殊池功能也包含在标准设置中。 例如:

    verifier /standard /driver MyDriver.sys
    
  • 使用驱动程序验证程序管理器

    1. 选择“ 为代码开发人员) 创建自定义设置 ( ”,然后单击“ 下一步”。
    2. 从完整列表中选择“选择单个设置”。
    3. 选择“ (检查) 特殊池”。

    特殊池功能也包含在标准设置中。 若要使用此功能,请在驱动程序验证程序管理器中单击“创建标准设置”。