9

Windows (正確には Win32) のカーネル モード ドライバーに相当するスレッド ローカル ストレージ (TLS) はありますか?

私が達成しようとしていること:

最終的に、ドライバーのディスパッチ ルーチン内から、他の多くの関数を呼び出す可能性があります (コールスタックが深い可能性があります)。処理中のリクエストに固有のコンテキスト情報を提供したいと考えています。つまり、すべての関数にパラメーターとして明示的に渡すことなく、呼び出されたすべての関数で表示されるはずの構造体、ポインターがあります。

静的/グローバルの使用は完璧なオプションではありません (マルチスレッド、同期オブジェクトなど)。

それがユーザーモードのコードである場合、そのような状況では明らかに TLS を使用します。TlsGetValueしかし、私の知る限り、 /のようなカーネルモード関数はありませんTlsSetValue。そして、これは理にかなっています-これらの機能が機能するには、最初にプロセス全体のTLSインデックスを割り当てる必要があります. OTOH ドライバー コードは、特定のプロセスに限定されず、任意のスレッドで呼び出すことができます。

ただし、永続的なスレッド固有のストレージは実際には必要ありません。トップレベルの関数呼び出し用にスレッド固有のストレージが必要なだけです。

ハックな方法ではありますが、TLSを「実装」する方法を知っていると思います。TLS インデックスを割り当てる代わりに、常に定義済みのインデックス (index=0 など) を使用します。最上位関数で、保存されている TLS 値を保存し、必要な値で上書きします。完了すると、保存された値が復元されます。

幸いなことに、私は TLS が Win32 でどのように実装されているかを知っています。TIBスレッドごとに構造体 (スレッド情報ブロック) があります。すべてのスレッドで、FS:[18h]セレクターを使用してアクセスできます。にはTIB、(とりわけ) TLS で使用される配列が含まれています。残りは非常に簡単です。

ただし、公式の API を使用して同様のことを実現したいと思います。

  • 必要なものを実現するための公式のカーネルモード API はありますか?
  • 私がやろうとしていることを避ける理由はありますか?再入に問題がある可能性があることはわかっています (つまり、一部のコードが私を呼び出し、TLS 値を上書きしてから、TLS に依存している可能性のある元のコードを最終的に呼び出します)。しかし、これは私の特定のケースでは不可能ですか?
  • これを解決するための汚れの少ない方法はありますか?

前もって感謝します。

PS One は、理論的には SEH を使用する可能性があります (これには、スレッドごとの情報も格納されます)。つまり、最上位のコードを でラップし__try/__except、コンテキスト情報が必要な場所で、いくつかのパラメーターを使用して継続可能な例外を発生させ、__exceptブロック内でパラメーターにコンテキスト情報を入力してから、実行を再開します。これは、文書化されていない機能を使用しない、100% 有効なプログラム フローです。しかし、パフォーマンスの複雑さは言うまでもなく、これは私にとって醜いハックのようです。

4

3 に答える 3

8

FS:[18h]を使用するのではなく、おそらくPsGetCurrentThreadTebを使用する必要があります。それでも、将来のOSリリース(サービスパックを含む可能性がある)で変更される可能性のある詳細に依存していると思います。

代わりに、コンテキスト情報へのポインターを格納できる配列へのインデックスとしてKeGetCurrentProcessorNumberを使用できませんでしたか?(もちろん、DISPATCH_LEVEL以上で実行している場合は、予期せずに別のプロセッサに切り替えることができなくなります。)

DISPATCH_LEVELでの実行が保証されていない場合は、テーブルまたはリンクリストを使用して、各エントリ(現在コードを実行しているスレッドを表す)にPsGetCurrentThreadの値のラベルを付けることができます。

于 2012-03-21T01:04:37.957 に答える
5

TEBでこれをしないでください!TIB と TEB はユーザーモード構造です。ユーザー モード アプリケーションは、ドライバーの実行中に別のスレッド/プロセッサからその内容を自由に変更できます。これは、ドライバーの権限昇格の脆弱性です。

リクエストに関連する一時的なコンテキストのコンテキスト構造を渡すことをお勧めします。より永続的なものが必要な場合は、スレッドの終了時にクリーンアップする AVL テーブルまたはハッシュ テーブルを使用できます。

于 2012-05-06T17:07:42.333 に答える
4

着信リクエストを保持する構造を作成し、実際のリクエストの代わりにこれを渡し、必要なフィールドを入力するだけです。明らかに、これでオブジェクトを渡す必要が完全になくなるわけではありませんが、通常はとにかくリクエストを渡します。

私が見たほとんどのドライバー (確かに膨大な量ではありません) から、すべてが常に要求中心でした。そのため、他の場所に保管しようとするのではなく、常に要求に結び付けていました。

于 2012-03-21T00:05:22.687 に答える