Spectre and Meltdownについて
今回CPUに依存する脆弱性が発見されて大きな問題となっている。
そこで正月休みを使ってこの問題の解説を試みる。
Disclaimer
私はセキュリティの専門家ではないので間違えた情報があるかもしれない。
一次情報を載せておくので怪しい場合にはそこにアクセスして自分で確認するように。
この情報を鵜呑みにしておきたいかなる問題にも責任は負いかねる。
今回の脆弱性についてのWEBページ
業務で問題の解決を行う場合にはこのページを参照すること。
概要
今回は2つの脆弱性が問題になっている。
1つ目はMeltdownと名付けられており、CPUのout-of-order実行を利用したもの。
2つ目はSpectreというCPUの投機的実行を利用したもの。
今回この問題が深刻なのは、どちらもCPUのパフォーマンス最適化のために存在する機構であり、モダンなほぼすべてのCPUに存在すること、
悪意のあるコードとそうでないコードの見極めが非常に難しいことなどから、解決の難しい問題となっている。
Meltdown
Meltdownから解説していく。
Meltdownと名付けられたこの問題はCPUのout-of-order実行の隙を突いた攻撃方法である。
out-of-order
out-of-order
と言うのはモダンなCPUが搭載しているパフォーマンス最適化手段である。
現在のCPUはアセンブリ命令をμOps
という更に小さなCPUのオペレーションに分割して実行する。
このμOps
に分解された命令はReorder-Buffer
とScheduler
によってデータの依存関係が計算されて、実行順が変更される。
結果としてそれぞれ依存関係から独立した命令は順序に関係なく実行され、依存がある部分は依存先の命令が完了次第即実行される。
以下が今回の問題となる疑似コードだが、
gist4ad97b3858f184ca74efbbfe54e845ef
4行目のmov
命令と5行目のshl
命令は依存関係があるものの、それ以外はすべて予めμOps
に分解されて実行される。
以下はWikipediaからの引用
OoOでは、命令及び実行結果を一時溜めておく場所を作り、命令の実行を次のように細分化する。
1 命令フェッチ。
2 命令にリオーダ・バッファ(reorder buffer)のエントリを割り当てる。
3 命令を命令待ち行列または命令発行キュー(reservation station, issue queue)に送る(dispatch)。
4 命令待ち行列内の命令は、入力オペランドが得られるまで実行されない。入力オペランドが得られた段階で、待ち行列内にそれより古い命令があっても先に待ち行列から取り除かれ、実行されることになる。
5 命令が適当な実行ユニットに対して発行(issue)され、実行される。
6 実行結果がリオーダ・バッファに格納される。
7 リオーダ・バッファ内の命令のうち、最も古い命令の実行が完了すると、その実行結果はレジスタファイルに書き戻され、命令はリオーダ・バッファから取り除かれる。これを卒業ないしリタイア(graduation, retire)ステージと呼ぶ。命令待ち行列とは異なり、より新しい命令が実行完了状態であっても、それより古い命令がリオーダ・バッファ内にリタイアせずに残っている場合は、その(より新しい)命令がリタイアすることはできない。
Preventing reading Karnel Memory from User space
上の例で示した疑似コードは実行するとカーネルの特権メモリをユーザースペースで読み込んでいるため例外を発生させる。
そのため、当然ユーザースペースからカーネルメモリを読み込むことは不可能である。
しかし後に述べるTransient Instruction
を経由することでカーネルメモリをCPUキャッシュに載せることが可能になる。
Transient Instruction
ちょっとどう翻訳していいかわからないのだが、これはout-of-order
実行によって実行される、
本来の実行パスでは実行されるはずのない命令である。
以下に擬似コードを示す。
このコードは擬似コードであり実際には動作しない。
int main() { char arr[1]; Exception e; throw e; arr[data * 4096] }
この擬似コードのarr[data * 4096]
は本来throw e
が例外を投げることによって実行が中断されるため実行されないのだが、
out-of-order
によってarr[data * 4096]
のメモリアクセスが実行される。
Reading Privilleged Memory
以上のテクニックを駆使することによって特権がなくても特権が必要なメモリの値をロードすることができる。
コードを再掲する。
gist4ad97b3858f184ca74efbbfe54e845ef
- まずは
line 4
でmov
命令を発行しrcx
にあるカーネルメモリの内容を読み込む line 5
でal
に格納した命令にアクセスして依存を生成するline 6
は最適化に対する対応なので無視line 7
でrax
つまり、先程カーネルメモリの内容を読み込んだアドレスに対して間接参照をする。
これらの処理がμOps
に分解されout-of-order
によって、line 7
でline 5/6
の命令完了待ち状態になり、
line 5
で例外が発生するよりも先にline 7
が実行される。
こうすることで例外が発生するよりも先に格納されたメモリにアクセスするすることが可能になる。
Side-Channel-Attack
しかし、上記の方法を利用してもout-of-order
の実行結果は巻き戻されて取得ができない。
ここでSide-Channel-Attack
を利用する。
Side-Channel-Attack
とは外からハードやCPUの状態を観測することで値を取得するという方法である。
今回のペーパーではFlush+Reload
という方法を利用していた。
Flush+Reload
については以下
https://eprint.iacr.org/2013/448.pdf
この方法を使うことでline 7
でのメモリアクセスを計測し、
キャッシュメモリを調べて、そのメモリアクセスにかかった時間を計測することでどのアドレスがキャッシュされているかを取得できれば、
秘密の値のみに依存したアドレスが取得できるようだ。
また攻撃手法として例外を握りつぶすためにプロセスのfork
を行い、その中でこれらの攻撃を行い、
メインプロセスでメモリアドレスを調べる方法が提案されている。
Spectre
こちらはCPUの投機的実行という機能を利用したものでMeltdownと似ているが、より実行しやすい。
投機的実行 (Speculative Execution)
CPUは分岐命令(if文とか)を実行する際に、パフォーマンス最適化のために過去に分岐した履歴から分岐先を予想して、
条件分岐の結果評価が完了する前にthen
節やelse
節を実行する。
その後条件分岐が確定し、投機的実行した結果の値が必要なくなれば、その結果はそのまま捨てられる。
つまりMeltdownみたいに実行されてほしくないコードが実行されることがありうる。
ちょっと嫌な雰囲気になってきたね。
Side-Channel-Attack
やはりここでもCPUキャッシュの状態を観測することで値を取得する。
以下に擬似コードを示す。
if (x < array1_size) y = array2[array1[x] * 256];
以下はペーパーに記載されていたシナリオである。
ここでarray2[array1[x] * 256]
はx < array1_size
が確定する前に実行されるとし、x
は取得したいアドレスの値とする。
するとarray1[x]
がキャッシュから取得され、アドレスk
が手に入る。
その後array2[k]
にアクセスすることで、キャッシュミスが起こり、その間にx < array1_size
が確定することで、すべての結果が破棄される。
しかしarray2[k]
への投機的実行はすでにCPUキャッシュに変化を起こしてしまっているのでそれを観測することで目的のデータを取得することができる。
Javascirpt
ペーパーによるとjavascriptでも実行できるためそれなりに危険そうである。
V8のデバッグシェルであるd8で実行して成功したようなので結構ダメそう。
Vendors
- Google
- Google Online Security Blog: Today's CPU vulnerability: what you need to know
- Cloud系はそれぞれアップデートすること
- Chromeは
SharedArrayBuffer
等を無効にするらしい(影響範囲とか大丈夫なのだろうか?)
- Mozilla
- Mitigations landing for new class of timing attack | Mozilla Security Blog
SharedArrayBuffer
の無効化、performance.now()
のresolutionを20µsに低減
- Apple
- わからん!
まとめ
ちょっと内容が複雑なため間違いを含んでいる箇所があったら申し訳ない!
とにかく基本は1次情報にあたってほしい。
より詳しい方、コメント等で修正があったらしていただけると助かります。
もう一度掲載しとく