| 発見日 | 2022年6月10日公開 ( 2022-06-10 ) |
|---|---|
| パッチ適用日 | パッチを適用できません |
| 影響を受けるハードウェア | Apple M1プロセッサ |
| Webサイト | pacmanattack.com |
Pacman [ a ]は、特定のARM CPU のサイドチャネル脆弱性で、マサチューセッツ工科大学のセキュリティ研究者によって 2022 年 6 月 10 日に公開されました。これは、 Apple の M1 CPUを含む多くの ARMv8.3 チップのポインタ認証 (PAC) メカニズムに影響します。[ 1 ] Pacman は、攻撃者がポインタの PAC 署名を推測できる「オラクル」を作成します。推測が間違っていたとしても、プログラムはクラッシュしません。PAC 署名は通常 16 ビット幅未満であるため、攻撃者はオラクルを使用して 2 の16乗以下の試行で署名を推測できます。これは、CPU キャッシュと分岐予測器の固有の設計によって引き起こされるため、ハードウェアを変更せずに修正することはできません。
Pacman単体では、悪用可能な脆弱性ではありません。PACは「最後の防衛線」[ 2 ]であり、CPU上で実行されているソフトウェアがメモリ破壊攻撃に悪用されていることを検知し、攻撃者が攻撃を完了する前にソフトウェアをクラッシュさせることで対応します。Appleは、この脆弱性が悪用されるには特定の条件が必要であるため、ユーザーにとって深刻な脅威とは考えていないと述べています[ 3 ] 。
PacmanはSpectreに似ており、分岐予測とメモリキャッシュという2つの主要なCPU最適化を悪用してPACオラクルを作成します 。[ 4 ]
PACは、ARMv8.3ベースのコンピュータプロセッサのセキュリティ機能であり、ポインタの上位ビットに暗号署名を追加することで、リターン指向プログラミング(ROP)の脆弱性を軽減します。コンパイラは、ポインタをメモリに格納する前にPACの「署名」命令を出力し、ポインタをメモリからロードした後に「検証」命令を出力します。攻撃者がポインタを改ざんした場合、署名は無効になり、次にポインタにアクセスしたときにプログラムがクラッシュします。[ 5 ] PAC署名は、ポインタの未使用の上位ビットに収まるほど小さくする必要があるため、暗号的に安全ではありません。したがって、攻撃者が推測した署名が正しいかどうかをプログラムをクラッシュさせることなく確実にテストできる場合、正しい署名をブルートフォース攻撃で突き止めることができます。[ 6 ]
現代のCPUは、条件分岐によるパイプラインのストールを減らすために分岐予測を採用しています。分岐予測は、ヒューリスティックを用いて条件分岐の方向を推測し、条件がまだ評価されている間に予測されたパスの実行を開始します。この期間中に実行される命令は「投機的」であり、CPUはその結果をメモリに書き戻さずにリオーダーバッファ(ROB)に保持します。CPUが条件の評価を終え、最初の予測が正しかったと判断すると、ROB内の命令の変更内容をメモリに書き戻し、発生した例外を伝播させることで「リタイア」します。もし投機が正しくなかった場合、CPUはROBをフラッシュし、正しい位置から実行を再開します。[ 7 ]

CPUキャッシュは、頻繁にアクセスされるメモリをCPUダイ上にキャッシュすることで、メモリアクセスを高速化します。これにより、物理的に分離されたノースブリッジとRAMチップとの通信時間が短縮され、メモリアクセスのコストが数百サイクルから10サイクル未満にまで削減されます。キャッシュされていないアドレスがロードされると、CPUはロードされたデータを直ちにキャッシュに格納し、キャッシュがいっぱいの場合は別のエントリをキャッシュから追い出します。これらの変更はROBには保持されません。これは、キャッシュ内のアドレスの有無が「観測不可能」と見なされるためです。そのため、投機的実行中に発生した格納と追い出しは、最終的にそのパスが実行されなかったとしても、ROBがフラッシュされた後も保持されます。[ 8 ]
Pacmanは、CPUを騙して、予測ミスした分岐におけるPACシグネチャの妥当性をチェックさせ、ROBフラッシュ時に誤った推測によって生成された例外を破棄します。[ 9 ] 推測が誤っていた場合、投機的実行中にスローされた例外によってCPUはストール状態になり、それ以降の命令が投機的に実行されるのを防ぎます。Pacmanガジェットは、以下の形式の命令列です。
if (条件): ptr = verify ( attacker_tamperable_pointer ) load ( ptr )この形式のシーケンスは一般的であり、PACをサポートするほとんどのコンパイル済みプログラムで見られます。[ 10 ] CPUが条件を誤って予測した場合、PAC検証命令の投機的実行を開始します。攻撃者の推測が正しかった場合、検証命令は成功し、CPUはメモリからアドレスのロードに進みます。推測が間違っていた場合、検証命令は例外をスローします。この例外はROBに保持され、CPUが条件が偽であると判断すると破棄されます。その後、攻撃者はハードウェアサイドチャネル攻撃を使用してロード命令が実行されたかどうかを判断し、推測したシグネチャが正しかったかどうかを判断します。[ 11 ]
Ravichandranらは、キャッシュベースのPrime and Probe法を用いてロード命令が実行されたかどうかを判定できることを実証している[ 11 ]。攻撃者は、Pacmanガジェット内のロード命令が実行されたかどうかを、キャッシュにデータを埋め込んだ後、ガジェットを呼び出し、以前にロードされたアドレスへのアクセスの遅延をチェックすることで判定する。アドレスの1つが以前よりも長くかかっている場合、そのアドレスはガジェットによって追い出されており、攻撃者は自分の推測が正しかったと判断する。その後、攻撃者はこの偽造されたポインタをプログラムの他の場所で利用して、そのポインタを乗っ取る可能性がある。
攻撃者は、 condition = trueでパックマンガジェットを何度も呼び出します。分岐予測器は、以降の呼び出しで条件が真であると推測するように学習します。この間、 はattacker_tamperable_pointer有効なPAC署名を持つ元の値です。
攻撃者は、制御下にあるアドレスからデータをロードすることでL1キャッシュを埋めます。これらのメモリ位置の内容は重要ではなく、攻撃者はアクセスレイテンシを正確に測定できれば十分です。[ 12 ]
|
|
攻撃者はattacker_tamperable_pointerターゲットポインタを上書きし、ターゲットポインタのPACシグネチャを推測します。次に、condition = falseでPacmanガジェットを呼び出し、分岐予測を誤らせます。分岐予測器はif文の内容を投機的に実行し、最終的にパイプラインをフラッシュしてロールバックします。[ 13 ]
この投機的実行中に、次の 2 つのことが発生する可能性があります。
verify()命令にフォールトが発生しなかったことを意味し、推測されたシグネチャが正しかったことを意味します。load()その後、命令はターゲットポインタをキャッシュにロードし、攻撃者のエビクションセット内のアドレスをエビクションします。load()。これは、推測されたシグネチャが間違っていたことを意味します。これは予測ミスした分岐内で投機的に実行されたため、エラーはプログラムには伝播しません。
|
|
攻撃者は、追い出しセット内の各要素へのアクセス時間を測定します。もし要素の1つが追い出されていた場合(つまり、アクセスが遅い場合)、推測は正しかったことになります。もしどの要素も追い出されていなかった場合(つまり、すべてのアクセスが高速の場合)、推測は間違っていました。このプロセスは、正しいシグネチャが見つかるまで、異なる推測で繰り返すことができます。[ 11 ]