PreviousMode

当用户模式应用程序调用本机系统服务例程的 NtZw 版本时,系统调用机制会将调用线程捕获到内核模式。 若要指示参数值源自用户模式,系统调用的陷阱处理程序会将调用方线程对象的PreviousMode 字段设置为 UserMode。 本机系统服务例程检查调用线程的 PreviousMode 字段,以确定参数是否来自用户模式源。

如果内核模式驱动程序调用本机系统服务例程并将参数值传递给来自内核模式源的例程,驱动程序必须确保当前线程对象中的 PreviousMode 字段设置为 KernelMode

内核模式驱动程序可以在任意线程的上下文中运行,并且此线程的 PreviousMode 字段可能设置为 UserMode。 在这种情况下,内核模式驱动程序可以调用本机系统服务例程的 Zw 版本,以通知例程参数值来自受信任的内核模式源。 Zw 调用将转到一个精简包装函数,该函数替代当前线程对象中的 PreviousMode 值。 包装函数将 PreviousMode 设置为 KernelMode ,并调用例程的 Nt 版本。 从例程的 Nt 版本返回时,包装函数将还原线程对象的原始 PreviousMode 值并返回。

内核模式驱动程序可以直接调用本机系统服务例程的 Nt 版本。 当内核模式驱动程序处理可以源自用户模式或内核模式的 I/O 请求时,驱动程序可以调用例程的 Nt 版本,以便当前线程的 PreviousMode 值在调用期间保持不变。 NtXxx 例程检查调用线程的 PreviousMode 值,以确定参数值是来自用户模式应用程序还是内核模式组件,并相应地处理它们。

如果内核模式驱动程序调用 NtXxx 例程,并且当前线程对象中的 PreviousMode 值无法准确指示参数值是来自用户模式还是内核模式源,则可能会出现错误。

例如,假设内核模式驱动程序在任意线程的上下文中运行,并且此线程的 PreviousMode 值设置为 UserMode。 如果驱动程序将内核模式文件句柄传递给 NtClose 例程,则此例程会检查 PreviousMode 值,并确定句柄必须是用户模式句柄。 当 NtClose 在用户模式句柄表中找不到句柄时,它将返回STATUS_INVALID_HANDLE错误代码。 同时,驱动程序会泄漏内核模式句柄,该句柄从未关闭。

例如,如果 NtXxx 例程的参数包括输入或输出缓冲区,如果 PreviousMode = UserMode,则例程调用 ProbeForReadProbeForWrite 例程来验证缓冲区。 如果在系统内存而不是用户模式内存中分配了缓冲区, ProbeForXxx 例程将引发异常, NtXxx 例程返回STATUS_ACCESS_VIOLATION错误代码。

如有必要,驱动程序可以调用 ExGetPreviousMode 例程,从当前线程对象获取 PreviousMode 值。 或者,驱动程序可以从 IRP 结构中读取 RequestorMode 字段,该结构描述所请求的 I/O 操作。 RequestorMode 字段包含请求作的线程中的 PreviousMode 值的副本。