
2026/10/16 23:44
ビッグフィッシュ:OpenBSD の 37 年ぶりのカーネルバグ悪用
RSS: https://news.ycombinator.com/rss
要約▶
Japanese 翻訳:
OpenBSD に対する最近のローカル権限昇格exploit は、攻撃者が強化された防衛を迂回して root アクセスを得ることができる重要なセキュリティ上の隙間を示しています。主要なメカニズムは、共有メモリの処理における古くからの整数オーバーフローバグに依存しており、37年前のコードが小さな 16 ビットのカウンターを使用し、反復的なプロセスフォーク時にオーバーフローする際に発生します。これは、解放されたメモリをシステムが正しく管理しない「使用後の解放」(use-after-free)攻撃を可能にする危険なランコンディション(race condition)を生み出します。このオーバーフローを、特定のネットワーク設定によってトリガーされる境界外書き込み脆弱性と組み合わせることで、機密データを漏洩させることなく内部カーネルポインタを破損させることができます。同様の問題については以前のエラタで部分的に対処されてはいますが、持続的なレジリエンスのために新たな防衛策が必要です。これらの脅威に備えるために、開発者は安全なunlink プロトコルの実装とブート時のメモリ配分ランダム化を行い、予測可能な攻撃ターゲットを不可能にしなければなりません。さらに、Linux 系システム上で OpenBSD を実行している際の境界外エラーやメモリエラーに対する堅牢な保護層を提供するためには、配分境界サンタイザーなど、コンパイラの安全性機能を有効にすることも重要です。
本文
OpenBSD 向けローカル権限昇格攻撃の実装と防御策について
現状と背景
Calif は攻撃に関する研究を発表してきた一方で、以下の防御側の実績は十分に注目されていません。
- オープンソースプロジェクトへの是正支援
- パッチ生成技術の向上
- 暗号技術の強化
- クライアント向けの内部エンジニアリング
本年初めに OpenBSD に向けた脆弱性レポートをいくつか発表し、修正パッチを提供しました。特に以下の問題が解決されました(Errata 026 および 018)。
- 共有メモリアタッチメントのカウント値オーバーフロー
- オリジナルの BSD ソースにおいて、このカウントは「符号付き 16 ビット整数」として定義されていました。
- プロセスを反復フォークさせることで、最大値(32,767)を超え負の値にラップオーバーします。
- この整数オーバーフローが競合条件を通じて「使用済みメモリへのアクセス(use-after-free)」を引き起こす可能性があります。
- カーネル内の別の境界外書き込みと組み合わせることで、**ローカル権限昇格(ルートへ)**が可能となります。
攻撃コードの実装手順
情報漏洩系の脆弱性を利用せず、KARL / SMAP / SMEP が有効化された OpenBSD システム上で、以下のステップを踏むことでローカル権限でのルートアクセスに成功しました。
-
共有メモリの準備と巻き戻し
- SysV 共有メモリセグメントを 127 分割マップし、
でアンマップします。munmap() - 共有メモリアタッチカウントを -32,643 に巻き戻すために、259 のプロセスをフォークします。
- SysV 共有メモリセグメントを 127 分割マップし、
-
メモリ配分の制御と整列(Grooming)
などからのメトリクスを使ってメモリ配分を追跡します。sysctl(KERN_MALLOCSTATS)- ヒープの整列を行い、新規ページが割り当てられるタイミングを判断します。
-
競合条件の獲得と構造体のアタッチ
を用いて競合条件に勝ちます。IPC_RMID- ヘルパープロセスでサイズ認識エラーのある新たな共有メモリセグメントをアタッチします。
-
非標準的なソケット配分の確保
- IP ソケット配分を整列させ、
を2(デフォルト値ではない)に設定します。IP_MULTICAST_TTL - これにより、永続的な 16 バイト構造体
を割り当てます。struct ip_moptions - 構造体の最後にある 2 つの 16 ビットカウントをパッキングします:
// imo + 12 = imo_num_memberships | imo_max_memberships << 16
- IP ソケット配分を整列させ、
-
境界外書き込み(Out-of-Bounds Write)のトリガー
- 条件付きで -1 バイト先の境界外書き込みを発生させます。
- 「所属メンバー数」と「最大メンバー数」という二つのフィールドを上書きします。
-
カーネルポインタの復元とコード実行
- ソケットを
し、グループメンバーを回遊させて原子減算を実行します。close() - PTE の自己参照マップを 2 度修正し、マッピングを「ユーザーアクセス可能」から「サブリノ(supervisor)アクセス可能」に切り替えます。
- 予測可能なカーネルポインタを上書きすることで、カーネルコードの実行を達成します。
- ソケットを
-
クリーンアップとシェル取得
- 共有メモリの会計処理をクリーンアップします。
- 上書きされたカーネルポインタを復元して、ルートシェルを取得します。
攻撃の核心:Write-What-Where
この脆弱性は、「どこに何を書き込むか」を制御する プリミティブ(write-what-where) を通じてコード実行を実現しました。
- 書き込みの原因:
TAILQ_REMOVE - 書き込む対象(What): ユーザーランドのメモリマッピング(サマリノモードアクセス可能化により SMAP/SMEP を回避)
- 書き込む場所(Where): 予測可能なカーネルポインタの位置
攻撃緩和策(Exploit Mitigation)
OpenBSD の KARL は関数およびデータアドレスのランダム化を実現していますが、カーネルメモリアロケーターは依然として**決定論的(deterministic)**です。
- 起動時のアロケーターとベストフィットアロケーターの双方で、ベースアドレスのランダム化が欠落しています。
- その結果、早期起動時の配分は常に予測可能な位置に収まり、関数ポインタを含んだ構造体が攻撃対象となります。
以下は、これらの経路を再び利用される可能性を排除または低減するためのアプローチです。
1. 安全なアンリンク(Safe-unlinking)
アンリンクメモリ書き込みを行う前に、二重リンクリストの不変条件を確認します。
- 不変条件違反時の対応:
- ユーザーモード:
を呼び出すabort() - カーネルモード:
を呼び出すpanic() - これによりメモリ腐敗を防ぎます。
- ユーザーモード:
- 実装例: FreeBSD および NetBSD の
は既にこれを採用しています。sys/queue.h
2. 自己参照 PTE マップ配分のランダム化
標的となる原子減算の位置が存在しないように、自己参照 PTE マップ配分のアドレスをランダム化します。
- 実装方法:
- 起動時にランダムバイト(
)を使用。.openbsd.randomdata
を選択して再帰エントリを設置(例:PML4 スロット
)。320 + (random_byte & 127)
の定義をランタイム表現にする。PTE_BASE
- 起動時にランダムバイト(
- 効果:
- ベースアドレス生成例:
〜0xffffa00000000000
(512 GiB インターバル)。0xffffdf8000000000
- ベースアドレス生成例:
- 代替案: ランダム化が不適切な場合、PTE を読み取り専用としてマークしたり、変更時に
を設定する。CR0.WP
3. カーネルアロケーターの非決定論的化
起動時と実行時の両方で配分の予測可能性を破壊します。
- ベースアドレスのランダム化:
- コスト無料であり、生成するギャップも後に利用可能です。
- 実行時のランダム化:
- 配分順序をランダム化し、さらに詳細なアロケーターの変更でオーバーヘッドを軽減します。
- 効果: ソフトウェア脆弱性やハードウェア脆弱性の有無にかかわらず、予測可能なポインタ位置を破壊できます。
4. コンパイラ機能による緩和
既存および将来のコンパイラ機能を活用して全体として脆弱性を緩和します。
Array Bounds Sanitizer(配分境界サニタイザー)
- 未定義振る舞い(Undefined Behaviour)サニタイザーの一部。
- 目的: 境界外固定サイズアレイアクセスを排除する。
- 実績: Calif は FreeBSD にリリースビルドで有効化を提案しており、同サニタイザーにより 21 の問題を検出しました(そのうちいくつかはローカル権限昇格へのセキュリティ影響あり)。
Alloc Tokens(アロケーショントークン)
- ヒープ系問題の緩和に役立つ forthcoming コンパイラ機能。
- 目的: ポインタを含むアロケーションと、ポインタを持たないアロケーションを分離する。
- 効果:
- ポインタへのアクセスを防ぎ、ポインタを持たないアロケーションからのオーバーフロー利用を困難にする。
- Use-after-Free などの脆弱性クラスにおいて、代替メモリ割り当てを行うことを不可能にする。
結論と展望
OpenBSD はこれまで、ソースコード監査、不安全 API の置換、高度なパスワードハッシング、暗号技術、権限分離、サンドボックス化、ASLR と W^X による堅牢化を通じて基準を設けてきました。
防御側を能動的に強化し、新しい緩和策を適応させることで、以下の効果を得られます。
- 攻撃プリミティブ全体の体系的な無効化。
- 攻撃者のコスト増大(追加の時間投入、必要な脆弱性の増加、代替経路の探索など)。
AI 支援の脆弱性情報発見の時代において、脆弱性クラス全体への対策と攻撃複雑性の増大を組み合わせることは、より重要な戦略となります。