web-dev-qa-db-ja.com

Meltdownがプローブアレイを使用する必要があるのはなぜですか?

これはメルトダウンアセンブリ言語コードのコードスニペットです。

 1. ; rcx = kernel address, rbx = probe array
 2. xor rax, rax
 3. retry:
 4. mov al, byte [rcx]
 5. shl rax, 0xc
 6. jz retry
 7. mov rbx, qword [rbx + rax]

Meltdownは、ページの配列(256 * 4096サイズ)を使用して、すべての要素を1バイトの値でアドレス指定し、byte [rcx]が何であるかを判別します。その論文によると、アレイのすべてのページを反復処理して、すべてのページの最初のCahe行にアクセスし、それを実行するのにかかった時間を確認しています。比較的高速に実行される場合、キャッシュライン番号はbyte [rcx]です。

Meltdownがそのバイトの値を推定するためにプローブ配列を使用する必要があるのはなぜですか?私が見るように、byte [rcx]のロードを担当する4行目のuOPが実行されると、いくつかのページがアクセスされ、この命令の前にバイトが読み込まれていない限り、新しいキャッシュラインにバイトの値がロードされます。 Meltdownがそのページにアクセスできないのはなぜですか? Flush + Reload攻撃はユーザーモードページに対してのみ機能するためですか?

3
M. Kalter

キャッシュタイミング攻撃キャッシュされたページに保存されている値については何も教えないwhichページがキャッシュされただけです。 Meltdown(およびSpectre)のトリックは、プログラムが知ることを許可されていない値、およびCPUが非常にすばやく「忘れる」ことに応じて、キャッシュに多数の1つページをロードすることです。

Meltdownは、CPUがbrieflyのように不正なメモリ読み取りが成功したかのように動作し、この不正に読み取られた値(ページサイズを掛けたもの)を配列のインデックスとして使用して、キャッシュされるメモリ(プローブアレイの1つのセグメント。正当にアクセスできる)。次に、エクスプロイトは不正な読み取りの例外(segfault /アクセス違反)から回復し、プローブアレイの各ページにアクセスしてプローブアレイのどのページにアクセスしたかを確認し、どのページがアクセスされたかを明らかにします。 「読めない」値だった。


4行目は、いくつかのカーネルメモリにアクセスし、そこから1バイトを読み込もうとします。このアクセスは割り込みをトリガーします。 (このカーネルメモリを含むページは最終的にキャッシュに入れられますが、この事実は私たちには関係ありません。アクセスしているカーネル内のアドレスはすでにわかっています。)この時点で、次の数行を実行するための競争を開始します。割り込みがこのスレッド全体を割り込みサービスルーチンに転送する前。

5行目では、取得した値に4096を乗算しています。これは通常、メモリ内のページのサイズです。この操作は完全にレジスタと即値で実行され、非常に高速であるため、割り込みが発生する前に発生する可能性があります。

6行目(または3行目)が必要な理由がわかりません。おそらく、このコードから引き出されたシナリオは、取得した値がゼロかどうかについて多くのことを気にします。

7行目は、4行目から不正に取得した値(5行目で4096を掛けたもの)をプローブアレイへのインデックスとして使用し、アレイスパンの256ページの1つをキャッシュにロードします。この命令はしばらく時間がかかるため、割り込みが発生する前にcompleteにならない可能性がありますが、startはすぐに実行されます(2つのレジスタを追加して、結果のアドレスをメモリマネージャー)。メモリマネージャーがそのアドレスで値を返すと、CPUはそれをレジスタRBXに格納するのではなく破棄します(割り込みがトリガーされた後に行われたすべての処理が破棄されるため)が、プローブアレイのその1ページとにかくキャッシュにとどまります。 CPUは、不正な読み取りに基づいてのみキャッシュされたページをキャッシュ解除するほど「スマート」ではありません。

同様に、割り込みが追いつくと、不正に読み取られた値をEAX/ALからその行4の前の値に戻します(これは、行2で設定されたゼロです)。 CPUの理論モデルでは、そのレジスタは値を受け取ることさえありませんでした。次の数行は単純にそれがあったかのように実行されます。実際には、CPUパイプラインには各レジスタの多くのコピーがあり、不正な読み取りの下流のコピーには不正な値(下流の命令で使用される)が格納されますが、その不正な値が「実際の」レジスタに書き込まれることはありません。したがって、攻撃者は不正な値で何もすることができません-割り込みがすべてのダウンストリーム命令をスローする前に数クロックのティックを取得するだけで、「この値をディスクに書き込む」などのことを行うには十分ではありませんが、開始しますメモリの読み取りは十分高速で、時間内に完了する必要はありません。

この時点で、プログラムは割り込みによってトリガーされた「OSトラップ」を受け取り、すでに設定したハンドラー(* nixのSEGVのシグナルハンドラー、またはWindowsのアクセス違反のSEH例外ハンドラー)を使用して処理します。 https://stackoverflow.com/questions/457577/catching-access-violation-exceptions )。プログラムはトラップを無視して実行を続行します(通常、これは危険です。ポインターで安全でないことが発生したことを意味します。この場合はare安全でないものです)。次に、プログラムは、プローブ配列の各ページにアクセスするのにかかる時間を計り、超高速でアクセスできるページを(それがすでにキャッシュされているため)見つけ、そのインデックスをページサイズ(再び4096)で除算して戻します。不正に読み取られたバイト。

0
CBHacking