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 值。 或者,驱动程序可以从描述所请求的 I/O 操作的 IRP 结构中读取 RequestorMode 字段。 RequestorMode 字段包含请求操作的线程的 PreviousMode 值的副本。