Event Tracing for Windows (ETW)

皆さん、こんにちは。A寿です。   突然ですが、皆さんは、馬に乗ったことはありますか?・・・このお話にご興味のある方は本文の最後の【閑話休題】までどうぞ。   さて、今回は、 Event Tracing for Windows (ETW) についてお話ししようと思います。ドライバ開発者の方にとって、なぜ、 ETW が必要なのでしょうか?読者の皆様にもご経験があるかもしれませんが、エンドユーザ様の運用環境の現象を、開発側で再現できない場合や、開発側でカーネルデバッガを接続し、Checked Build 版ドライバでデバッグプリントを出力すると、タイミングが変わって現象が再現しない場合があります。このような時、ドライバに ETW を実装しておくと、エンドユーザ様の運用環境で現象を再現することさえできれば、追加で何かをインストールする必要なく、かつ、パフォーマンスに影響を与えることもほとんどなく、デバッグプリント並みの詳細なログが取ることができるのです。追加で何かのインストールが必要ない、というのは、 OS にすでに入っているツール (logman.exe) を使ってログを採取することができる、ということです。ただ、一方で、「イベントログの出力方法」の記事にも書いた通り、常時採取するには向いていません。短時間でもデータ量が非常に多くなってディスクスペースを圧迫する可能性がありますし、データ量を抑えようとしてサイクリックに上書きすると、肝心のエラー時の情報が上書きで消されてしまう可能性があるからです。そのため、イベントログで、トラブルが発生した時点を特定し、そのログの内容からトラブルシューティングを始め、現象発生の手順が確立した段階で、現象発生の前後のみ、 ETW のログを採取することが良いかと思います。   また、さらに言えば、 ETW はドライバ開発者以外の方にとっても重要な場合があります。ドライバ開発者にとって ETW が必要な理由を申し上げましたが、同じことは OS のコンポーネントにも言えます。つまり、 OS のコンポーネントの詳細なログ採取も行えます。以前の記事「WPA とか XPerf とか」や「USB Event Tracing for Windows 7」、「NDIS のトレース」などは、 ETW を使用しています。   なお、ここで一点ご注意いただきたいのは、 ETW で採取できるログはバイナリ形式であることです。そのため、上記のブログ記事で紹介しているツールなどは、ログを人間が読みやすい形式に変換していますし、本ブログでも、バイナリ形式からテキスト形式に変換する方法をご紹介します。   今回のブログでは、 ETW について、以下の内容をご説明します。   1. ETW…


I/O コントロール発行に使うハンドルに必要なアクセス権限

