このページの目次

ライブパッチング

カバー範囲: kernel livepatch (KLP) → ftraceベース → 原子置換 → 状態一貫性モデル → リアルタイムカーネル カーネルバージョン: 4.0 ~ 6.x (メインライン), エンタープライズ版 (RHEL 7+)

概要

ライブパッチングにより、カーネルの再起動なしでカーネル関数を修正できます。これは重要なセキュリティ修正(CVE)や小さな論理バグの修正に適しています。中核的な原理は、実行中の関数のエントリポイントに ftrace トランポリンを設置し、新しい関数へジャンプさせることです。その後、すべてのプロセスのカーネルスタックを順にチェックし、古い関数内で実行されていないことを確認します。すべてが安全に退出した後に、古い関数は呼び出されなくなります。

実装原理

// kernel/livepatch/core.c + kernel/livepatch/patch.c
// ftraceをベースにしています:

// 1. ライブパッチの登録:
klp_enable_patch(patch)klp_patch_object(patch->objs)klp_patch_func(func)  // 置換対象の関数ごとに
ftrace_set_filter_ip(func->old_func, ...)  // ftraceフックを設定
        → 関数エントリが ftrace トランポリン → ライブパッチハンドラ → 新しい関数 に置換されます

// 2. 一貫性チェック (安全な移行):
klp_try_complete_transition()すべてのプロセスをトラバース (for_each_process_thread)klp_check_stack(task, func)  // カーネルスタックをチェック
      → 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