前の記事はこちら。
さて、BranchScopeを使うと分岐命令の挙動を抜き取ることで別プロセスのプログラムの動作、しいては別プロセスの秘密情報を読み取ることができるということが分かった。
本論文をもう少し進めていき、どのようなアプリケーションで影響があるのか。また対策は無いのか見ていく。
分岐予測ミスの判定はどのようにして行う?
さて、どのようにして分岐予測がヒットorミスであることを判定すれば良いのだろうか? とりあえず一番単純な方法として、ミスした場合のペナルティをタイマで測定してそれで判断すると言う方法が有り得る。 ユーザ空間でもrdtsc命令やrdtscp命令が使用可能なので、それで時間を計ればよいだろう。
そのために、1つの分岐命令で * 分岐するかしないか * 分岐予測がヒットしたかミスしたか に分けてペナルティを計測してみたのが図7となる。 ここで重要なのは、分岐するかしないかに関係なく、ミスが発生する場合に大きなペナルティが生じる。 図7aが、分岐しない場合における分岐予測のヒットとミスにおけるペナルティの分散具合、図7bが、分岐しない場合における分岐予測のヒットとミスにおけるペナルティの分散具合となる。
さらに、図8は上記の測定を何度も行い、システム上のノイズの影響をなるべく少なくした結果だ。 もちろん、最初の試行(キャッシュフェッチの影響が出る)よりも2番目の試行の方が誤差が小さい。
これにより、Victimプロセスが分岐を実行した後、Atackerプロセスが分岐命令を実行することによりVictimプロセスの動きを予測することが可能になる。
例えば、Victimプロセスにより分岐予測の飽和カウンタがStrongly Taken(ST)になっているものとしよう。 Victimプロセスが分岐命令を実行し、これが実際に分岐したものとする。 Atackerが分岐命令を実行し、これが分岐しない場合、(NNパタン)、表1におけるMM(Miss & Miss)パタンが観測されることにある。
Victimプロセスが分岐命令を実行し、分岐しなかったものとすると、 Atackerが分岐命令を実行し、これが分岐しなかった場合(NNパタン)、表1におけるMH(Miss & Hit)パタンが観測されることになる。
BranchScopeにより攻撃するアプリケーション
このBranchScopeだが、原論文によるとIntel SGX(Software Guard eXtension)をも突破することが出来るということらしい。
まずは、SGXというものを調査してみると、アプリケーションがハードウェア的に保護されたメモリ領域を作り、 他のプロセスからアクセスすることができない領域を作ることができるらしい。 これはシステムソフトウェアであっても、特定のアプリケーションによって作られたメモリ領域にアクセスすることはできない。
SGX を使っていても...?
表はSGXでプロセスを保護した状態において、内部プロセスのビット情報を分岐命令から推測した例である。 たとえSGXを使っていても、高い予測率でビット情報を読み取れていることが分かる。
BranchScopeで攻撃できるアプリケーション達
Montgomery Ladder
この演算は、現代の暗号化において非常に重要な要素であるRSAに使われている演算である。 基本的に秘密鍵kに依存しない演算ではあるため、タイミングや電力を読み取る形式には強いとされているが、秘密鍵kiに基づいて分岐命令を実行するためにBranchScopeによる予測が可能であるとされる。 最新の暗号ライブラリは分岐命令を含まないように慎重に設計されているのでこの場合は抜き取れる情報は限られるが、古いライブラリであれば情報を抽出できる。
libjpeg
画像を復元する際にのIDCT(inverse cosine transform)の操作に分岐命令が含まれているため、jpegライブラリの動作を読み込んで画像を復元することができる。 もともとページフォルトの回数をカウントするサイドチャネル攻撃により可能であるとされていた。 この攻撃はページフォルトの攻撃では行列の行と列の要素0であるかどうかを判定する分岐命令を実行しているが、さらにBranchScopeはこの行列の要素が0でなかったとしても攻撃することができる。
ASLR value recovery
メモリ領域のアドレスマップをランダム化する暗号化方式(ASLR)に対して、分岐命令が衝突するかどうかを観測することによりアドレス空間のランダム化機能をバイパスすることができる。
じゃあどうやって防げるの?
このBranchScopeのもともとの発想は、ハードウェア的に分岐予測器が共有されているところ、からスタートしている。 じゃあこれはどのようにして防ぐことができるのだろう?
ソフトウェアによるBranchScope防止方法
まず最も単純な方法として、秘密情報に対して分岐命令を発生させない。 慎重にプログラムを構築する必要がある。 ただし、大規模なシステムに対してこれをすべて適用することはできない。なのでこの方法は限定的な解決策だ。
もう一つの方法は、そもそも分岐命令を発生させないコンパイラの最適化だ。これは"if-conversion"と呼ばれている。 例えば、条件分岐命令を発生させない代わりに、"conditional move(cmov)" でデータフローを選択する方法がある。これだと条件分岐が発生しない。
ハードウェアによるBranchScope防止方法
PHTエントリ選択のランダム化
BranchScopeはどのエントリを選択するかを仮想アドレスから推定することができることを前提にしているが、このインデックス選択をランダム化することによりBranchScopeを無効化することができる。 各プロセスでランダム値を発生させ、この値により使用するPHTを選択するようにすれば、BranchScopeの攻撃を防ぐことができる。
そもそも分岐命令に対して分岐予測を実行しない
性能が低下することを受け入れることができるならば、秘密情報を扱うブロックについては分岐予測を行わないという手法もあり得る。
BPUの分離
プロセス毎に使用するBPUをハードウェア的に分離してしまう。 これはハードウェアの増加などの問題を招く。