FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

Intel CPUの脆弱性"ZombieLoad"の論文を読んでみる

Intelがまた出した。Meltdown / Spectre系のCPUの脆弱性として新たに発表された"ZombieLoad"である。

これもまた論文が発表されている。これらの論文は、最新のCPUの技術を勉強するにあたって非常に有用なものだ。ZombieLoadの論文を読んで、どのような脆弱性であるのかを読み解いていくことにした。

参考にしたのは、"ZombieLoad: Cross-Privilege-Boundary Data Sampling" という論文だ。以下からダウンロードできる。

arxiv.org

すべてを理解できたわけではないが、ZombieLoadの本質は、Intel CPUのハードウェア的なバグであるというところであると言える。アーキテクチャ上のバグではないため、AMD、Armでは現れない。Intelの実装が単純に問題だった、ということになりそうだ。

そもそもMeltdown / Spectreの分類はどのようになっているのかというところから復習する。

  • Spectre : 分岐予測が予測に失敗する事象を悪用する
  • Meltdown : CPU例外の後の一時的な実行を悪用する

ということを思い出しておく。

この中でZombieLoadはMeldwon型の脆弱性であると言える。ロードストアユニットのバッファに入っている脆弱性をついたものだ。

ちなみに、このZombieLoad単体では攻撃対象のアドレスを制御することはできない。しかし、ZembieLoadと別の攻撃方法を組み合わせることで、より詳細な攻撃が可能になるということだ。

現代のCPUは、命令はアウトオブオーダで実行される。しかし、プログラムの順番を維持しなければならないという制約から、パイプラインの途中ではアウトオブオーダで実行されるとしても最後はインオーダで完了するための機構が備わっている。ALUやLSUの内部はアウトオブオーダで実行されるのだが、特にメモリアクセスについては順番を守る必要がある。このため、LSUの内部はメモリアクセスの順番を守るための様々なバッファが搭載されている。これらの一つに、問題があるということなのだ。

ZombieLoadのキモは、あるロード命令が例外を発生した場合、そのロード命令より前のメモリ操作に属する古い値を投機的にロードしてしまう、ということだ。

f:id:msyksphinz:20190518235016p:plain

ZombieLoadについて説明するにあたり重要なCPU内ユニットとして、メモリオーダバッファ(Memory Order Buffer)がある。Intel CPUの場合、データロードを行うユニットは2つ、データストアを行うためのユニットが1つ搭載されている。メモリオーダバッファはロードバッファとストアバッファの内部を管理し、メモリの依存関係を解決してどのメモリアクセス命令を発行してよいのかを決定する。

ZombieLoadが攻撃対象とするロードバッファは、ロード命令が発行されると、その情報を格納されるバッファだ。

  1. ロード命令が発行されると、ロードバッファにキューイングされる。
  2. ロード操作がメモリに発行され、データが返されると、対応するロードエントリを開放する。
  3. ロード命令がリタイアする。

上記の手順でロード命令は処理される。

しかしここで問題なのは、Intel CPUの場合はロード命令が複雑な複雑なマイクロアーキテクチャの状態に入った場合、そのロード命令の後にロードデータを使う命令は、ロードバッファに格納されている古いデータを読むことがある、ということが観測されたのである。ロード命令が実行中断される前に、漏洩した値が後続の命令によって投機的に使用される可能性がある、ということである。

これだけだとなかなか攻撃手法として使うことができないが、さらに従来のサイドチャネル攻撃と組み合わせることでより強力な攻撃手法として成立させることができる。

  • いったい何が原因なのか?

今回のこのZombieLoadは、他のサイドチャネル攻撃と異なり、ハードウェア的な原因が明らかになって以来ということが問題となっている。つまり、アーキテクチャの問題ではなく、Intel CPUの実装的なバグではないかということである。

この問題の原因を特定するために、以下の実験を行っている。

  1. あるページをキャッシュ不可に設定し、キャッシュからそのページをフラッシュする。
  2. そのページに対するロード命令は、すべてのキャッシュを回避されメモリに直接アクセスされ、データは直接フィルバッファに転送される。
  3. キャッシュにデータのコピーがないことを確認するために、秘匿情報をキャッシュ可能なページに書き込む。
  4. 再度と秘匿データをロードすると、キャッシュ不可能な場所からデータをロードするが、ここでリークが発生する。

  5. 攻撃のシナリオ

攻撃するタイプとしては、2種類が考えられる。

  • Variant 1: Kernel Mapping : カーネルとユーザが同じ物理ページを異なるアドレスから参照する際、異なるプロセスであっても下位のアドレスがあっているため、Faultページロードが発生した際にデータのリークが発生する。
  • Variant 2: Microcode-Assisted Page-Table Walk : ページフォルトが発生した際の、マイクロコードによるページテーブルウォークが起きる。今回のシナリオあは、物理ページに対して仮想アドレス v v_2マッピングされている場合、一方のアドレス v_2 側でアクセスビットが無効になっていたとしても、ページテーブルウォークなどのマイクロコーデでの動作が有効になるとデータ漏洩が発生する。

今回ほZombieLoadでは、Meltdownと違い特定のアドレスを漏洩させることはできず、あくまで基本はLSUのフィルバッファに格納されているデータがそのまま読めている、ということだ。しかし様々な手法を使うことで、ケーススタディでは以下の秘匿データを習得することができている。

  • AES-NI鍵データ
  • SGXでガードされた鍵データ
  • VM間の交換チャネル
  • ウェブブラウザの動作のモニタリング

などの攻撃が可能だということらしい。