広い意味でのバイナリプランティング
バイナリプランティングって、宇宙人のインプランティングみたいで怖いですよね!?
バイナリプランティング概説
現代的にはDLLによるバイナリプランティングを指すようです。
DLLのバイナリプランティング
Windowsでは昔はカレントディレクトリを優先的に読み込んでいましたが、ファイルダブルクリックでアプリ起動すると嵌められるってことで、比較的最近に仕様変更になりました。現在のDLL読み込みの仕様として、順序はこんな感じ。LoadLibraryせずに依存関係で読み込むとこんな順序です。
- Known DLLsは登録済み絶対パスで参照
- アプリケーションモジュールのあるディレクトリから検索
- システムディレクトリ(ようするにC:\Windows\System32)から検索
- 16ビットシステムディレクトリ。今もあるかは不明。
- Windowsディレクトリ(ようするにC:\Windows)から検索
- 現在の作業ディレクトリ(カレントディレクトリ)から検索
- PATHで指定されたディレクトリから検索
なお、Windows7の問題は、システム or WindowsディレクトリのDLLが依存関係で読み込むDLLの中に、カレントディレクトリのDLLを読み込んで使う古い実装のものが混じっているのでしょう。特に16ビットとかはあっても不思議ではない。
WindowsにおいてはDLLとEXEはほとんど同じですが、EXEは大人の事情で、現在の作業ディレクトリがトップの最古の仕様のようです。
問題になるのはなになの?
数年ごとに大量に報告されるマイクロソフトはうんざりしたのか、「サーセン基準標準がありませんでした。パイセンこれでどうっすか?」と
DLL の植え付けの脆弱性のトリアージ – 日本のセキュリティチーム
っていう分かりやすい解説を出してます。
要約すると、カレントディレクトリにあるのを読み込む場合はCWEとして「修正してやる!」となるようです。
EXEだとどうなの?
多分ですが、パス省略してEXEを呼び出してカレントディレクトリのファイルが実行されるのは仕様。ただし、アプリケーションレベルでそれやるのはCWEになるかもしんないです*1
Windowsでのプログラム実行
いろんな関数があります。これだけでなく派生もあります。
- system
- WinExec
- popen
- CreateProcess
- ShellExecute
この中でWinExecは太古のWindowsなので忘れてあげることにしましょう。systemみたいな危険な代物で、使うべきではありません。脆弱性とか考えられていない仕様なので。情弱にも無検証にCreateProcessやShellExecuteで置き換えた懐古趣味のプログラムもありますが、使う人は当時の安全性基準適用している自業自得ってことで。テキトーに解説すると。
system
シェルを呼び出します。Windows10の時点ではシェルプロンプトのCMD.EXEに引数渡して実行する感じです。シェルの拡張子補完をするので、拡張子なしだと環境変数EXTPATHの順で補完するっぽいです。
CreateProcess
プロセスを起動します。拡張子を省略するとEXEを補完するようです。カレントディレクトリや環境変数を指定できるし、プロセスの権限も指定できます。
ShellExecute
シェルを呼び出すのでsystem同様に拡張子補完するところが似てますが、あとはCreateProcessに準拠してて、さらにUACをサポートするとこがちゃうかな?
伝統がおりなすアレとマルチプラットフォーム
OSSなんかだと、つい伝統あるものなら大丈夫かなって気にしなってしまいますよね。
脆弱性の問題なんかが起きると、リファクタリングでソースが綺麗になるのも嬉しいところです。古くから*2UNIX系とWindows系にマルチプラットフォームで対応している場合は、まあうまくやっているんでしょう。しかし、なぜかWindows系のコードメンテナンスって脆弱性対策が不徹底なことがあるので、コミッターやレビューアの関心度の差でしょうか?不思議ですね。
ようやく本題
マルチプラットフォームと謳っているOSSの場合、Windowsのコードは注意深く読んだ方が良いです。UNIX系から派生した場合にありがちな僕たちの失敗。
それってシェル組み込みコマンド?
UNIX系から派生していると、いろいろと勇気ある行動のコードを見ることがあります。
- なぜか、いまだにsystemコマンド使っている(正しく使えばいんだろうけど)
- なぜか、拡張子なしでコマンド記述してわざわざEXEを補完している
- なぜか、コマンドを絶対パスで書かない(カレントにプラントされたらどうすんですか!?)
コマンドのパス省略は一見問題ないですが、実行ファイル(DLL除く)の場合はカレントディレクトリが優先されるWindowsの伝統仕様に注意が必要です。これがUNIXだとcpは組み込み(ビルトイン)なので、同じノリでWindowsでファイルコピーにCOPYを使うのは問題ないのですが、ディレクトリコピーしたいからXCOPYなんて使うと、外部コマンドです。カレントに実行ファイルがあると詰みます。きーつけましょう。
Windowsでシェルってどうやって呼ぶの?
多分、ShellExecuteを呼ぶのが正解です。systemコマンドでCMDを呼んだりすると、EXE以外も補完するので、カレントディレクトリのCMD.exeどころかCMD.batやCMD.cmdが呼び出されたりするので、すげー困ります。どうせ使うのはEXEなんだし、#ifdef WIN32してるのだから、横着せずに拡張子付きで指定しましょう。とにかくきーつけましょう。以上
脆弱性なの?
とあるサーバで使うOSSでメンテナンスコマンドを実行すると、カレントディレクトリのコマンドを実行する困った仕様がありました。これって脆弱性なの?というと微妙です。サーバでメンテナンスコマンドを実行する時点で特権もってて、おそらく自由にコマンド実行できるので、問題じゃないはず。あと、注意深い管理者は良く問題になるCMDとかXCOPYがないかチェックするものです。これは常識ですよね!?
魔法の呪文
いかがでしたか、いかがでしょうか、いかがでしたでしょうか、調べてみました。
*1:使い方を勘案するようで、それでもOKな場合があるようです。雰囲気ですが。
*2:ソースにWindows2000やXP用の動作が書いてあるのがそれ