2012-03-20 65 views
8

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

我尽量做到:

从我的驱动程序的调度程序可以调用许多其它功能中

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

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

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

不过其实我并不需要一个持续线程专有存储。我只需要一个特定于线程的存储器用于我的顶级函数调用。

我想我知道如何“落实”的TLS,但在一个hackish的方式。我将永远使用预定义的索引(比如index = 0),而不是分配TLS索引。在顶层函数中,我将保存存储的TLS值,并用所需的值覆盖它。完成后,保存的值将被恢复。

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

但是我宁愿使用一个官方的API来实现类似的东西。

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

在此先感谢。

P.S.理论上可以使用SEH(也存储每线程信息)。也就是说,将顶级代码换成__try/__except,然后在需要上下文信息的地方 - 用继续例外的某些参数,在__except块中用参数填充上下文信息,然后恢复执行。这是一个100%有效的程序流程,不使用未记录的功能。但无论如何这似乎是一个丑陋的黑客攻击对我来说,更何况性能并发症。

回答

7

比使用FS相反:[18H]你应该使用PsGetCurrentThreadTeb。即使那样,我认为你会依赖未来操作系统版本可能会改变的细节(可能包括服务包)。

相反,不能使用KeGetCurrentProcessorNumber作为索引到一个数组,你可以存储指向您的上下文信息? (当然,假设你运行在DISPATCH_LEVEL或更高级别,所以你不能切换到不同的处理器。)

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

+0

优秀的答案,非常精确。我同意依靠特定的无证功能并不是一个好的做法。然而,我发现它非常难以想象TIB布局或访问方式可能会改变。此外,司机有不太严格的便携性要求恕我直言。使用全局数组并通过'KeGetCurrentProcessorNumber'访问它是一个非常好的主意。在我的特殊情况下,请求可能会到达IRQL的不确定位置,我不确定是否允许我提出这个请求(我称之为其他例程),但是绝对值得查看。 – valdo 2012-03-21 07:49:14

+0

P.S.一张“链表”表格正是我想摆脱的一件事。非常感谢。 – valdo 2012-03-21 07:49:53

+0

为什么你很难想象TIB的结构会发生变化? Win64必须改变了吗? ARM的情况可能会有所不同。即使这些字段保持不变,内核也不会重复使用它们来替代别的东西,并且会丢失数据(或者更糟糕的是,您可能会吹走它的数据)。 – Stewart 2012-03-21 15:38:20

4

您可以创建包含传入请求的结构,你通过这个周围,而不是实际的请求,那么你只是把你需要的任何领域。显然这并不能完全消除传递对象的需要,但通常你总是传递请求。

大多数我见过(这诚然是不是一个巨大的量)的一切总是司机东西要求中心。所以他们总是把事情与请求联系起来,而不是试图将它保存在其他位置。

+0

我的情况是有点问题更多。我使用C++(不要告诉我我是一个变态),并且我有一些代码在对象析构函数中执行,我无法传递额外的参数。 – valdo 2012-03-21 00:21:53

+0

+1,用于避免TLS之类的奇怪事物以及类似恐怖事件。所以有一些背景。它只是一个对象实例指针。如果有IO请求,请使用上下文实例ptr以及所有其他gunge加载它,就像您说的那样。 – 2012-03-21 22:12:02

+0

@马丁詹姆斯:我不知道为什么TLS被认为是“奇怪”。这在用户模式代码中非常有用。 – valdo 2012-03-22 19:07:12

4

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

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

+1

+1用于发现漏洞。但是请注意,OP已经解释了为什么他不能使用上下文结构(他需要来自对象析构函数的上下文,它不能传递参数),并且他已经在使用表并希望更有效。 – 2012-05-06 20:15:14