9

Windows 中的内核模式驱动程序是否有等效的线程本地存储 (TLS)(准确地说是 Win32)?

我试图达到的目标:

最终,在我的驱动程序的调度例程中,它可能会调用许多其他函数(可能有很深的调用堆栈)。我想提供一些特定于正在处理的请求的上下文信息。也就是说,我有一些结构,指向它的指针应该在所有被调用的函数中都是可见的,而不是显式地将它作为参数传递给每个函数。

使用静态/全局不是一个完美的选择(多线程、同步对象等)。

如果那是用户模式代码 - 在这种情况下显然会使用 TLS。但是 AFAIK 没有像TlsGetValue/这样的内核模式函数TlsSetValue。这是有道理的——要使这些功能正常工作,必须首先分配一个进程范围的 TLS 索引。OTOH 驱动程序代码可以在任意线程上调用,不限于特定进程。

但是,我实际上并不需要持久的特定于线程的存储。我只需要一个特定于线程的存储来进行顶级函数调用。

我想我知道如何“实施” TLS,尽管是以一种骇人听闻的方式。我不会分配 TLS 索引,而是始终使用预定义的索引(例如 index=0)。在顶级函数中,我将保存存储的 TLS 值,并用所需的值覆盖它。完成后,保存的值将被恢复。

幸运的是,我知道 TLS 在 Win32 中是如何实现的。每个线程都有一个TIB结构(线程信息块)。在每个线程中都可以使用FS:[18h]选择器访问它。包含(除其他外)TLS 使用的TIB数组。其余的非常简单。

但是我更喜欢使用官方 API 来实现类似的东西。

  • 是否有官方的内核模式 API 来实现我所需要的?
  • 是否有理由避免我打算做的事情?我知道重入可能存在问题(即某些代码调用我,我覆盖 TLS 值,然后最终调用可能依赖于 TLS 的原始代码)。但这在我的具体情况下是不可能的?
  • 有没有更脏的方法来解决这个问题?

提前致谢。

PS One 理论上可以使用 SEH(它还存储了每个线程的信息)。也就是说,用 包装顶层代码__try/__except,然后在需要上下文信息的地方 - 用一些参数引发可继续异常,在__except块中用上下文信息填充参数,然后恢复执行。这是一个 100% 有效的程序流程,没有使用未记录的功能。但尽管如此,这对我来说似乎是一个丑陋的 hack,更不用说性能上的复杂性了。

4

3 回答 3

8

与其使用 FS:[18h],不如使用 PsGetCurrentThreadTeb。即便如此,我认为您仍会依赖可能在未来操作系统版本中更改的细节(可能包括服务包)。

相反,您不能使用 KeGetCurrentProcessorNumber 作为数组的索引,您可以在其中存储指向上下文信息的指针吗?(当然,前提是您运行在 DISPATCH_LEVEL 或更高级别,这样您就不会意外切换到不同的处理器。)

如果不能保证在 DISPATCH_LEVEL 上运行,则可以使用表或链表,每个条目(表示当前正在运行代码的线程)都标有 PsGetCurrentThread 的值。

于 2012-03-21T01:04:37.957 回答
5

不要对 TEB 这样做!TIB 和 TEB 是用户模式结构。用户模式应用程序可以在您的驱动程序运行时从另一个线程/处理器随意修改这些内容。这将是您的驱动程序中的权限提升漏洞。

我建议为与您的请求相关的临时上下文传递上下文结构。如果您需要更永久的东西,您可以使用在线程退出时清理的 AVL 表或哈希表。

于 2012-05-06T17:07:42.333 回答
4

您可以创建一个包含传入请求的结构,然后传递它而不是实际请求,然后您只需输入您需要的任何字段。显然,这并不能完全消除传递对象的需要,但通常无论如何您都会传递请求。

从我见过的大多数驱动程序中(诚然,数量并不多),一切都始终以请求为中心。因此,他们总是将事情与请求联系起来,而不是试图将其保留在其他位置。

于 2012-03-21T00:05:22.687 回答