
2026/07/11 5:43
Linux のすべてのディストリビューションに 15 年間存在しているスタック系 UAF「GhostLock」
RSS: https://news.ycombinator.com/rss
要約▶
Japanese 翻訳:
GhostLock(CVE-2026-43499)は、2011 年から 2026 年 4 月までの主要なすべての Linux ディストリビューションに影響を与える、重大な長年のスタック使い捨て後の解放(stack-use-after-free)脆弱性である。これは
remove_waiter() 関数内の論理的誤りに起因しており、攻撃者が再割当された内核スタック上で偽の構造体を作成することでシステムを劫奪し、セキュアなコンテナから脱出することを可能にする。VEGA の研究者らは、この理論的な欠陥を KERNELCTF コンプーティションにおいて安定した成功確率 97% の権限昇格エクスプロイトに変換することに成功し、その功績として Google から 92,337 ドルもの賞金を受賞した。攻撃メカニズムは、依存関係のサイクルを構築して -EDEADLK ロールバックを引き起こし、制御フローを劫奪するための制御されたポインタ記述を可能にするものである。システム整合性へのこの深刻なリスクに対処するため、Google は 2026 年 4 月に遡及される公式修正(コミット 3bfdc63936dd)を発表し、remove_waiter() 内の論理誤りを是正した。組織には、被曝に即座にアップグレードするか、あるいはエクスプロイトに必要な特定の攻撃表面を破壊する RANDOMIZE_KSTACK_OFFSET セキュリティ機能を有効化するよう促される。本文
研究報告:IonStack Part II ~ GhostLock ~ 15 年間もすべての Linux ディストリビューションに存在する「スタック系 UAF」Vulnerability (CVE-2026-43499)
概要と発見の背景
GhostLock (CVE-2026-43499) は、VEGA が発見した Linux カーネルの重大な脆弱性です。
- 発見期間: 2011 年以降(Linux 2.6.39)、2026 年 4 月に修正されるまで約15 年間存在しました。
- 影響範囲: すべての主要な Linux ディストリビューションおよびバージョン(v2.6.39-rc1 〜 v7.1-rc1)。
- 発症条件: 特別なカーネル設定や権限、隔離環境が不要です。
のみ必要。CONFIG_FUTEX_PI=y - 成功率: 97% の確率で成功する権限昇降(Privilege Escalation)およびコンテナ脱出手段に変換可能。
- 賞金: Google kernelCTF において、$92,337 ドルが支払われました。
脆弱性を利用した攻撃者の能力
非特権のローカル攻撃者は以下の操作が可能になります:
- 通常のスレッド系システムコールのみを用いて、カーネルスタック領域への「ダングリング(未使用だが存在する)カーネルポインタ」を取得。
- ほぼ任意のアドレスへのポインタを書き込む。
- 関数テーブル(Function Table)をハイジャックして制御フローを乗っ取り、最終的に root アクセス を取得。
脆弱性の技術的詳細:概要と根本原因
導入経緯
- 脆弱性はコミット
("rtmutex: Simplify PI algorithm...") の8161239a8bcc
改修に伴い導入されました。rtmutex - 修正コミット:
("rtmutex: Use waiter::task instead of current in remove_waiter()") によって 2026 年 4 月に修正済み。3bfdc63936dd
根本原因:ライフサイクル管理の誤り
kernel/locking/rtmutex.c の remove_waiter() 関数が、呼び出し元のスレッド(current)と実際の待ち行列オブジェクト(ウェイター)が一致しない状況で誤った挙動を示します。
- 設計意図: 関数は当初、「スレッド自身がブロックされ、自分自身をクリーンアップする」シナリオ用として書かれていました。
// 誤った実装の例(簡略化) raw_spin_lock(¤t->pi_lock); // "現在のスレッド" のロック rt_mutex_dequeue(lock, waiter); current->pi_blocked_on = NULL; // "現在のスレッド" を対象にクリア - 現実の挙動:
経由で、別のスリープ中のスレッド(ウェイター)のためにクリーンアップを行う場合があります。rt_mutex_start_proxy_lock()- この時、
は実際のウェイターではなく、再キューイングを要求したスレッドです。current - しかしコードは誤って
をクリアします。current->pi_blocked_on
- この時、
ダングリングポインタの生成(Use-After-Free)
ウェイタータスクは睡眠状態にあるため、カーネルスタック上にオブジェクトが存在しますが、そのポインタが「解放」されます:
- プロキシーパス:
で別の futex へ移動を試みます。FUTEX_CMP_REQUEUE_PI - デッドロック検出: チェーンウォークにより
が返されロールバック処理が実行されます。-EDEADLK - 誤ったクリア: ロールバック処理で
が NULL 化されますが、実際のウェイター(別のスレッド)のポインタはスタック上で存在し続けます。current->pi_blocked_on - UAF 発動: ユーザー空間に戻る瞬間にスタックが解放され、ダングリングなカーネルポインタがユーザー空間に残ります。これを通じて任意のアドレスへの書き込みが可能になります。
エクスプロイトの構成要素
エクスプロイトは以下のステップで構成されています:
- Prefetch: カーネルイメージのシフト量(Slide)と物理マップベース(Physmap Base)をリーク。
- GhostLock: ダングリングな
を残す。rt_mutex_waiter - Reclaim (スタック系-UAF 再回収):
を用い、解放されたフレームの上に偽のPR_SET_MM_MAP
を作成。rt_mutex_waiter - Arbitrary Address Writer: Rtmutex rb-tree の erase 機能を悪用し、関数テーブル(例:
)を上書き。inet6_protos[IPPROTO_UDP] - Control Flow Hijack (CFH): CPU エントリ領域 (CEA) を活用し、ループバックパケットを送信して制御フローをハイジャック。
- DirtyMode:
のモードビットを反転させ、以降の処理をユーザー空間で完結させる。core_pattern
アンドロイドへの適用可能性
本稿は汎用 x86 Linux システムを対象としていますが、アンドロイドでも同様の手法が可能です:
- スタックフレームの再回収(
など)。PR_SET_MM_MAP - ASLR と CFI の両方を回避する手法の適用。
技術的アプローチの詳細
1. ASLR リーク (Prefetch)
- 特定のアドレスへのプレフェッチは、ページテーブルのマッピング状態によって異なるサイクル数を実行します。
- これを計測することで、非特権プロセスがカーネルイメージのベースアドレス(KASLR)を復元できます。
- Linux はデフォルトでランダム化を強く行わないため、理論上 100% の確度で復元可能。
2. CEA スプレイとランダム化回避
- CEA (CPU Entry Area): 例外処理時に使用される CPU 固有の領域(物理アドレスは固定)。
- プログラムがソフトウェア例外を引き起こすと、CEA のスタックに
が保存されます。pt_regs - 物理オフセットは固定されているため、ダイレクトマップアライアスを容易に計算可能です:
cea_direct = physmap_base + CPU1_CEA_BASE - これにより、約 120 バイトの制御可能なメモリ領域を既知のアドレスで利用できます。
3. スタック再利用:PR_SET_MM_MAP
を呼び出すことで、解放されたウェイターのスタック上にあるフレームを再利用します。prctl(PR_SET_MM, PR_SET_MM_MAP, ...)- バッファー(
)が古いオブジェクトの上に自然に重なるため、名前空間を必要とせず制御可能な領域を獲得できます。user_auxv// 偽造されたウェイターの構成例 tree: rb ノード(消去してポインタ操作) task: &init_task lock: target - 8 (書き込みのターゲット) wake_state: 0
4. 任意アドレスへの書き込み
- 手法:
(rb-tree の erase)を利用。子ノードを持つルートを検去すると、その子をルートスロットに書き込む処理を行います。rt_mutex_dequeue() - 制約:
- ターゲット前:ロックされていない状態である必要がある。
- 後続データ:未マップな値がないことが必須(マシンのパニックを防ぐため)。
- ターゲット例:
inet6_protos[IPPROTO_UDP]// ライアウトの要約 target - 8 -> raw_spinlock_t wait_lock (ロックされていない) target -> waiters.rb_root.rb_node (ここに書き込み) target + 8 -> waiters.rb_leftmost target + 16 -> owner
5. Control Flow Hijack (CFH)
- 上書きされたハンドラー(
)をトリガーすることで、ループバック IPv6 UDP パケットを送信させます。inet6_protocol.handler - これにより PC(プログラムカウンタ)制御を取得し、ROP(Return Oriented Programming)チェーンを実行します。
6. DirtyMode と core_pattern
- 目的: 1 回の書き込みで
のモードビットを反転させ、以後の権限昇降処理をユーザー空間で行えるようにする。core_pattern - ターゲット:
(書き込み可能なカーネルデータ)。coredump_sysctls[1].mode
まとめと提言
- 脆弱性の深刻度: 特別な環境設定が不要なため、97% の確率で攻撃に成功し、root 権限取得が可能。
- 影響対象: Linux v2.6.39 以降のすべてのバージョン(最新 LTS バージョン含む)は影響を受けます。
- 対策:
- アップグレード: 最新版の LTS (Long Term Support) バージョンへのアップグレードを検討することを強く推奨します。
- パッチ適用: VEGA が提出したパッチを適用してください。
パッチと緩和策
修正されたコード(
kernel/locking/rtmutex.c)では、以下の点が改善されました:
関数内で、常に実際のウェイタータスク(remove_waiter()
)のロックを使用するように変更されています。waiter->task- ポインタクリアとチェーンウォーク処理を正しく実装したスレッドを対象に行うように修正されました。
追加の緩和策
- RANDOMIZE_KSTACK_OFFSET: これをオンにすると、スタック再利用ステップは失敗するため、攻撃パスが阻断されます(デフォルトではオフ)。
- STATIC_USERMODE_HELPER: 特定の DirtyMode パスを閉じます。
開発者へのお知らせ
本研究は VEGA の「CyberMeowfia」プロジェクトの一環として公開されました。完全なエクスプロイトコードや詳細な分析については、同プロジェクトのリポジトリをご参照ください。