- はじめに — 題名と本文のあいだの距離
- rosenbridgeが実際に何なのか
- 著者が自ら引いた四つの境界線
- なぜMEやPSPと区別して話すべきなのか
- どうやって見つけたか — 文書なしに命令集合を探索する問題
- sandsifterのスキャンが実際に見つけるもの
- 方法は一般化されるが発見は一般化されない
- 実務者がここから持ち帰るもの
- 参考資料
はじめに — 題名と本文のあいだの距離
xoreaxeaxeax/rosenbridge というGitHubリポジトリがあります。説明は一行です。「Hardware backdoors in x86 CPUs.」スターは2,500個を超え、周期的にコミュニティの上位へ再浮上します。
この題名だけを見て「自分のCPUにバックドアがある」と結論づけるのは自然なことです。ところが同じリポジトリのREADMEを最後まで読むと、状況はかなり変わります。
この記事は、その文書を最初から最後まで読み、著者が自ら引いた境界線を正確に移すことから始めます。そのあとで、この研究で実際に一般化されるものは何なのかを扱います。
まず日付を明かしておきます。このリポジトリはGitHub API基準で2018年8月9日に作成され、最後のコミットは2018年10月12日です。2026年の新しい発表ではなく2018年の研究です。 同じ著者が2026年8月に別のリポジトリを新しく上げたことで、プロフィール全体が一緒に注目された結果と見られます。
rosenbridgeが実際に何なのか
READMEが説明する構造はこうです。
メインのx86コアの隣に小さな非x86コアがもうひとつ入っています。このコアはモデル特化レジスタの制御ビットで有効化され、そのあと「launch-instruction」と呼ばれる命令で切り替えられます。切り替わったあとは、特別な形式のx86命令に包まれた命令を受け取って実行するのですが、著者はこの命令集合をDEIS(deeply embedded instruction set)と呼びます。
このコアが実行する命令はすべてのメモリ保護と特権検査を迂回します。 そのためリング3、つまり一般のユーザープログラムがリング0のカーネルデータを自由に読み書きできるようになります。
本来ならこの機能を有効にするにはカーネル権限が必要です。ところがREADMEは、一部のシステムで既定で有効になっているのが観察されたと書きます。その場合、権限のないコードがそのままカーネルを改変できます。
ここまでが確認されたメカニズムです。リポジトリにはこれを裏づける道具も一緒にあります。DEIS用のアセンブラ、権限昇格の概念実証、MSRを通じてバックドアを閉じる起動スクリプト、そして研究に使われたファザーたちです。
著者が自ら引いた四つの境界線
READMEには、この発見の範囲を狭める文がいくつもあります。引用する価値があります。
第一に、影響範囲。 「この問題の影響を受けるのはVIA C3 CPUだけだと考えられている。」VIAのCシリーズは、産業オートメーション、POS、ATM、医療用ハードウェア、そして一部の消費者向けデスクトップやノートPCを対象に販売されました。
第二に、世代。 「この脆弱性の範囲は限定的である。C3以後の世代のCPUにはもはやこの機能がない。」
第三に、意図。 免責条項にはこう書かれています。VIAのプロセッサは低電力と組み込み設計における優秀さで知られており、ここで説明した機能は組み込み市場のための有用な機能として善意で作られ、初期の一部世代で意図せず有効なまま残ったものと見ている、というものです。そして「悪意を含意しない」と明示します。
第四に、道具の限界。 確認用の道具はアルファ状態でありベアメタルでのみ実行すべきであり、「バックドアのないシステムをクラッシュさせたり、カーネルパニックを起こしたり、停止させたりしうる」と警告します。そして決定的なことに、これらの道具は特定のプロセッサ系列とコアを前提に設計されているため、研究された形から少しでも変形したバックドアは見逃すと書いています。
著者本人はこの作業の性格をこう規定します。「ますます複雑になるプロセッサでバックドアがどのように生まれうるのか、そして研究者と最終利用者がそうした機能をどのように識別できるのかを示す事例研究であり思考実験として公開する。」
この四つを外して題名だけを流通させることが、この研究を不正確にするもっともよくあるやり方です。
なぜMEやPSPと区別して話すべきなのか
READMEに興味深い比較があります。rosenbridgeは、Intel Management EngineやAMD Platform Security Processorのように公に知られたx86の補助プロセッサとは完全に別個であり、知られているどの補助プロセッサよりも深く埋め込まれている、というものです。CPUのすべてのメモリだけでなくレジスタファイルと実行パイプラインにまでアクセスできるからです。
この区別が重要な理由は、脅威モデルが違うからです。
MEやPSPは別個のプロセッサです。自分のファームウェアを走らせシステムメモリにアクセスしますが、メインコアの実行パイプラインのなかにいるわけではありません。対応方法もそれに合わせたものになります。ファームウェアのバージョン管理、ネットワークアクセスの遮断、一部の環境での無効化の試みが議論されます。
rosenbridgeが説明するものは違います。実行中の命令ストリームのなかで切り替わり、同じパイプラインで特権検査を飛ばします。ソフトウェアの観点からは、命令ひとつが急に別の意味を持つことに近いところです。
この二つを「CPUのなかの隠れたコア」とひとまとめにすると、対応方法もひとまとめになります。実際にはまったく違う層の問題であり、一方への対応がもう一方にはまったく通用しません。
どうやって見つけたか — 文書なしに命令集合を探索する問題
ここからがこの研究で実際に一般化される部分です。どうやって見つけたか。
x86の命令集合を外から探索するのは思ったより難しいところです。理由がいくつかあります。
命令が可変長です。1バイトのものもあれば15バイトのものもあります。だから「すべての命令を列挙せよ」という要求に正答がありません。バイト組み合わせの空間が天文学的なので、やみくもに全数調査することもできません。
文書化されていない命令は定義上参照する表がありません。 ディスアセンブラはマニュアルを根拠に作られているので、マニュアルにないものについてはディスアセンブラも知りません。
そして誤ったバイトを実行すればプログラムが死ぬかシステムが止まります。
著者の道具であるsandsifterが解く問題がこれです。READMEの表現で「プロセッサの命令集合を探索するために機械語を体系的に生成し、実行を観察しながら異常現象を監視することで、x86プロセッサの隠された命令とハードウェアのバグを監査」します。
核心は不一致を見つけることです。プロセッサが実際にどう解釈するかと、参照用ディスアセンブラがどう解釈するかを比べて、二つの答えが分かれる地点を集めます。人がマニュアルを読んで推測するのではなく、機械二台の意見の違いを自動で収集する方式です。
sandsifterのスキャンが実際に見つけるもの
この道具の結果の説明が現実的なので引用に値します。
基本の監査はこう実行します。
sudo ./sifter.py --unk --dis --len --sync --tick -- -P1 -t
READMEによれば、スキャンはプロセッサの速度と複雑度に応じて数時間から数日かかります。終わったら要約の道具を回します。
./summarize.py data/log
そしてここが重要なのですが、READMEはこう書きます。「一般的にあなたのプロセッサでは数百万個の文書化されていない命令が発見されるだろうが、これらはたいてい少数のグループにまとめられる。」
数百万という数字に驚く必要はないという意味です。要約の道具は異常現象をまとめたあと、三つの範疇に分類することを試みます。
- ソフトウェアのバグ — ハイパーバイザーやディスアセンブラのバグ
- ハードウェアのバグ — CPU自体のバグ
- 文書化されていない命令 — プロセッサに存在するが製造元が認めていない命令
READMEは、自動分類が難しい場合があり手動分析が必要になりうるとも明示します。
成果の一覧もそのまま移します。この道具は「すべての主要ベンダーの秘密のプロセッサ命令、ディスアセンブラとアセンブラとエミュレータに広範に存在するソフトウェアのバグ、エンタープライズ向けハイパーバイザーの欠陥、そしてx86チップの良性および安全上重大なハードウェアのバグ」を見つけ出したと書かれています。
方法は一般化されるが発見は一般化されない
この二つを並べると、この研究をどう扱うべきかが明確になります。
発見は狭いところです。 VIA C3、2018年、以後の世代にはなし、悪意なしと推定。今日あなたのノートPCやサーバーのCPUにこれがある可能性は事実上ありません。VIA C3の入った産業機器をまだ運用しているなら話は別ですが、その場合はすでに別の理由でも交換対象でしょう。
方法は広いところです。 「文書のないインターフェースを相手にするとき、二つの独立した解釈器を置いて意見が分かれる地点を自動で収集する」というアプローチは、プロセッサにだけ使われるものではありません。
同じ構造がこういう場所にも当てはまります。
- パーサー二つが同じ入力を別々に解釈する地点を探す(リクエスト密輸と逆シリアル化脆弱性の源泉です)
- クライアントとサーバーが同じプロトコルメッセージを別々に解釈する地点を探す
- コンパイラとインタプリタが同じソースを別々に処理する地点を探す
- 二つの異なる実装を同じ入力で走らせて結果を比べる差分ファジング全般
最近の事例としては、PostgreSQLをRustで再実装したpgrustプロジェクトがあります。原本と再実装を同じ入力で走らせて動作が分かれる地点を探す方式で、リポジトリの文書によれば、その過程で原本のPostgreSQL側のバグまで発見したそうです。参照実装があるということは無料のオラクルがあるという意味であり、これはファジングでもっとも値打ちのある資産です。
実務者がここから持ち帰るもの
整理します。
第一に、リポジトリの説明とREADMEの本文で範囲が違うことがあります。 セキュリティ研究において題名は発見の範疇を語り、本文は発見の範囲を語ります。引用するときは本文のほうを引用すべきです。
第二に、研究者本人が付けた但し書きを消さないでください。 rosenbridgeの免責条項は、著者が自ら「悪意を含意しない」と書いたものです。その文を外して引用することは、研究者がしていない主張を代わりにすることです。
第三に、道具の検出限界を併せて読んでください。 rosenbridgeの確認用の道具は「研究された形から少しでも変形すれば見逃す」と明示します。これはこの道具だけの問題ではなくシグネチャベースの検出全般の性質です。あなたが使うスキャナーも同じ限界を持っており、たいていそう明示しません。
第四に、緩和策の有効範囲を確認してください。 READMEは起動時点にMSRを操作してバックドアを閉じるスクリプトを提供しながら、「これを適用してもカーネル権限を持つ攻撃者は再び有効にできる」と書きます。ほとんどの緩和はこういう形です。特定の攻撃者能力の下でのみ有効であり、その能力を超えれば無効です。どの脅威モデルで有効なのかを知らなければ、その緩和があなたにとって有効なのかも分かりません。
ハードウェアの信頼という問題は本物の問題であり、こういう研究はその問題を議論可能な形にしてくれます。だからこそ正確に引用する価値があります。
参考資料
- xoreaxeaxeax/rosenbridge — GitHub(2018年8月作成、2018年10月最終コミット。本文の引用はすべてREADMEから移したものです)
- xoreaxeaxeax/sandsifter — the x86 processor fuzzer
- Breaking the x86 ISA — Christopher Domasの白書(sandsifterリポジトリ内)
私はrosenbridgeの確認用の道具もsandsifterのスキャンも直接実行していません。二つの道具はどちらもベアメタルでの実行を要求し、システムを停止させうると警告しています。本文の動作の説明はすべてリポジトリの文書に書かれている内容です。
현재 단락 (1/59)
`xoreaxeaxeax/rosenbridge` というGitHubリポジトリがあります。説明は一行です。「Hardware backdoors in x86 CPUs.」スターは2,500個を超...