Reptar: Intel CPUのFSRM/REX脆弱性
(lock.cmpxchg8b.com)- 一部のIntelプロセッサでは、
rep movsと重複したrex.r接頭辞が FSRM最適化 と組み合わさると、CPUが通常の規則から外れた「glitch」状態に入ることがある - 原因は、x86の緩い 接頭辞デコード と、
movsbのように暗黙のオペランドを使う命令で本来は無意味であるはずのrex接頭辞が、特定の最適化経路に乗ってしまうことにある - Googleの検証パイプラインは2023年8月、この組み合わせで予測不能な結果を発見し、予期しない分岐・無条件分岐の無視・
xsaveとcallの命令ポインタ記録異常を観測した - 複数のコアが同じバグを同時にトリガーすると、machine check exception とシステム停止が発生する可能性があり、非特権ゲストVM内でも再現できるためクラウド環境で重要である
- Intelは影響を受けるプロセッサ向けの マイクロコード更新 を公開しており、更新できない場合は
IA32_MISC_ENABLEで fast strings を無効化できるが、大きな性能低下を伴う
x86接頭辞と rep movsb
rep movsbはx86でメモリを移動する慣用的な方法で、ソース・宛先・方向・カウントを設定すると、プロセッサが繰り返しコピーを処理する- 実際の命令は
movsbであり、repはその命令を複数回繰り返すように変える 接頭辞(prefix) である - x86命令のデコードは比較的緩く、意味のない接頭辞や衝突する接頭辞が付いていても通常は無視される
- コンパイラはこのような重複接頭辞を使って、単一命令を望ましいアラインメント境界までパディングできる
rex、vex、evexは後続命令のデコード方法を変える接頭辞である
rex 接頭辞が問題になる組み合わせ
- i386では汎用レジスタが8個なので3ビットでレジスタを指定できたが、x86-64では汎用レジスタが16個なので追加ビットが必要である
rex接頭辞は、後続命令がオペランドをエンコードする際に利用できる余分なビットを提供する- 通常は
rex.rxbのように表記され、b、x、r、wビットが選択的に設定される
- 通常は
movsbはオペランドが命令内に明示されず、すべて暗黙的であるため、rex.rxb rep movsbのrexビットは意味を持たないはずである- 通常、プロセッサはこのような
rex接頭辞を静かに無視するが、fast short repeat move をサポートするシステムでは、この組み合わせが脆弱性につながる
FSRMと影響を受けるプロセッサ
- FSRMはIce Lakeで導入された機能で、ERMSの短い文字列処理の限界を補う
- ERMS(enhanced repeat move/store)は、バッファのアラインメントと広幅ストアをマイクロコードで処理し、従来の
rep movsbコードをより高速にできる- 初期設定コストが大きいため、非常に短い文字列には向かない
- FSRMは 128バイト以下 の短い移動をより高速に処理するための機能である
/proc/cpuinfoのflags行でfsrmフラグによりサポート有無を確認できる- FSRMを含むプロセッサの例は次のとおり
- Ice Lake
- Rocket Lake
- Tiger Lake
- Raptor Lake
- Alder Lake
- Sapphire Rapids
- この一覧は網羅的ではなく、完全な一覧はIntel advisory INTEL-SA-00950 を確認する必要がある
発見と再現
- Googleの検証パイプラインは Oracle Serialization 手法により、ランダム生成したプログラムの2つの形を実行した後、最終状態が同じかどうかを比較する
- 関連説明は以前の記事 Oracle Serialization にある
- 2023年8月、FSRM最適化された
rep movsに重複したrex.r接頭辞を追加したとき、予測不能な結果が発生した - 観測された異常動作は次のとおり
- 予期しない位置への分岐
- 無条件分岐の無視
xsaveまたはcall命令で命令ポインタ(instruction pointer)が正確に記録されない- デバッガがあり得ない状態を報告する
- 複数のコアが同じバグをトリガーすると、プロセッサが machine check exception を報告して停止する可能性がある
- 非特権ゲストVM内部でも再現可能であり、クラウド事業者にとってセキュリティ上重要な問題となる
- 再現ツールと研究資料はGoogleの security research repository で公開されている
icebreakツールのローカルミラーも icebreak.tar.gz として提供されている
icebreakは異なるコアのペアを指定して再現を試みる- 影響を受けないシステムでは、無限ループのように出力がないはずである
- 影響を受けるシステムでは、再現成功ごとに
.が出力される - SMTの兄弟コアでは任意分岐が観測される可能性がある
- 同一パッケージのSMP兄弟コアでは machine check が観測される可能性がある
- 異なる2コアを指定しない場合、hammer thread が必要になることがある
考えられる原因と観測された影響
- 現代システムのマイクロコード動作は公開されていないため、根本原因は観測に基づく理論としてしか扱えない
- CPUは大きく フロントエンド とバックエンドに分かれる
- フロントエンドは命令をフェッチしてデコードし、μopsを生成する
- バックエンドは命令をアウトオブオーダー実行し、ROB(reorder buffer)に結果を保存してコミットする
- このバグは、フロントエンドが
movsb命令のサイズを誤って計算し、その後のROBエントリが誤ったアドレスに結び付けられる状態を引き起こすように見える - この状態では、命令ポインタが誤って計算される混乱状態が発生する
- システムは最終的に内部的に一貫した状態へ回復できるが、その途中の結果は誤る可能性がある
- 複数のSMTまたはSMPコアが同時にこの状態に入ると、十分なマイクロアーキテクチャ状態の損傷が発生し、machine check を強制しうる
- システム状態を machine check が発生するほど損傷させることができ、SMT兄弟コアにスケジュールされたプロセス実行ではスレッド間干渉が観測される
- この損傷を権限昇格に十分な精度で制御できるかどうかは確認されていない
対応方法
- Intelは影響を受けるすべてのプロセッサ向けの更新済みマイクロコードを INTEL-SA-00950 として公開している
- OSまたはBIOSベンダーがすでに更新を提供している可能性がある
- 更新できない場合は、
IA32_MISC_ENABLEモデル固有レジスタを通じて fast strings を無効化できる - fast strings の無効化は大きな性能低下を引き起こすため、どうしても必要な場合を除いて使用すべきではない
関連CPUバグ資料
- Googleは発見したCPUバグを公開しており、一部はセキュリティ影響がなくても読む価値がある
- 例
- movlps just doesn’t work:
movlpsが動作しない事例 - registers can sometimes roll back: レジスタが以前の値にロールバックする事例
- movlps just doesn’t work:
1件のコメント
Hacker News の意見
関連記事: https://cloud.google.com/blog/products/identity-security/goo...
https://news.ycombinator.com/item?id=38268043から来た内容だが、コメントはここに統合されている
これを読んで、自分のソフトウェアが動いているハードウェアについて自分がどれだけ知らないかを実感した
「プレフィックス(prefix)は機能をオン・オフして命令の動作を変えられる」というが、なぜ機能をオン・オフするのに「プレフィックス」が必要なのか気になる
BIOSに入らずに機能を動的に切り替えるためのものなのか?
REPプレフィックスが最も一般的で、同じ命令を可変回数だけ繰り返せるようにする役割を持つ
繰り返し回数はCXレジスタから取り、メモリ内でオブジェクトを移動するような一般的なループを非常に短くできる
memcpy関数はしばしばREP MOVS 1命令にインライン化され、必要ならカウントをCXにコピーする命令が付く
REXプレフィックスも、64ビットプログラムが64ビット値とアドレスを頻繁に扱うためかなり一般的だ
どのプレフィックスもBIOSなどでグローバル設定可能なものをトグルするのではなく、次の命令が何をすべきかを指定するだけだ
あまり使われないアドレッシング方式では、DSではなく別のセグメントを使わせる「セグメントプレフィックス」が付き、x86_64の「REX」プレフィックスはレジスタフィールドにビットを追加して汎用レジスタ16個を使えるようにした
同様に「LOCK」プレフィックスは、元の仕様はやや不十分だったものの、一部のメモリ演算をシステムの他の部分に対してアトミックにし、「LOCK CMPXCHG」で比較して設定する処理を実装する、といった使い方がある
他のCPUアーキテクチャにもこうした演算の表現はあるが、通常は既存の命令空間の中に収めるため、すべての命令を表現するのにより多くのビットが必要になる
とくにここで問題になった「REP」プレフィックスは例外に近く、太古から残っているマイクロコード反復プレフィックスだ
それでもmemset/memmoveのような、今でも性能に敏感な演算を表すので、CPUベンダーが最適化し続ける価値があり、今回のバグもそうした過程で生じたようだ
最大の問題は、命令エンコーディング空間を「効率的に活用」したことだ
後になって新しい命令、さらに悪いことに追加レジスタが登場すると、新しい命令バリエーションをどうにか押し込まなければならず、その方法がプレフィックスを付け足すことだった
命令セットを拡張するたびにopcode空間の一部を削って新しいプレフィックスをねじ込んできた
Intelが今年また別の新方式を提案したことを見ると、この流れは続きそうだ
診断過程を見て、qemuがrepz retに遭遇したときのことを思い出した: https://repzret.org/p/repzret/
HNのルール上、こういうタイトルは禁止すべきだと思う
何のリンクなのかまったく伝わらず、URLはむしろさらに紛らわしい
こんな無意味なタイトルなら、投稿者が短い説明を添えるべきだと思う
タイトルに文脈をできるだけ入れると、人々がリンクをクリックせず、ツイートに反応するようにコメント欄で自分の関心事だけを磨き上げることになるのをすでに見てきた
HNは知的好奇心とリンククリックを促すことの中間点を選んでいる
曖昧なタイトルのためにリンクをクリックする気がなくても、少なくともリンクをクリックした人たちに答えることになるので、インターネットの他の場所よりはましだと思う
曖昧で気の利いたタイトルを正当化できるほどの見返りがない記事は、この投稿と違ってフロントページから落ちていく
記事はとてもよく書かれていた
アセンブリプログラミングとIntel命令セットはもちろん、マイクロアーキテクチャについてもほとんど知らないが、説明を追うことができ、ここで何が起きているのかをおおよそ理解できた気がする
AMD CPUも影響を受けるのか知っている人はいるだろうか
問題が本当にプロセッサが命令長を取り違えることだとしたら、大きな性能低下なしにマイクロコードで修正できるという点が印象的だ
自分の直感が完全に間違っているのかもしれないが、命令長の計算は論理ゲートに直接合成される類いのものだと思っていた
考え直してみると、uOPデコーダ自体はハードウェアとして健全で、マイクロコードで最適化されたコピー・ルーチンがuOPストリームについて事実でないことを推論しようとしている状況なのかもしれない
たとえば「なるほど、これはrep movだからループのためにuOPを2つ後ろへ戻ればいいな」といった具合かもしれない
IntelのCPUチームがそこまで詳細を公開することはなさそうだ
「ERMS」と「FSRM」がよく分からず、Googleにも良い資料がほとんど見当たらないように思える。
これらが、
rep movsbを最適化されたSSEmemcpy実装の代わりに最高性能で使えることを示す CPUIDフラグにすぎないのか、それともrep movsbをより高速にする特別なエンコーディングやプレフィックスなのかが気になっている。後者だとしたら、なぜ必要なのか、FSRMがどう活用されるのかも分からない。
ERMSはAVXのより低コストな代替で、FSRMは短いブロック向けのより良いバージョンだったようだ。
「その後のプロセッサの低価格版である、2017年発売のKaby Lake CeleronおよびPentiumには、高速メモリコピーに使えるAVXはないが、Enhanced REP MOVSBはある。
そして2018年以降に発売されたIntelのモバイル・低電力アーキテクチャの一部は、SkyLakeベースではなかったものの、前世代マイクロアーキテクチャよりもREP MOVSBでCPUサイクル当たり約2倍多くのバイトをコピーする」
「Ice LakeマイクロアーキテクチャのFast Short REP MOV(FSRM)以前、Enhanced REP MOVSB(ERMSB)は、ブロックサイズが少なくとも256バイトのときにのみ、AVXコピーや汎用レジスタコピーより高速だった。
64バイト未満のブロックでは、ERMSBの内部起動コストが約35サイクルと高く、はるかに遅かったため、FSRM機能は128バイト未満のブロックも高速化することを目的としていた」
[1] https://stackoverflow.com/a/43837564
[2] http://www.intel.com/content/dam/www/public/us/en/documents/...
最適な命令選択とスケジューリングは、コンパイル時に静的に行うこともできるし、実行時に複数のライブラリ関数の1つを選ぶ、あるいはJITで動的に行うこともできる。
実行時にどの命令スケジューリングが最適かを検出するには、実際のCPUを知る必要がある。
すべてのCPUモデルの表を持つこともできるが、実行中のCPUがその最適化を実装しているかをOSに問い合わせることもできる。
Linuxでは、CPUがその最適化を実装していると報告できるようにするためのパッチが必要だった。
https://www.phoronix.com/news/Intel-5.6-FSRM-Memmove
rep movsbが高速なので、SSE/AVX最適化実装を使う必要がないことを示しているにすぎない。Intel勧告 [1] に次のように書かれているのを見た。
Intelは、この問題を社内で発見したIntel社員に感謝すると述べており、またこの問題を報告したGoogle社員にも感謝している。
[1] https://www.intel.com/content/www/us/en/security-center/advi...
影響の説明があるIntel勧告も参考になる: https://www.intel.com/content/www/us/en/security-center/advi...
「一部のIntel(R)プロセッサにおいて、プロセッサ命令シーケンスが予期しない動作を引き起こし、認証済みユーザーがローカルアクセスを通じて権限昇格、情報漏えい、サービス拒否を引き起こせる可能性がある」
Paradox InteractiveのVictoria 3チームのKonrad Magnussonが、これとmimallocに関連する何かを見つけている: https://github.com/microsoft/mimalloc/issues/807
完全に関係しているかは分からないが、その可能性はある。