Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread-local storage in kernel mode?

Is there a Thread-Local Storage (TLS) equivalent for kernel-mode drivers in Windows (Win32 to be exact)?

What I try to achieve:

Eventually from within my driver's dispatch routine it may call many other functions (there may be a deep callstack). I want to supply some context information specific to the request being processed. That is, I have some structure, pointer to which should be visible in all the called functions, without explicitly passing it as a parameter to every function.

Using static/global is not a perfect option (multithreading, sync objects and etc.).

If that was a user-mode code - one would obviously use TLS in such a situation. But AFAIK there are no kernel-mode functions like TlsGetValue/TlsSetValue. And this makes sense - for those function to work one has to allocate a process-wide TLS index first. OTOH driver code may be invoked on arbitrary thread, not limited to a specific process.

However I don't actually need a persistent thread-specific storage. I just need a thread-specific storage for my top-level function invocation.

I think I know how to "implement" the TLS, though in a hackish way. Instead of allocating the TLS index I will always use a predefined index (say, index=0). At the top-level function I'll save the stored TLS value, and overwrite it with the needed value. Upon completion the saved value will be restored.

Luckily I know how the TLS is implemented in Win32. There's a TIB structure (thread information block) for each thread. In every thread it may be accessed using FS:[18h] selector. The TIB contains (among other things) an array used by TLS. The rest is pretty straightforward.

However I'd prefer to use an official API to achieve something similar.

  • Is there an official kernel-mode API to achieve what I need?
  • Are there reasons to avoid what I'm planning to do? I know there may potentially be a problem with re-entrance (i.e. some code invokes me, I overwrite the TLS value and then eventually call the originating code, which may rely on the TLS). But this is not possible in my specific case?
  • Are there less dirty ways to solve this?

Thanks in advance.

P.S. One may theoretically use SEH (which also has per-thread information stored). That is, wrap the top-level code by __try/__except, then where the context information is needed - raise the continuable exception with some parameter, in the __except block fill the parameter with the context information, and then resume the execution. And this is a 100% valid program flow, without use of the undocumented features. But nevertheless this seems an ugly hack for me, not to mention the performance complications.

like image 320
valdo Avatar asked Mar 20 '12 23:03

valdo


3 Answers

Rather than using FS:[18h] you should probably use PsGetCurrentThreadTeb. Even then, I think you'd be relying on details that might change in future OS releases (potentially including service packs).

Instead, couldn't you use KeGetCurrentProcessorNumber as an index into an array where you can store a pointer to your context information? (Provided that you're running at DISPATCH_LEVEL or higher, of course, so that you can't be switched to a different processor unexpectedly.)

If you're not guaranteed to be running at DISPATCH_LEVEL, you could use a table or linked list, with each entry (representing a thread that is currently running your code) labelled with the value of PsGetCurrentThread.

like image 144
Harry Johnston Avatar answered Nov 09 '22 09:11

Harry Johnston


Don't do this with the TEB! The TIB and TEB are usermode structures. A user-mode application can modify that stuff at will from another thread/processor while your driver is running. This would be a privilege escalation vulnerability in your driver.

I would recommend passing down a context structure for ephemeral context related to your request. If you need something more permanent, you could use an AVL table or a Hash table which you clean up when threads exit.

like image 37
Neeraj Singh Avatar answered Nov 09 '22 10:11

Neeraj Singh


You can create a structure that holds the incoming request, and you pass this around instead of the actual request, then you just put in any fields you need. Obviously this doesn't completely remove the need to pass an object around, but normally you are passing the request around anyway.

From most of the driver stuff I've seen (which admittedly isn't a huge amount) everything was always request centric. So they always tied things to the request instead of trying to keep it in some other location.

like image 21
Zipper Avatar answered Nov 09 '22 08:11

Zipper