私は最近、JavaScriptでキャッシュ攻撃を行うことについて次の論文を読んでいました。
https://arxiv.org/pdf/1502.07373v2.pdf
しかし、私はそれがどのように機能するかについて混乱しました。この論文では、(12ウェイキャッシュの)エビクションセットを見つけるのに高い成功率を得るには、8 MBのバッファーで十分でした。これがどのように可能であるか、私には正確にはわかりません。
私は自分のコンピュータの数値を計算しましたが、うまくいくようには見えません(3MBキャッシュ、12ウェイ):
なぜ機能するのですか?
私は自分のコンピューターで試してみましたが、70%の確率で被害者のアドレスを追い出すことができたようです(私が追い出しをまったく実行しなくても、被害者のアドレスはまだ約20%のミス率)。
オペレーティングシステムがページを完全にランダムに割り当てると仮定すると、私の最善の計算では、特定の被害者のアドレスが4 MBのバッファーに少なくとも12の一致するページを持つ確率は約11%です。それはそれほど可能性が高くなく、確かにあなたが見た70%の成功率と一致していません。
ただし、オペレーティングシステムがページをランダムにマッピングするのを避け、代わりに隣接するページをマッピングするために最善を尽くすのには、十分な理由があります。これの1つの理由は、OSが大きな連続したバッファーを割り当てる必要がある場合があり(巨大なページや大きなDMAバッファーなどをサポートするため)、物理ページをランダムに割り当てると、十分に大きな領域を見つけます。これはメモリの断片化と呼ばれます。
しかし、この議論のコンテキストでは、連続割り当てのより興味深い利点は(皮肉なことに)レベル3キャッシュのパフォーマンスです。大きなメモリバッファーを使用するアルゴリズムを実行している場合、最高のパフォーマンスを得る方法は、連続した物理メモリを割り当てることです。これにより、個々のページが互いにキャッシュから追い出されなくなります。この方法でOSがパフォーマンスの最大化に成功すると、攻撃の効果を最大化することにも成功します。4MBのバッファーがキャッシュ全体をカバーし、被害者のページを排除する可能性が100%あります。したがって、観測された70%の成功率は、チャンスの尺度ではなく、適切なキャッシュパフォーマンスのためのページの割り当てにおけるOSの効果の大まかな尺度です。
実際にこのように動作するOSの例を確認したい場合は、 Linuxのバディアロケーター をお読みください。まず、メモリを大きな空きブロックのセットに分割します。次に、ページを割り当てたい場合は、それらの大きなブロックの1つを取り、それを半分に分割します。次に、半分の1つを取り、それを再び半分に分割し、1ページサイズのブロックのペアが得られるまで続行します。その時点で、2ページサイズのブロックが1つ、4サイズが1つ、 8サイズなど。最初の2つの割り当ては、2ページのブロックを半分に分割した結果であるため、互いに隣接する2つの1ページのブロックになります。 3番目の割り当ては、他の2ページのブロックを半分に分割します。これも、同じ理由で他の2ページの隣にあります。
そのため、新しいページが必要なときはいつでも、アロケータは見つけることができる最小のブロックを取り、単一のページになるまでそれを分解します。最後に、ページが解放されると、アロケータはそのすぐ隣に空きページがあるかどうかを確認して、2つのページをより大きなブロックに戻すことができます。正味の効果は、可能な場合、割り当てをほぼ連続的に保つことです。