windows-drivers-rs - RustでWindowsドライバー開発を可能にするプラットフォーム
(github.com/microsoft)- Windows DriversをRustで開発できるようにするRust crate群で、WDMおよびWDFドライバー開発モデルのサポートを目標としている
- 主な構成は、WDKビルド設定用の
wdk-build、WDK APIの直接FFIバインディングであるwdk-sys、安全で慣用的なWDK APIバインディングのwdk、panic handler用のwdk-panic、allocサポート用のwdk-alloc、wdk-sysの直接バインディング利用を支援するマクロ群wdk-macrosで構成される - WDM、KMDF、UMDFドライバーとWin32 Servicesのサポートを念頭に作られており、WDK 22H2以降に含まれるすべてのWDFバージョンのサポートを含む
crates.ioで公開されているcrateは現在KMDF v1.33のみをサポートしており、ほかの構成のバインディングはwindows-drivers-rsをcloneした後、wdk-sysのbuild.rs設定を修正して生成できる- 利用の流れは、Cargo
libパッケージの作成、wdk-build、wdk、wdk-sys、wdk-alloc、wdk-panic依存関係の追加、cdylib設定、WDK metadata設定、build.rsでwdk_build::configure_wdk_binary_build()を呼び出し、DriverEntryを追加し、cargo makeを実行するという構成- Kernel Mode crateであるKMDFおよびWDMドライバーでは、panic戦略
abort、#![no_std]、panic handlerの設定が必要 - Rust標準ライブラリの
allocモジュールを使うには、wdk_alloc::WdkAllocatorのグローバルallocator設定が必要
- Kernel Mode crateであるKMDFおよびWDMドライバーでは、panic戦略
- ビルド要件は、
bindgen用のlibclang、post-build作業用のcargo-make、有効なWDK環境であり、推奨される方法はeWDK developer promptに入ること cargo makeはデフォルト動作でドライバーのビルドとパッケージングを行い、結果として署名済みドライバーパッケージとWDRLocalTestCert.cerファイルがtarget/<Cargo profile>/packageまたはtarget architectureパス配下に生成されるcargo make default --target <TARGET TRIPLE>、--release、--features <FEATURES>、+<TOOLCHAIN>のような引数の受け渡しをサポートし、WDK_BUILD_ENABLE_SIGNTOOL_VERIFY=true設定で生成された.sysおよび.catファイルの署名検証処理を有効化できる- 新しいCargo拡張
cargo-wdkは、Rustドライバービルドの推奨ツールとしてcargo-makeを置き換えるために開発中のPreview段階にある - WDM、KMDF、UMDFの最小サンプルはexamples directoryにあり、ドライバー作成の例はWindows-rust-driver-samplesで確認できる
- まだ開発初期段階であり、production useにはまだ推奨されない
3件のコメント
Hacker News のコメント
覚えていない人のために言うと、Mark Russinovichは上司の後任となり、次期 MSFT CEO 候補として名前が挙がる前、Redmond のエンジニアたちが NT カーネル開発を学びに行くようなソフトウェアツールおよび NT カーネルのコンサルティング会社を運営していた。
また、Sony の DRM ルートキットや Symantec のルートキットのようなファイル保護機能を発見し、Best Buy が ERD Commander を違法コピーしていたことも突き止めた。
2014年に LinkedIn を消してしまったのは、今となっては少し惜しい。Valley 全体と Mark が 1次つながりだったアカウントだったのだが、それでも相対的な無名さには自由と機敏さがある。自分がどれだけやったか、稼いだか、誰を知っているかを語るのは無意味だ、という Desmond Dekker のレゲエ曲は何だったかな。
あの規模の企業が、実際のソースコードとエンジニアへのアクセスというはるかに有利な立場にありながら、こうしたことを自力でうまくできないというのはかなり興味深い。こうした第三者、少なくとも Levin はかなりの部分をリバースエンジニアリングに頼らざるを得なかった。
https://newosxbook.com
世界中の Windows を使うほぼすべての会社が、少なくとも1つは Sysinternals のツールを使っていることを考えると、Sysinternals の影響力はもしかすると Azure そのものよりも大きかったかもしれない。
MSFT が Mark Russinovich とそのチームを acquihire した理由も、そこにあるのではないか。
最初の本から受けた印象は、世界を極端に白黒で見ているというものだった。
元のツイート: https://twitter.com/markrussinovich/status/17057307039574058...
http://farside.link/twitter.com/markrussinovich/status/17057...
すばらしい /s だが、これは Rust らしくない:
pub struct QueueContext {
buffer: PVOID,
length: usize,
timer: wdf::Timer,
current_request: WDFREQUEST,
current_status: NTSTATUS,
spin_lock: wdf::SpinLock,
}
Linux カーネルで Rust ドライバーを書く場合にも似た問題があり、C と相互運用する他のプロジェクトでも同じだ。
NTSTATUS のような型には、かなり多くのドキュメントが付いている。C や C++ と違い、Rust では整数値を enum 値にそのまま代入することはできない。ラッパークラスを作って毎回キャストさせることもできるが、そうするとコードの半分が .into() になり、ドライバーにオーバーヘッドも生じる可能性が高い。
見たところ、buffer 用の void* 程度を除けば、こうした enum 値を設定したり変更したりしているのではなく、読むだけだ。NTSTATUS には match {} ブロックで十分そうだ。WDFREQUEST はハンドルなので、同じ型の別のハンドルに差し替える以外にできることもあまりない。
Timer と SpinLock は、unsafe なライブラリ呼び出しを内部に包んだRust らしいオブジェクトになっている。それ以外については、かなりの性能負担なしにこのコードをもっと Rust らしくする方法はあまり見当たらない。
何がもっと良いか分かるか? C# のようなメモリ管理言語でデバイスドライバーを書くことだ。
カーネルをより簡単に扱えるようにするより、カーネル内でメーカーのコードを実行する量を減らす方が最善だという Microsoft の判断には同意する。C# は「あるバッファにアクセスしたいが、まだページインされておらず、自分は割り込みハンドラーの中にいる」といった状況には向いていないので、カーネルでガベージコレクターをバグなく動かすのはほぼ不可能に見える。
ドライバーはページフォールトが許されないタイミング、たとえば割り込みハンドラー中にもメモリへアクセスする可能性があるため、メモリの可用性を非常に厳密に制御しなければならない。C# 言語とランタイムは、少なくともそれを明示的に扱う機能を追加する必要がある。
少し過小評価されているように思うので補足します。Russinovich は Windows カーネルに関して数多くの資料やツールを作ってきた人物です。Windows カーネル関連の開発者の中で(ルートキットを作った開発者たちを含めて)、Russinovich の資料や文書を見て学ばなかった人はいないのではないかと思います。
WindowsカーネルをRustで書き直しているという話は聞いていましたが、ついにドライバーSDKが出てきたのですね。近いうちに20XX年からはRustでドライバーを作れという告知が出そうです。