皆さん、こんにちは。A寿です。   突然ですが、皆さんは、左ハンドルの車を運転したことはありますか?・・・このお話にご興味のある方は本文の最後の【閑話休題】までどうぞ。   さて、今回は、I/O コントロール発行に使うハンドルに必要なアクセス権限についてお話ししようと思います。結論から言いますと、 「CreateFile() の 2nd parameter の accessMode には、 I/O コントロールコードを定義する CTL_CODE() マクロの 4th parameter の Access に指定された権限が必要」 ということです。言い換えると、 I/O コントロールコードの定義に指定されたアクセス権 (Access) を指定せずに、 CreateFile() で取得したハンドルを使って、 DeviceIoControl() でその I/O コントロールを発行しても、アクセスは拒否される、ということです。   このことについて、以前の記事「アプリケーションから SCSI コマンドを発行する方法」でご案内した、 WDK の SPTI サンプルを使った、 I/O コントロールの発行方法を題材にご説明したいと思います。この記事から少し抜粋しますと、まず、以下のように CreateFile() を使って、オープンしたデバイスのハンドルを取得します。   137 fileHandle = CreateFile(string, 138                         accessMode, 139                         shareMode, 140                        …


INFファイルの構文チェック ~ chkinf の使い方 ~

皆さん、こんにちは。A寿です。   突然ですが、皆さんは、大使館に行ったことはありますか?・・・このお話にご興味のある方は本文の最後の【閑話休題】までどうぞ。   さて、今回は INF ファイルの構文チェックを行う、 chkinf というツールをご紹介しようと思います。以前、「ドライバ インストール時のトラブルシューティングの第一歩」という記事を書きました。ここに書いた以外のトラブルシューティング初期の切り分け方法として、 chkinf ツールで INF ファイルの構文チェックを行い、出力結果のエラーや警告をもとに正しい構文になるよう修正し、問題が解決するかどうか確認する、という方法もあります。今回は、 chkinf の使い方だけではなく、実際に、WDK サンプルの INF ファイルを変更しながら、どのようなエラーや警告が出るかをお見せしていこうと思います。この情報により、皆さんのトラブルシューティングの一助となれば幸いです。   まず、chkinf ツールは、以下のフォルダにあります。     \WinDDK\{バージョン}\tools\Chkinf   このフォルダ内の chkinf.bat というバッチファイルで Perl のスクリプトを実行しています。このフォルダ内には、 chkinf.pm を初めとして、多くの .pm ファイルがあります。これらが INF ファイルの構文チェックをする実体です。 chkinf.bat は、これら .pm ファイルを実行する役割を持ちます。このフォルダの詳細については、下記ドキュメントをご参照ください。     ChkINF Components   http://msdn.microsoft.com/en-us/library/ff543464(VS.85).aspx   続いて、手順の概要は以下の通りです。   1. コマンドプロンプトを起動します。    管理者権限は必要ありません。 2….


Bindview とINetCfg API

みなさま、お久しぶりです。さなえすです。   ローカル エリア接続のプロパティから、チェックボックスのチェックを入れる・はずすといった手順で、IPv6 の有効・無効の切り替えなどを行うことができます。では、似たような操作を、プログラムで行いたい場合どうすればよいのでしょうか?     INetCfg インターフェースは、ネットワーク関連のモジュールのセットアップや、コンフィグレーションを行うための機能を提供しています。なので、この INetCfg インターフェースを使用してプログラムを実装すれば、IPv6 のコンポーネントを有効・無効にすることもできるようになります。INetCfg インターフェースの使用方法については、Windows Driver Kit (WDK) で、技術ドキュメントとサンプル コード (Bindview) を公開していますので、実際のコードを見たい方は、WDK の下記のディレクトリを直接ご参照ください。         Bindview Sample       %BaseDir%\src\network\config\bindview   何はともあれ、まずはサンプルを動かしてみてください。使用方法はこんなかんじです。  1. サンプルをビルドし、 Bindview.exe を管理者権限で起動  2. [Show Bindings For] のプルダウンより、列挙するネットワーク機能の種類を選択       例えば IPv6 の設定を変更したい場合、[All Protocols] を選択し、"インターネット プロトコル バージョン 6 (TCP/IPv6) " を選択  3.条件に該当する Bind Path を展開/選択して右クリックし、[Enable]/[Disable] を実施…


ドライバーのデジタル署名の基礎

  久方ぶりです。まさかたです。 さて、今回は、ドライバーのデジタル署名のお話をしたいと思います。   始めに、ドライバーのデジタル署名についてあまりご存知ない方に、簡単にデジタル署名とは何か?なぜドライバーに署名が必要なのか?ということについてお話ししたいと思います。 まず 「署名」 という言葉の意味について辞書を見てみますと、例えば「本人が自分の名を書類などに書くこと。また、その書かれたもの。」と書かれております。 これは、ドライバーにおける署名も同様で、ドライバーの場合は、書類にではなくドライバーパッケージもしくはドライバーのバイナリそのものに対して、作成者本人が誰であるかを示す名前を記すことになります。 それでは、なぜドライバーに対して、作成者が誰であるのかを示す必要があるのでしょうか? これは言うまでもないことかもしれませんが、作成者の分からないドライバーをご自身の PC にインストールすることは、決して安全とは言えないからです。 というのも、現在は UMDF やプリンタードライバーのように、一部のドライバーはユーザーモード空間で動作するものがありますが、多くのドライバーはカーネルモード空間で動作しています。 カーネルモード空間は、その名の通り、OS の主要な機能を管理するモジュールを始めとして、その他のドライバーも動作するようなメモリ空間です。 そのため、カーネルモードで動くドライバーは、うっかりにせよ意図的にせよ、そのような OS やドライバーが管理するメモリを触ることができてしまうわけです。 ただ、実際には、そのようなメモリをあっさりと書き換えることができ、さらにそのまま動作してしまっては、意図しない動作をしてしまったり、大切なデータが破壊されたり、さらにはデバイスが誤動作、故障することもあり得ます。 そこで OS は、カーネルモード空間上で、このような不正な操作を検出した場合には、このまま動作を継続させてさらに深刻な事態に陥ることを回避するために、その動作を停止させます。 この動作の停止が、一般的にブルースクリーンですとか、BSOD (Blue Screen of Dead) と呼ばれる形で表面に出てくることがあります。 話が逸れましたが、ご自身の PC にドライバーをインストールする場合、それが誰によって作成されたのか、信頼できるものであるかを確認することは大切なことです。 そして、それを確認するための手段のひとつとして、デジタル署名というものがあるわけです。 なお、Windows Vista や Windows 7 では、署名のされていないドライバーや、署名の発行元の信頼性を確認できないドライバーをインストールしようとした場合、以下のような警告が表示されます。 図1. ドライバーソフトウェアの発行元を検証できません 32bit OS では、上記の警告が出た場合でも、「このドライバーソフトウェアをインストールします」を選択してインストールすれば、動作させることができますが、64bit OS では署名は必須となっており、署名がない場合は、ドライバーをインストールしたとしても動作させることができませんのでご注意ください。   さて、具体的にドライバーに対して、どのようにして署名を行うかについてですが、署名そのものについての技術的なお話は、暗号化などさらに深い話が待っていますので、ここでは割愛させていただきます。 ただ、Windows OS のドライバーで利用可能な署名の方法にはいくつか種類があり、一般的には INF ファイルや…


スタックオーバーフロー

こんにちは、K里です。   今回は Windows OS がクラッシュする最多要因の一つであるカーネルスタックオーバーフローについてお話したいと思います。   カーネルスタックは、関数間でやりとりする引数、戻り値や関数内で使用するローカル変数を保持するためのストレージ領域で、そのサイズはプロセッサアーキテクチャに依存して x86 では 12 KB、x64 (amd64/EM64T 含) では 24KB、Itanium では 32 KB と固定で割り当てられます。また、カーネルスタックは、Windows OS の各プロセスで動作するスレッド単位で割り当てられますので、スレッド内で呼び出される全ての関数で使用するスタック消費サイズが割り当てサイズを超えた場合スタックオーバーフローが発生します。その結果、OS はシステム内で致命的なエラーが発生したと判断し、下記のいずれかの Bugcheck を発生させることになります。   Bug Check Codes http://msdn.microsoft.com/en-us/library/ff542347(VS.85).aspx STOP 0x1E: KMODE_EXCEPTION_NOT_HANDLED STOP 0x2B: PANIC_STACK_SWITCH STOP 0x7E: SYSTEM_THREAD_EXCEPTION_NOT_HANDLED STOP 0x7F: UNEXPECTED_KERNEL_MODE_TRAP STOP 0x8E: KERNEL_MODE_EXCEPTION_NOT_HANDLED   以下は x86 での典型的なスタックオーバーフローです。   1: kd> !analyze -v *******************************************************************************…


NDIS のトレース

こんにちは、さなえすです。暑くなってきましたが、皆さまいかがお過ごしですか?「梅雨(つゆ)」の語源は諸説あるようですが、梅の実が熟す時期の雨という意味もあるそうです。今年は私も梅シロップと梅酒を漬けてみました。これで夏を乗り切りつつ、暑さがおさまる頃には美味しい梅酒が飲めるといいなぁーと、楽しみにしております♪   先日、NDIS チームのブログで NDIS.sys の TMF (Trace Format) ファイルが公開されていました。実際の記事はこちら (→ ”TMF download page”) です。以前 K 里さんの投稿でも USB のイベントトレーシングについて書かれていましたが、NDIS.sys ドライバーも同様に ETW の機能を利用してトレースをとる事ができます。今日は TMF ファイルを使った NDIS の ETW トレース の出力・デコードの方法を皆さまにご紹介いたします。   ※注意 なお、NDISチームのブログでも記載がありますが、”TMF download page” で公開されている TMF ファイルは、Windows 7 と Windows Server 2008 R2 においての以下のバージョンの NDIS のものです。全ての修正モジュールに対応しておりませんので、お使いの NDIS バージョンに該当しているかどうか、ご注意ください。   –     RTM –     KB977927 –     KB981765 –     KB2471472 –     KB2482122 –     SP1…


イベントログの出力方法

皆さん、こんにちは。A寿です。   突然ですが、皆さんは、パスポートなしで他国に入国したことはありますか?・・・このお話にご興味のある方は本文の最後の【閑話休題】までどうぞ。   さて、今回はカーネル ドライバでのシステムイベントログの出力方法をご紹介しようと思います。ドライバ内の情報をシステム イベントログに残すことで、お客様先のトラブル発生時に、イベントビューアーでそのドライバ以外のモジュールのログと併せて確認できるため、トラブル発生時の大まかな状況をつかむことができます。トラブルシューティングのための情報記録の手段として、他に DbgPrint や、 Event Tracing for Windows (ETW) という方法があります。これらは、イベントログよりも詳細な情報を記録できるメリットがあります。しかし、その一方で、常時採取するには、イベントログよりもデータ量が大きくなってしまったり、データ量を抑えようとしてサイクリックに上書きすると、肝心のエラー時の情報が上書きで消されてしまう可能性があったりというデメリットもあります。そのため、イベントログで、トラブルが発生した時点までのどこを調査すべきかを判断してから、より詳細な情報を見るために、DbgPrint や ETW を使われるのが良いかと思います。   まず、カーネル ドライバでのシステムイベントログの出力方法について、手順の概要は以下の通りです。   IO_ERROR_LOG_PACKET のポインタを宣言します。 IoAllocateErrorLogEntry() を呼び、戻り値を 1. のポインタに代入します。 第一引数にはドライバオブジェクトまたはデバイスオブジェクトのポインタを入れます。 第二引数には IO_ERROR_LOG_PACKET 構造体のサイズ、 DumpData のサイズ×個数、 %n に挿入する文字列のサイズ、の和を入れます。     3.    2. の戻り値が NULL でなければ、 IO_ERROR_LOG_PACKET のメンバ変数に値をセットし、 IoWriteErrorLogEntry() を呼びます。   続いて、 Toaster サンプルの busenum.sys の DriverEntry() に、上記手順の具体的な実装を追加して、 busenum.sys ロード時にシステム…


Package-Aware プリンタ ドライバ

こんにちは。A尾です。 今回は Package-Aware プリンタ ドライバについてお話しさせていただきます。   既に皆さんご存知の方も多いかと思いますが、Windows Vista より、INF ファイルとその INF ファイルに記述されているドライバ構成ファイルを一つのオブジェクトとして扱うことを目的に、Driver Package という概念を取り入れられました。これにより、ドライバのインストール時は、まず Driver Store に Driver Package がストアされ、その後にドライバ構成ファイルがシステムにインストールされるようになりました。この動作はプリンタドライバにおいても同様ですが、プリンタ ドライバでは Point and Print というインストール シナリオも存在します。   Point and Print によりインストールが行われる場合、Windows Vista 以前の Windows OS では、サーバーからクライアントに個々のドライバ構成ファイルがダウンロードされ、ダウンロードされたファイルを使用してドライバのインストールが行われます。そのため、クライアントへのインストールの際、適切にドライバ署名が行われているかどうかのチェックが困難であったり、現在どのバージョンのドライバがインストールされているのか、どのバージョンのドライバが使用するモジュールがインストールされているのかを把握することが困難でした。 対しまして、Windows Vista からは、Driver Package の概念を利用した Package-Aware プリンタ ドライバというものが登場しました。 これにより、Point and Print によるインストール時には、サーバーからクライアントに Driver Package がダウンロードされ、クライアントの Driver Store にストアされた後、システムにインストールされるようになりました。そのため、ローカルにてインストールするのと同様にインストール時にドライバ署名のチェックが可能となり、また、本来依存関係にあるファイルが、異なるモデル、バージョンのドライバがインストールされることにより互換性が無くなってしまうようなことが回避可能となりました。  …


デバイス ドライバを開発する?しない?

なおきお~です。皆様、いかがお過ごしでしょうか?ご無事でしょうか? この度の東北地方太平洋沖地震により、亡くなられた方々のご冥福をお祈り申し上げますとともに、被災された皆様と、そのご家族様に対しまして、心よりお見舞い申し上げます。 また、このブログを閲覧していただいている皆様が、ご無事であることも、お祈り申し上げております。   さて、大震災以降、安全性というものの重みを思い知らされている日々ですが、デバイス ドライバを開発する際も、ささやかなものですが、安全性や安定性を意識しなければなりません。 その手始めとして、どのようなモジュールを開発するか?と決める時です。 Windows OS に含まれているモジュールを利用すると、既に動作の実績もあり、安定しています。また、脆弱性が見つかれば、マイクロソフトが解決してくれるので安全です。また、開発の工数も短縮できると、いい事づくめです。   ただ、Windows OS に含まれているモジュールの利用に固執してしまって、失敗してしまうこともあります。その一例として、USB と Serial Port (RS-232C) の変換のデバイス ドライバがあります。 Windows OS には、usbser.sys というモジュール (デバイス ドライバ) が、含まれています。名前から想像すると、これが、USB と Serial Port (RS-232C) の変換を行うデバイス ドライバかな?と思ってしまいます。 名前で誤解してしまうのですが、以下の USB の FAQ の “表 2: Windows での USB DWG Class のサポート” に、ある通り、usbser.sys は、実は、CDC (Communications Device Class) に準拠したモデム クラスのデバイス ドライバなのです。  …