
2026/08/11 1:03
非常に長い割り込みを利用したシステム管理モードの侵害
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
x86 CPU のシステム管理モード(SMM)保護が重大なセキュリティ脆弱性により破られ、遠隔攻撃者が以前から不活性化していた 100 を超える SMM TOCTOU 脆弱性を悪用できるようになりました。これら従来の脆弱性は物理アクセスか DMA 機能付き周辺装置が必要でしたが、今回の脆弱性はマシン指令の実行時間が過度に長すぎることを利用しており、Zen 3 Ryzen 7 5800H で実証された概念検証では、MMIO アドレス
0xfcc68860 から幅広な XMM ローディングが行われ、実行が約 40 億サイクル(~1 秒)停止しました。これは SMM の標準的な 1 秒同期タイムアウトを超えています。通常動作下では、SMM セキュリティはすべてのプロセッサコアがこのウィンドウ内で同期することを前提としています。 stalled 指令により他のコアが SMM に入ることを防ぎ、システム管理中断(SMI)による非同期化攻撃が可能となります。この問題への修正としてファームウェアアップデートでタイムアウトを単純に延長するアプローチは多くの場合実用的ではありません。マルチコアプラットフォームではパフォーマンス劣化やシステムハングを引き起こす可能性があるためです。その結果、ユーザーは二つの困難な選択肢に直面します:不活性化していた SMM バグの遠隔悪用を受け入れるか、または重要なタイミングパラメータを調整して不安定さを引き受けるかのどちらかです。この研究は Christopher Domas (@xoreaxeaxeax) によって行われ、彼は -r xmm|ymm|zmm および -a <phys-addr> など flags を備えたツール smiiiiiiiiiiiiiiiiiiii を提供し、異なるレジスタ幅と MMIO アドレスに合わせた悪用のための設定を可能にしました。脆弱性を他のプラットフォームへ移植するには、各プラットフォーム固有の SMM レンデブーゼス タイムアウトを超えるために長い指令を調整する必要があります(例えば XMM から YMM または ZMM への読み出し拡大など)。究極的には、これは SMM が持つ孤立した実行という保証が、単一の極めて長いマシン指令によって崩壊することを示しています。本文
SMM(システム管理モード)への攻撃:超長時間割り込み命令を利用した手法
概要
事実、隠れて動作しているすべての x86 プロセッサのバックグラウンドで実行される安全かつ**超特権レベルの実行環境である SMM(System Management Mode)は、単に「極めて長く実行されるマシン命令」**だけで破壊できてしまう。
SMM の仕様では、コア全体が同時に SMM 内にあるか外にあるかのいずれかにある必要がある。この前提が欠ければセキュリティモデルは成立しない——つまり、スレッドの一つが SMM を進入すると、他のもろもろなスレッドもそれに追随することになる。これを破るには、「SMM に加入すべきである」ということに気づいてさえいないほど忙殺されている者がいるだけが必要だ。
作動原理
この攻撃は、以下の手順でコア間のタイミング(Rendezvous)を無視させることで機能する。
- コア 0が非常に長い命令を開始する。
- コア 1が「コア 0 に SMM への参加を招待する」処理を行う。
- コア 1が SMM を進入する。
- コア 1が「コア 0 の到着」を待機する(非常に長い時間)。
コア 0 - 非常に長い命令を開始 | v コア 1 - コア 0 に SMM への参加を招待する | v コア 1 - SMM を進入する | v コア 1 - コア 0 の到着を待つ(待機が繰り返される) | [以下、極めて長い時間経過] | v コア 1 - コア 0 の到着を諦める | v コア 1 - SMM 内で秘密の操作を行う | v コア 1 - SMM を退出する | v コア 0 - SMM に参加する(遅れて)
この時点で、コア 1 は SMM から退出し、コア 0 は SMM の内に留まっているため、コア 1 が攻撃できるようになる。しかし注意点がある:これが成り立つためには、かつて想定される以上に極めて長い命令が必要となる。現代のプロセッサの大多数のマシン命令は高速に処理される(例:
add 命令はわずか 1 サイクル)。
コア 1 にコア 0 の到着を諦めさせるには、コア 0 で以下の時間かかる命令が必要となる:
- 約 40 億サイクル(壁時計時間で1 秒以上)
1 秒タイマアウトの仕組み
x86 ファームウェアは、CPU コアが SMM を進入した際、以下のコードを実行する。
for (Timer = StartSyncTimer (); !IsSyncTimerTimeout (Timer, mTimeoutTicker) && SyncNeeded; ) { mSmmMpSyncData->AllApArrivedWithException = AllCpusInSmmExceptBlockedDisabled (); if (mSmmMpSyncData->AllApArrivedWithException) { break; } CpuPause (); }
このコードは、以下のいずれかが先で待機を中断する。
- すべてのコアが SMM を進入する場合
- 最大1 秒(mTimeoutTicker)経過する場合
別のコアが SMM の外で実行を続ける一方で、あるコアだけが SMM コードを実行させるためには、SMM の外にあるコアがその間の1 秒間無割り込みで実行し続けねばならない。
- **SMI(System Management Interrupt)**は命令境界で発生するため、2 つの命令の間には空隙が必要である。
- この空隙があることで、保留中の SMI がコアを SMM に引き込む。
- したがって、待避時間は単一の命令で行わねばならず、1 秒間の rendezvous(相対面会)を凌ぐ無割り込みなオペレーションでなければならない。
実証コンセプト(Proof-of-Concept)
禁止された 1 秒長の命令に到達する手法はいくつかあり、具体的なアプローチはプラットフォームによって異なるだろう。しかし大まかには、以下の手順で行う:
- 高遅延を持つ MMIO アドレスを見つける。
- CPU がそこから可能な限りゆっくり読み取るように誘導する。
- 非公開の領域から極端に低速で読取られるものを悪用する。
- ISA が許す最も広いロード命令を使用して単一の命令で可能な限り多くのバイトをその領域を横断させる。
- 他のコアが同じバスを競合させることでさらに遅延を引き起こす。
これにより、**「読み取り=命令」**となり、CPU はそれをほぼ 1 秒間保持し続けることになる。
提供されている実証コンセプトは、Zen 3 Ryzen 7 5800H 向けにチューニングされており、
0xfcc68860 のスロウな MMIO から広範な xmm ロードを実行することで、全コアの rendezvous を破るのに十分な長時間のスロットリングが発生する。
攻撃用のアセンブリ命令
mov $0xfcc68860, %rsi ; ターゲットの MMIO アドレス vmovdqu (%rsi), %xmm0 ; 極めて長いロード命令
犠牲者コア(スピン待ち)
約 1 秒間かかる読み込みループ上でスパインし、SMI に応答できない状態を維持する。
/* 犠牲者コア:約 1 秒間かかる読み込みループ上でスパインし、SMI に応答できない */ for (;;) asm volatile ("vmovdqu (%0), %%xmm0" :: "r"(mmio) : "xmm0");
攻撃側コア(SMI を発火)
別のコアがパーコアの SMI カウンタを起動し、SMI の嵐を発火させる。
#define MSR_PERF_CTL0 0xc0010200 /* AMD コアパフォーマンスイベント選択 MSR */ #define MSR_PERF_CTR0 0xc0010201 /* そのペア付きの 48 ビットカウンタ */ for (int cpu = 0; cpu < ACTIVE_CPUS; cpu++) { msr_write(cpu, MSR_PERF_CTL0, 0x43002b); /* EN | OS | USR | イベント番号 0x2b */ msr_write(cpu, MSR_PERF_CTR0, 0); /* カウンタ値をゼロ化する */ } // SMI を発火させる(ポート 0xb2 を蹴る) asm volatile ("outb %%al, $0xb2" :: "a"(0)); /* ポート 0xb2 を蹴る → #SMI */ // カウントを読み返し、同期が破られたか確認 /* ...SMI の嵐を発火させ、その後各コアのカウントを再取得... */ uint64_t delta = smi_max - smi_min; if (delta) puts("!!! コアが SMM の外で実行し続けた");
結果の確認:
- カウントが一致しない場合、それはあるコアが他のコアが引き込まれている間に SMM の外で実行を続け、他のコアが行った SMI を取り逃したことを意味する。
- これにより、SMM の保証——その動作中は他は何も走らないという単純な仮定——は崩れ去る。
攻撃の実施と影響
SMM のセキュリティは、シンプルな仮定に依存している:
SMM が動作している間、他の何ものも動作しない。
これにはSMM TOCTOU(Time-of-Check-to-Time-of-Use)の CVE が 100 件以上存在する。
- SMM ハンドラは共有メモリ内の値をチェックし、その後それを使用する。
- 攻撃に必要なのは、チェックと使用の間にその値を書き換えることだけであり、それで SMM の内部に入る。
しかし、これらの問題は以下の理由により実在では不活性化されており、ほとんどパッチが当てられていない:
- SMM が実行している間に共有メモリの書き換えを行うものが存在しない(何かが必要であり)。
- SMM の rendezvous のため、SMM の外のコアは攻撃を起動できないからである。
- 唯一の侵入経路:DMA 機能を有する周辺デバイスが CPU に背後から書き込むことであり、物理的なアクセスや悪意のあるデバイスが必要とされたため、このクラス全体がハードウェア問題として帳消しとなっていた。
SMI の非同期化は、プラットフォームを安全に保っていた前提条件を取り除く:
- SMM が実行されている間に、外部のコアが動作できるようになる。
- 物理的アクセスやハードウェアの変更なしで SMM が実行され続けることができる。
- 不活性していた CVE がソフトウェアから利用可能になる。
緩和策
おそらく緩和策は存在せず、それが従来の SMM 問題とは比較してやや興味深い要因となっている。
以下の対策を検討するが、いずれもトレードオフがある:
- タイマートを維持すれば、rendezvous は容易に破壊される。
- タイマートを取り除くと、正当にスタックしたコアが最初の SMI でプラットフォームを停止させてしまう。
- タイマートを増やすと、各回の SMM 進入時にすべてのコアをクワイエンスせざるを得ないマルチコアプラットフォームでパフォーマンスが低下する。
それまで、推奨される回避策としては**「長時間の命令を実行しないこと」**である。最適な次の道筋は何か、あるいはそもそも進路があるのか明らかなではない。
他のプラットフォームへの移植
実証コンセプトにおけるデフォルトの
vmovdqu を 0xfcc68860 に設定することは、このマシン(Zen 3 Ryzen 7 5800H)にとってのスロウスポットであり、おそらく他の場所では通用しない。
自分のマシンで rendezvous を破るためには、スロットリング時間が SMM のタイマートを超え那样的に調整された長時間の命令を見つける必要がある。以下のようなヒントがある:
- MMIO に焦点を当てる
でプラットフォームのスロウな MMIO 領域を見つける。mmiotic
- 読み取りを広げる
→-r xmm
→ymm
とステップアップさせ、スロットリングが rendezvous タイマートを越えるまで続ける。zmm
- 命令を交換する
- 単一の MMIO 読み取りだけでは遅すぎない場合は、別の病的に長い命令が必要となる;
でそれらを見つける方法を示している。asm-hall-of-shame
- 単一の MMIO 読み取りだけでは遅すぎない場合は、別の病的に長い命令が必要となる;
構築
make # smiiiiiiiiiiiiiiii をビルドします
使用方法
デフォルト設定は一台のマシン(Zen 3 Ryzen 7 5800H)向けにチューニングされています。他のマシンでは、長時間の命令を再調整するまで発散は見られません(参照:プラットフォームへの移植)。
ツールを実行し、各コアの SMI カウンタを発火させて、発散を観察します:
sudo ./smiiiiiiiiiiiiiiii # デフォルト:0xfcc68860 での xmm ロード (-r xmm)
フラグメント一覧
| フラグ | デフォルト | 説明 |
|---|---|---|
| | タイムされた MMIO 読み取りのためのベクトルレジスタ幅(16/32/64 バイト)。SMI カウントのデルタが観察されない場合、ツールは次のサイズにステップアップすることを推奨します。 |
| | MMIO タイミングループのためのターゲット物理アドレス(16 進数 または十進数)。 |
, | — | 使用方法を表示し、終了する。 |
著者
smiiiiiiiiiiiiiiii は Christopher Domas (@xoreaxeaxeax) による研究成果です。