このページの目次

カーネルの堅牢化

対応範囲: KASLR → stack protector → KPTI → KASAN/KMSAN/UBSAN → FORTIFY_SOURCE → lockdown → seccomp → SLAB_FREELIST_RANDOM → init_on_free カーネルバージョン: 2.6 ~ 6.x

アドレス空間のランダム化: KASLR

起動時にカーネルコード/データ/モジュールのベースアドレスをランダム化:
  → ROP/JOP攻撃ではgadgetsのアドレスが必要 → ベースアドレスが不明 → 攻撃が困難

実装: arch/x86/boot/compressed/kaslr.c
  ブートローダーの段階でランダムなベースアドレスを選択 → 再配置されたカーネルを解凍

kptr_restrict: /proc/kallsymsからのカーネルアドレス漏洩を制限
  /proc/sys/kernel/kptr_restrict = 2 → 非rootユーザーからはすべて0として表示

Stack Protector

// CONFIG_STACKPROTECTOR: コンパイラが各関数のスタックフレームにcanaryを挿入
// gcc: -fstack-protector-strong
//   → 保護対象: ローカル配列がある関数や、アドレス演算を行う関数
// canaryが書き換えられると → スタックオーバーフロー → __stack_chk_fail() → panic

// kernel/stackleak.c (オプション): より徹底的なスタッククリア
//   各システムコールの返却前に使用済みスタック領域を消去
//   → スタック情報の漏洩防止(未初期化のローカル変数など)

KPTI: Meltdown対策

2018年のMeltdown脆弱性:
  CPUは予測実行中にページテーブルのU/S bitをチェックしない → ユーザーモードからカーネルメモリを読み取れる

KPTI (Kernel Page Table Isolation):
  各プロセスに2つのページテーブルを持つ:
    カーネルモード: 完全マッピング (user + kernel)
    ユーザーモード: 最小限 (user + trampoline)
  → ユーザーモードではカーネルメモリへの予測アクセスができない

パフォーマンスへの影響: ~5%~30% (システムコール集中型), PCIDにより一部緩和
現代のCPU (Cascade Lake以降, Zen2以降): ハードウェアで修正済み、KPTIは自動的に無効化

Sanitizers: 実行時エラー検出

// KASAN (Kernel Address Sanitizer):
//   検出: 境界外アクセス, use-after-free, double-free
//   シェードメモリに基づく (コンパイル時のインストルメンテーション)
//   オーバーヘッド: ~1.5-2倍の低速化, デバッグ用カーネルのみ

// KMSAN (Kernel Memory Sanitizer):
//   検出: 未初期化メモリへのアクセス
//   KASANよりも重い (~3倍), 開発用途のみ

// UBSAN (Undefined Behavior Sanitizer):
//   検出: 整数オーバーフロー, シフトの境界外, 空ポインタの逆参照
//   オーバーヘッドが低く、本番環境で有効化可能 (CONFIG_UBSAN_BOUNDS)

FORTIFY_SOURCE

// コンパイル時にmemcpy/strcpy/sprintfを置換:
//   バウンダリ情報がある場合 → チェック付き呼び出しを生成
//   コンパイル時に既知の境界外アクセス → コンパイルエラー
//   実行時の境界外アクセス → BUG() (エラーを返さない)
//
// ユーザー空間のFORTIFY_SOURCEと類似しているが、より多くの関数をカバー

Kernel Lockdown

UEFI Secure Bootが有効化されると:
  → kernel lockdownが自動的に有効化される (integrityモード)
  → 禁止される操作:
    - /dev/mem, /dev/kmem (メモリ読み書き)
    - ioportへのアクセス
    - kexec (署名されていないカーネルの読み込み)
    - BPFによるカーネルメモリへの書き込み
    - ACPIテーブルの上書き

/proc/sys/kernel/lockdown:
 none / integrity / confidentiality

seccomp

// prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)
// プロセスが呼び出せるシステムコールを制限 (不可逆)

// BPFフィルター:
//   システムコール番号と引数をチェック → ALLOW / DENY / KILL / TRAP
//   Chromium, Docker, systemdなどが使用

// SECCOMP_RET_USER_NOTIF (5.0以降):
//   判断をカーネル内で行わず、ユーザー空間の監視プロセスに通知
//   例: コンテナマネージャが特定のシステムコールの承認/拒否を行う

その他の堅牢化オプション

# 解放時にゼロクリア:
CONFIG_INIT_ON_FREE_DEFAULT_ON=y    # 解放されたslabオブジェクトをゼロクリア (UAFによる情報漏洩防止)

# slab freelistのランダム化:
CONFIG_SLAB_FREELIST_RANDOM=y      # slab freelistポインタをランダムにソート (ヒープエクスプロイト防止)

# ユーザーメモリコピーのハードニング:
CONFIG_HARDENED_USERCOPY=y         # usercopyのソース/ターゲットが有効なheap/slab領域内であることを検証

# スタックのランダム化 (既存, プロセス単位):
/proc/sys/kernel/randomize_va_space = 2  # ASLRを完全に有効化

参考

  • ソースコード⁠: security/lockdown/, kernel/seccomp.c, mm/kasan/, lib/ubsan.c
  • カーネルドキュメント⁠: Documentation/admin-guide/kernel-parameters.txt
  • LWN: "Kernel address space layout randomization", "The kernel lockdown patches"

キーワード: KASLR, stack protector, KPTI, KASAN, FORTIFY_SOURCE, lockdown, seccomp, init_on_free