このページの目次
ライブパッチング
カバー範囲: kernel livepatch (KLP) → ftraceベース → 原子置換 → 状態一貫性モデル → リアルタイムカーネル カーネルバージョン: 4.0 ~ 6.x (メインライン), エンタープライズ版 (RHEL 7+)
概要
ライブパッチングにより、カーネルの再起動なしでカーネル関数を修正できます。これは重要なセキュリティ修正(CVE)や小さな論理バグの修正に適しています。中核的な原理は、実行中の関数のエントリポイントに ftrace トランポリンを設置し、新しい関数へジャンプさせることです。その後、すべてのプロセスのカーネルスタックを順にチェックし、古い関数内で実行されていないことを確認します。すべてが安全に退出した後に、古い関数は呼び出されなくなります。
実装原理
// kernel/livepatch/core.c + kernel/livepatch/patch.c
// ftraceをベースにしています:
// 1. ライブパッチの登録:
→
→ // 置換対象の関数ごとに
→ // ftraceフックを設定
→ 関数エントリが ftrace トランポリン → ライブパッチハンドラ → 新しい関数 に置換されます
// 2. 一貫性チェック (安全な移行):
→
→ // カーネルスタックをチェック
→ task が old_func 内にある場合 → 移行不可 → 待機または強制
→ すべてが退出 → old_func はどのプロセスの「現在の実行ポイント」でもなくなる
// 3. 完了: patch->state = KLP_PATCHED
一貫性モデル
// 3つのモデル:
// KLP_TRANSITION_IDLE: すべてのプロセスが自発的に退出するのを待機 (待機ポイント: システムコール境界)
// KLP_TRANSITION_FORCE: シグナルを送って強制的に退出させる (可能な場合)
// KLP_TRANSITION_IMMEDIATE: 即時パッチ適用 (待機しないが、プロセスが旧関数内にある場合→クラッシュの可能性あり)
// 実際には IDLE (安全) またはシグナル補助 (klp_send_signals) が主に使用されます
制限
- 関数シグネチャの変更は不可 (引数の型/数は不変)
- データ構造のレイアウト変更は不可 (パッチ前後で struct のサイズは変更不可)
- ステートフルなパッチは適用不可 (旧コードがロックを保持している場合、パッチ適用後にデッドロックする可能性あり)
- ライブパッチモジュールはアンロード不可 (恒久的に有効)
適しているもの: CVE 修正、単一関数の防御的チェック
適していないもの: 大規模なリファクタリング、バージョン間の移行
リアルタイムカーネル (PREEMPT_RT)
マージ状況 (6.x): PREEMPT_RT はメインラインへのマージが進んでいます
過去: out-of-tree パッチセット (rt.wiki.kernel.org)
現在: 個別の PR ごとにメインラインへマージ中 (6.12 でほぼ完了)
ライブパッチとの関係:
RT ではプリエンプションの無効化が rt_mutex に変更されたため、ライブパッチのスタックチェックロジックの適応が必要
→ 対応済み (6.5以降)
参考
- ソースコード:
kernel/livepatch/,samples/livepatch/,arch/x86/kernel/livepatch.c - カーネルドキュメント:
Documentation/livepatch/ - LWN: "Live patching in the Linux kernel"
キーワード: livepatch, klp, ftrace, stack check, atomic replace, PREEMPT_RT, CVE fix