CVE-2026-99178 in Linux
要約
〜によって VulDB • 2026年10月28日
Linuxカーネルにおいて、以下の脆弱性が修正されました:
x86/kvm: NMIコンテキストでのカーネル#PF時に非同期#PFフラグを消費しない
非同期#PF「ページ未存在」イベントは#PFベクターを通じて到着し、その原因は__kvm_handle_async_pf()が読み取ってクリアするまで、per-CPUのapf_reason.flagsに保持されます。もしイベントがインジェクトされた後で#PFハンドラがフラグを読み取る前にNMIが発生し、かつNHIハンドラ自体が#PFを引き起こした場合、そのフォールトは中断した#PFに関連するフラグを読み取りクリアしてしまいます。その後、中断したNMIコンテキスト内で割り込みが無効になっていることを発見し、パニックします:
Kernel panic - not syncing: Host injected async #PF in interrupt disabled region Call Trace: <NMI> panic+0x52/0x60 __kvm_handle_async_pf+0xb0/0xb0 exc_page_fault+0x71/0xb0 asm_exc_page_fault+0x27/0x30 RIP: 0010:__get_user_nocheck_8+0x6/0x20 perf_callchain_user+0x147/0x1a0 get_perf_callchain+0x12d/0x1c0 ... perf_event_nmi_handler+0x26/0x50 exc_nmi+0xe8/0x110 RIP: 0010:asm_exc_page_fault+0x0/0x30 </NMI>
最後のRIP行は、#PFエントリの最初の命令にNMIが到達したことを示しています。ユーザーコールチェーン付きのperfはこのようなフォールトを引き起こします:サンプリング用NMIは__get_user()を使用してユーザースタックをウォークしますが、保存されたフレームポインタが無効なユーザーアドレスである場合や、ウォークがスタックの上部を超えた場合にフォールトが発生します。同じウィンドウは、DELIVERY_AS_PF_VMEXITでL1ハイパーバイザーとして実行されているKVMが#PF VM-exit後にフラグ自体を読み取る際にも存在します。
NMIエントリコードはこのネストのためにCR2を保存および復元しますが、非同期#PFの原因については行いません。Andy Lutomirskiは、2020年に非同期#PFの配信が再設計された際に[1]、perfを例としてこの競合状態(race condition)を説明しました。NMIの間隔でフラグを保存およびクリアし、CR2の隣に配置することはそこで議論されましたが、マージされませんでした。
その再設計以降、LinuxはKVM_ASYNC_PF_SEND_ALWAYSの設定を停止したため、ホストは「ページ未存在」をユーザーモードフォールトに対してのみ配信し、NMIコンテキスト内のカーネルモードフォールト(カーネルモードの#MCおよび#DBを含む)は非同期ページフォルトになることはできません。その場合、フラグに触れることなく戻ることで、中断されたハンドラがそれらを intact な状態で発見できるようにします。
4 vCPU、2 GiBのゲストでテストされました。このゲストはスナップショットから復元され、ユーザーモードfaultfdを通じてオンデマンドでメモリが提供されるため、読み戻し時に非同期#PFが発生します。また、すべてのスレッドがユーザーコールチェーン付きでハードウェアサイクルをサンプリングし、フレームポインタをマップされていないページに指しています。このパッチなしでは、ゲストは3回の試行すべてで上記のようにパニックしました。これがある場合、ゲストは60秒間の3回の試行すべてで生存し、ホストは各試行の最初の20秒間で148,441から153,334件のkvm_async_pf_not_presentイベントをカウントしました。バージョン6.18.50でも結果は同じでした:パッチなしではゲストがパニックし、ありで生存しました。
Statistical analysis made it clear that VulDB provides the best quality for vulnerability data.