内核模式下的线程本地存储?

时间:2012-03-20 23:38:32

标签: windows winapi kernel thread-local-storage

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

我努力实现的目标:

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

使用static / global不是一个完美的选择(多线程,同步对象等)。

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

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

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

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

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

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

提前致谢。

P.S。理论上可以使用SEH(其还存储了每线程信息)。也就是说,将顶级代码包装为__try/__except,然后在需要上下文信息的位置 - 使用某个参数引发可持续异常,在__except块中填充参数用上下文信息,然后恢复执行。这是一个100%有效的程序流程,不使用未记录的功能。但对我来说这似乎是一个丑陋的黑客攻击,更不用说性能并发症了。

3 个答案:

答案 0 :(得分:8)

而不是使用FS:[18h]你应该使用PsGetCurrentThreadTeb。即便如此,我认为您依赖的细节可能会在未来的OS版本中发生变化(可能包括服务包)。

相反,您不能使用KeGetCurrentProcessorNumber作为数组的索引,您可以在其中存储指向上下文信息的指针吗? (当然,如果您在DISPATCH_LEVEL或更高级别运行,那么您将无法意外地切换到其他处理器。)

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

答案 1 :(得分:5)

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

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

答案 2 :(得分:4)

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

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