Thread-lokaler Speicher im Kernel-Modus?

8

Gibt es eine Thread-Local Storage (TLS) Entsprechung für Kernel-Modus-Treiber in Windows (Win32 um genau zu sein)?

Was ich versuche zu erreichen:

Irgendwann aus der Dispatch-Routine meines Treibers kann es viele andere Funktionen aufrufen (es kann einen tiefen Callstack geben). Ich möchte einige Kontextinformationen angeben, die spezifisch für die Anfrage sind, die verarbeitet wird. Das heißt, ich habe eine Struktur, deren Zeiger in allen aufgerufenen Funktionen sichtbar sein sollte, ohne sie explizit als Parameter an jede Funktion zu übergeben.

Die Verwendung von static / global ist keine perfekte Option (Multithreading, Synchronisationsobjekte und so weiter).

Wenn das ein Code für den Benutzermodus wäre, würde man in einer solchen Situation offensichtlich TLS verwenden. Aber AFAIK gibt es keine Kernel-Mode-Funktionen wie TlsGetValue / TlsSetValue . Und das macht Sinn - für diejenigen, die arbeiten müssen, muss man zuerst einen prozessweiten TLS-Index zuweisen. Der OTOH-Treibercode kann in einem beliebigen Thread aufgerufen werden und ist nicht auf einen bestimmten Prozess beschränkt.

Ich brauche jedoch keinen persistenten Thread-spezifischen Speicher. Ich brauche nur einen threadspezifischen Speicher für den Aufruf meiner Funktion auf oberster Ebene.

Ich denke, ich weiß, wie man das TLS "umsetzt", wenn auch in hackischer Weise. Anstatt den TLS-Index zuzuweisen, verwende ich immer einen vordefinierten Index (z. B. index = 0). Bei der Top-Level-Funktion speichere ich den gespeicherten TLS-Wert und überschreibe ihn mit dem benötigten Wert. Nach Abschluss wird der gespeicherte Wert wiederhergestellt.

Zum Glück weiß ich, wie das TLS in Win32 implementiert ist. Es gibt eine TIB -Struktur (Thread-Informationsblock) für jeden Thread. Auf jeden Thread kann mit FS:[18h] selector zugegriffen werden. Das TIB enthält (unter anderem) ein von TLS verwendetes Array. Der Rest ist ziemlich einfach.

Ich würde jedoch lieber eine offizielle API verwenden, um etwas Ähnliches zu erreichen.

  • Gibt es eine offizielle Kernel-Modus-API, um das zu erreichen, was ich brauche?
  • Gibt es Gründe zu vermeiden, was ich vorhabe? Ich weiß, dass möglicherweise ein Problem mit dem Wiedereintritt auftreten kann (d. H. Ein Code ruft mich auf, ich überschreibe den TLS-Wert und rufe schließlich den Ursprungscode an, der sich auf den TLS stützen kann). Aber das ist in meinem speziellen Fall nicht möglich?
  • Gibt es weniger schmutzige Wege, das zu lösen?

Vielen Dank im Voraus.

P.S. Man kann theoretisch SEH verwenden (das auch pro-Thread-Informationen gespeichert hat). Das heißt, den Code der obersten Ebene um __try/__except umbrechen, dann, wo die Kontextinformationen benötigt werden - die Ausnahme continuable mit einem Parameter auslösen, im Block __except den Parameter mit den Kontextinformationen füllen und dann die Ausführung fortsetzen. Und dies ist ein 100% gültiger Programmablauf, ohne die undokumentierten Funktionen zu verwenden. Aber nichtsdestotrotz scheint dies ein hässlicher Hack für mich zu sein, ganz zu schweigen von den Performancekomplikationen.

    
valdo 20.03.2012, 23:38
quelle

3 Antworten

7

Anstatt FS: [18h] zu verwenden, solltest du wahrscheinlich PsGetCurrentThreadTeb verwenden. Selbst dann, denke ich, würden Sie sich auf Details verlassen, die sich in zukünftigen OS-Versionen ändern könnten (möglicherweise einschließlich Service Packs).

Können Sie KeGetCurrentProcessorNumber nicht als Index für ein Array verwenden, in dem Sie einen Zeiger auf Ihre Kontextinformationen speichern können? (Vorausgesetzt, Sie arbeiten mit DISPATCH_LEVEL oder höher, so dass Sie nicht unerwartet auf einen anderen Prozessor wechseln können.)

Wenn Sie nicht sicher sind, dass sie auf DISPATCH_LEVEL ausgeführt werden, können Sie eine Tabelle oder eine verkettete Liste verwenden, wobei jeder Eintrag (der einen Thread darstellt, der gerade Ihren Code ausführt) mit dem Wert von PsGetCurrentThread beschriftet ist.

    
Harry Johnston 21.03.2012, 01:04
quelle
4

Sie können eine Struktur erstellen, die die eingehende Anfrage enthält, und Sie geben diese statt der eigentlichen Anfrage weiter, dann fügen Sie einfach alle Felder ein, die Sie benötigen. Offensichtlich wird dadurch die Notwendigkeit, ein Objekt zu übergeben, nicht vollständig entfernt, aber normalerweise wird die Anforderung trotzdem weitergegeben.

Von den meisten Treiber-Sachen, die ich gesehen habe (was zugegebenermaßen keine große Menge ist), war immer alles auf Anfrage zentriert. Also haben sie die Dinge immer an die Anfrage gebunden, anstatt sie an einem anderen Ort zu behalten.

    
Zipper 21.03.2012 00:05
quelle
4

Tu das nicht mit dem TEB! Die TIB und TEB sind Usermode-Strukturen. Eine Anwendung im Benutzermodus kann dieses Zeug nach Belieben von einem anderen Thread / Prozessor ändern, während der Treiber ausgeführt wird. Dies wäre eine Sicherheitslücke in Ihrem Treiber, die eine Sicherheitsverletzung darstellt.

Ich würde empfehlen, eine Kontextstruktur für ephemeren Kontext zu übergeben, die mit Ihrer Anfrage zusammenhängt. Wenn Sie etwas dauerhafteres benötigen, können Sie eine AVL-Tabelle oder eine Hash-Tabelle verwenden, die Sie beim Beenden von Threads aufräumen.

    
Neeraj Singh 06.05.2012 17:07
quelle