Windows中的内核模式驱动程序是否有等效的线程局部存储(TLS)(确切地说是Win32)?
我努力实现的目标:
最终,在我的驱动程序的调度程序中,它可能会调用许多其他函数(可能存在深度调用)。我想提供一些特定于正在处理的请求的上下文信息。也就是说,我有一些结构,指针应该在所有被调用的函数中都可见,而不是将它作为参数显式传递给每个函数。
使用static / global不是一个完美的选择(多线程,同步对象等)。
如果那是用户模式代码 - 在这种情况下显然会使用TLS。但是AFAIK没有像TlsGetValue
/ TlsSetValue
这样的内核模式函数。这是有道理的 - 要使这些功能工作,必须首先分配一个进程范围的TLS索引。 OTOH驱动程序代码可以在任意线程上调用,不限于特定进程。
但实际上我并不需要持久性特定于线程的存储。我只需要一个特定于线程的存储来进行我的顶级函数调用。
我想我知道如何“实施”TLS,虽然是以一种黑客的方式。我将始终使用预定义的索引(例如,index = 0),而不是分配TLS索引。在顶级函数中,我将保存存储的TLS值,并用所需的值覆盖它。完成后,将恢复保存的值。
幸运的是,我知道如何在Win32中实现TLS。每个线程都有一个TIB
结构(线程信息块)。在每个线程中,可以使用FS:[18h]
选择器访问它。 TIB
包含(以及其他内容)TLS使用的数组。其余的很简单。
但是我更喜欢使用官方API来实现类似的功能。
提前致谢。
P.S。理论上可以使用SEH(其还存储了每线程信息)。也就是说,将顶级代码包装为__try/__except
,然后在需要上下文信息的位置 - 使用某个参数引发可持续异常,在__except
块中填充参数用上下文信息,然后恢复执行。这是一个100%有效的程序流程,不使用未记录的功能。但对我来说这似乎是一个丑陋的黑客攻击,更不用说性能并发症了。
答案 0 :(得分:8)
而不是使用FS:[18h]你应该使用PsGetCurrentThreadTeb。即便如此,我认为您依赖的细节可能会在未来的OS版本中发生变化(可能包括服务包)。
相反,您不能使用KeGetCurrentProcessorNumber作为数组的索引,您可以在其中存储指向上下文信息的指针吗? (当然,如果您在DISPATCH_LEVEL或更高级别运行,那么您将无法意外地切换到其他处理器。)
如果您不能保证在DISPATCH_LEVEL上运行,则可以使用表或链表,每个条目(表示当前正在运行您的代码的线程)标记为PsGetCurrentThread的值。
答案 1 :(得分:5)
请勿使用TEB执行此操作! TIB和TEB是用户模式结构。用户模式应用程序可以在驱动程序运行时从另一个线程/处理器随意修改这些内容。这将是您的驱动程序中的权限提升漏洞。
我建议传递与您的请求相关的短暂上下文的上下文结构。如果你需要更永久的东西,可以使用AVL表或哈希表,当线程退出时你可以清理它。
答案 2 :(得分:4)
您可以创建一个保存传入请求的结构,然后传递它而不是实际请求,然后您只需输入所需的任何字段。显然,这并不能完全消除传递对象的需要,但通常你无论如何都要传递请求。
从我见过的大多数驱动程序(实际上并不是一个巨大的数量),一切都始终以请求为中心。因此,他们总是将事情与请求联系起来,而不是试图将其保留在其他位置。