Linux Kernel Hardening and Security
Linux カーネルハードニング & セキュリティ機能: 包括的ガイド
ドキュメントバージョン: 1.0
最終更新日: 2026-04-10
対象読者: システム管理者、セキュリティエンジニア、SREチーム、カーネル開発者
対象カーネルバージョン: Linux 5.x 〜 6.x系
目次
- はじめに
- KASLR — カーネルアドレス空間配置のランダム化
- KPTI — カーネルページテーブル分離(Meltdown対策)
- Spectre対策 — Retpoline、IBRS、STIBP
- スタックプロテクタ — CONFIG_STACKPROTECTOR
- 制御フロー整合性(CFI)
- SeccompとSeccomp-BPF
- POSIX Capabilities
- No-Execute(NX)ビット
- Write-or-Execute(W^X)ポリシー
- アドレスサニタイザ — KASAN、KMSAN、KCSAN
- ロックダウンモード
- 整合性測定アーキテクチャ(IMA)
- dm-verityとdm-integrity
- セキュアブートとUEFI
- カーネルモジュール署名
- sysctlセキュリティパラメータ
- 本番環境向けハードニングチェックリスト
- CISベンチマーク主要項目
- セキュリティ監査ツール — checksec、lynis、openscap
- まとめ
- 参考文献
1. はじめに
Linuxカーネルは、クラウドサーバーやコンテナオーケストレータから組み込みデバイス、スーパーコンピュータに至るまで、現代のインフラストラクチャのほぼすべての基盤となっています。ユーザ空間アプリケーションとハードウェアの境界として、カーネルはLinuxシステムにおける最も重要なセキュリティ境界です。カーネルが侵害されれば、システム全体の完全な侵害を意味します。ring-0権限を持つ攻撃者に対しては、ユーザ空間のセキュリティメカニズムは一切保護を提供できません。
過去20年以上にわたり、Linuxカーネルコミュニティは幅広い脅威に対応する豊富なハードニング機能を開発してきました:
- メモリ破壊攻撃(バッファオーバーフロー、Use-After-Freeなど)
- 投機的実行サイドチャネル攻撃(Meltdown、Spectreの各亜種)
- 権限昇格(Capability悪用を通じた攻撃)
- コードインジェクションとコード再利用攻撃(ROP、JOP)
- ファームウェアおよびブートプロセスの改ざん
- カーネルモジュールサプライチェーン攻撃
- 情報漏洩(カーネルメモリからユーザ空間へ)
本記事では、これらのハードニング機能それぞれについて詳しく解説します:
- 理論 — 脅威モデルと緩和策の仕組み
- カーネル設定 — ビルド時に有効化する
CONFIG_*オプション - ランタイム設定 — ブートパラメータと
sysctlチューナブル - 検証方法 — 実行中のシステムで機能が有効であることの確認方法
- パフォーマンスへの影響 — 期待されるオーバーヘッド
- 実践例 — すぐに使用できるコマンドとコードスニペット
脅威の全体像
┌─────────────────────────────────────────────────────────────┐
│ 攻撃対象領域 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ネットワ │ │システム │ │ メモリ │ │ ブート │ │
│ │ーク攻撃 │ │ コール │ │ 破壊 │ │ チェーン │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Linux カーネル │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌──────────┐ │ │
│ │ │ KASLR │ │Seccomp │ │Stack │ │Secure │ │ │
│ │ │ KPTI │ │Capabil. │ │Protect │ │Boot │ │ │
│ │ │ Spectre │ │Lockdown │ │CFI │ │IMA │ │ │
│ │ │ NX/W^X │ │sysctl │ │KASAN │ │dm-verity │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └──────────┘ │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
多層防御の原則
単一のハードニング機能だけでは不十分です。Linuxカーネルのセキュリティモデルは**多層防御(Defense in Depth)**の原則に従っています。複数の保護レイヤーが重なることで、1つのレイヤーが突破されても、後続のレイヤーが引き続き保護を提供します。
レイヤー1: ハードウェア → NXビット、SMEP、SMAP、CET
レイヤー2: ブート → セキュアブート、UEFI、IMA
レイヤー3: カーネル → KASLR、KPTI、CFI、スタックプロテクタ
レイヤー4: システムコール → Seccomp-BPF、Capabilities
レイヤー5: ランタイム → ロックダウン、sysctlハードニング
レイヤー6: 整合性 → dm-verity、モジュール署名
レイヤー7: 監査 → checksec、lynis、openscap
2. KASLR — カーネルアドレス空間配置のランダム化
2.1 概要
KASLR(Kernel Address Space Layout Randomization)は、ブート時にカーネルイメージがロードされるメモリアドレスをランダム化するセキュリティ技術です。これにより、カーネル関数やデータ構造のアドレスが予測不可能になるため、メモリ破壊脆弱性の悪用が大幅に困難になります。
KASLRがない場合、カーネルは常に固定された既知のアドレスにロードされます。バッファオーバーフロー脆弱性を発見した攻撃者は、commit_creds()やprepare_kernel_cred()などの特定のカーネル関数にジャンプするエクスプロイトを作成できます。なぜなら、それらのアドレスは同一カーネルビルドにおいて常に同じだからです。
2.2 KASLRの動作原理
KASLRなし(決定的配置):
┌────────────────────────────────────┐
│ 0xffffffff81000000 カーネルテキスト │ ← 常に同じ
│ 0xffffffff82000000 カーネルデータ │
│ 0xffffffff83000000 カーネルモジュール │
└────────────────────────────────────┘
KASLRあり(ランダム化された配置):
ブート1回目: ブート2回目:
┌────────────────────────────────┐ ┌────────────────────────────────┐
│ 0xffffffff89a30000 テキスト │ │ 0xffffffff85f10000 テキスト │
│ 0xffffffff8ab40000 データ │ │ 0xffffffff87020000 データ │
│ 0xffffffff8bc50000 モジュール │ │ 0xffffffff88130000 モジュール │
└────────────────────────────────┘ └────────────────────────────────┘
KASLRは3つのレベルでランダム化を導入します:
- 物理アドレスのランダム化 — カーネルが展開される物理メモリアドレス
- 仮想アドレスのランダム化 — カーネルテキストとデータの仮想アドレスマッピング
- モジュールアドレスのランダム化 — ロード可能なカーネルモジュールのベースアドレス
x86_64ではエントロピーは通常9〜10ビットで、2MBアラインメント境界で最大1024の配置位置を提供します。
2.3 カーネル設定
# 必須カーネル設定オプション
CONFIG_RANDOMIZE_BASE=y # KASLRを有効化
CONFIG_RANDOMIZE_MEMORY=y # カーネルメモリセクションのランダム化
CONFIG_RELOCATABLE=y # KASLRの動作に必要
# オプション(推奨)
CONFIG_GCC_PLUGIN_RANDSTRUCT=y # カーネル構造体のレイアウトをランダム化
2.4 ブートパラメータ
# KASLRはモダンなカーネルではデフォルトで有効
# 明示的に制御する場合:
# KASLRを有効化(多くのディストリビューションでデフォルト)
GRUB_CMDLINE_LINUX="kaslr"
# KASLRを無効化(デバッグ用のみ — 本番環境では使用しないこと)
GRUB_CMDLINE_LINUX="nokaslr"
# GRUB変更を適用
sudo update-grub
# RHELベースのシステムの場合:
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
2.5 検証方法
# 方法1: /proc/cmdlineでKASLRが有効か確認
cat /proc/cmdline | grep -o 'nokaslr' || echo "KASLRは有効です(nokaslrが見つかりません)"
# 方法2: リブート間でカーネルシンボルアドレスを比較(root権限が必要)
sudo cat /proc/kallsyms | grep ' T _text'
# リブート後、アドレスが変化するはず
# 方法3: dmesgでKASLRメッセージを確認
dmesg | grep -i kaslr
# 期待される出力: "KASLR using RDRAND RDTSC..."
# 方法4: カーネル設定を確認
grep CONFIG_RANDOMIZE_BASE /boot/config-$(uname -r)
# 期待値: CONFIG_RANDOMIZE_BASE=y
2.6 KASLRと情報漏洩
KASLRの有効性は、カーネルアドレスを秘密に保つことに完全に依存します。いくつかのカーネルインターフェースがアドレスを漏洩し、KASLRを無効化する可能性があります:
# カーネルポインタへのアクセスを制限
# /proc/kallsymsはカーネルシンボルアドレスを表示する
sudo sysctl -w kernel.kptr_restrict=2
# 値の意味:
# 0 = すべてのユーザにアドレスが表示される(安全でない)
# 1 = 非特権ユーザからアドレスを隠す(%pKでハッシュ化)
# 2 = rootを含むすべてのユーザからアドレスを隠す
# dmesgアクセスを制限(カーネルログにアドレスが含まれる場合がある)
sudo sysctl -w kernel.dmesg_restrict=1
# アドレスを漏洩する可能性のあるperfイベントを制限
sudo sysctl -w kernel.perf_event_paranoid=3
# 永続化
cat >> /etc/sysctl.d/90-kaslr-hardening.conf << 'EOF'
kernel.kptr_restrict = 2
kernel.dmesg_restrict = 1
kernel.perf_event_paranoid = 3
EOF
2.7 KASLRバイパス技術と対策
| バイパス手法 | 説明 | 対策 |
|---|---|---|
/proc/kallsyms漏洩 | カーネルシンボルアドレスの読み取り | kptr_restrict=2 |
dmesgポインタ漏洩 | カーネルログにアドレスが出力される可能性 | dmesg_restrict=1 |
| タイミングサイドチャネル | Prefetch/TSXベースのタイミング攻撃 | KPTI(ページテーブル分離) |
| ハードウェアサイドチャネル | Meltdown、Spectre | KPTI + Spectre対策 |
| 例外ベースプロービング | #PFタイミングの差異 | KPTI |
| カーネルヒープスプレー | カーネルアロケーションへの影響 | SLABランダム化 |
2.8 FGKASLR — 細粒度KASLR
標準のKASLRはカーネルイメージのベースアドレスをランダム化します。FGKASLR(Fine-Grained KASLR)はさらに進んで、カーネルテキストセクション内の個々の関数の順序をランダム化します:
# FGKASLRカーネル設定(新しいカーネルで利用可能)
CONFIG_FG_KASLR=y
# ブート時に関数をシャッフルし、ベースアドレスが漏洩しても
# 特定の関数の位置を予測することを大幅に困難にする
2.9 パフォーマンスへの影響
KASLRはランタイムパフォーマンスへの影響はほぼゼロです。ランダム化はブート時にのみ発生し、カーネルは配置されたアドレスで実行され、継続的なオーバーヘッドは発生しません。
- ブート時間: +10〜50ms(ランダム化の一回限りのコスト)
- ランタイム: 測定可能なオーバーヘッドなし
- メモリ: 追加メモリ使用なし
これにより、KASLRは利用可能なセキュリティ機能の中で最もコスト効率の高いものの一つとなっています。
3. KPTI — カーネルページテーブル分離
3.1 概要
KPTI(Kernel Page Table Isolation)は、KAISER(Kernel Address Isolation to have Side-channels Efficiently Removed)とも呼ばれ、Meltdown脆弱性(CVE-2017-5754)に対する主要なソフトウェア緩和策です。Meltdownは、非特権ユーザ空間プロセスが投機的実行を悪用して任意のカーネルメモリを読み取ることを可能にします。
KPTIの導入前は、ユーザ空間とカーネル空間は同じページテーブルを共有していました。カーネルページはスーパーバイザ専用(ring 3からアクセス不可)としてマークされていましたが、Meltdownは投機的実行がこれらの権限チェックをバイパスし、カーネルデータをCPUキャッシュに漏洩できることを示しました。
3.2 Meltdownの仕組み
従来の(脆弱な)アーキテクチャ:
┌──────────────────────────────────────────┐
│ 単一のページテーブル │
│ ┌─────────────────────────────────────┐ │
│ │ ユーザ空間ページ(アクセス可能) │ │
│ │ 0x0000... - 0x7fff... │ │
│ ├─────────────────────────────────────┤ │
│ │ カーネル空間ページ(スーパーバイザ)│ │ ← CPUは権限を確認
│ │ 0xffff... - 0xffffffff... │ │ ← しかし投機的実行は
│ └─────────────────────────────────────┘ │ チェックを無視!
└──────────────────────────────────────────┘
Meltdown攻撃のフロー:
1. ユーザ空間コードが投機的にカーネルアドレスを読み取る
2. CPUは最終的に権限違反を検出 → 例外
3. しかし: データは既にキャッシュに存在
4. 攻撃者はキャッシュタイミングを使ってカーネルデータを推測
3.3 KPTIの動作原理
KPTIは各プロセスに対して2つの別々のページテーブルセットを維持します:
KPTIあり:
┌──────────────────────┐ ┌──────────────────────┐
│ ユーザページテーブル │ │ カーネルページテーブル │
│ (ユーザモードで使用) │ │(カーネルモードで使用)│
│ ┌────────────────┐ │ │ ┌────────────────┐ │
│ │ユーザページ │ │ │ │ユーザページ │ │
│ │(完全マッピング)│ │ │ │(完全マッピング)│ │
│ ├────────────────┤ │ │ ├────────────────┤ │
│ │カーネルページ │ │ │ │カーネルページ │ │
│ │(最小限のスタブ │ │ │ │(完全マッピング)│ │
│ │ エントリ/出口 │ │ │ │ │ │
│ │ トランポリン │ │ │ │ │ │
│ │ のみ) │ │ │ │ │ │
│ └────────────────┘ │ │ └────────────────┘ │
└──────────────────────┘ └──────────────────────┘
▲ ▲
CPUがring 3の時に CPUがring 0の時に
使用される 使用される
3.4 カーネル設定
# KPTIを有効化
CONFIG_PAGE_TABLE_ISOLATION=y
# このオプションはx86_64カーネルではデフォルトで有効
# カーネル設定を確認:
grep CONFIG_PAGE_TABLE_ISOLATION /boot/config-$(uname -r)
3.5 ブートパラメータ
# ブートパラメータによるKPTI制御
# KPTIを有効化(脆弱なCPUではデフォルト)
GRUB_CMDLINE_LINUX="pti=on"
# KPTIを無効化(CPUが脆弱でない場合のみ、例: AMD)
GRUB_CMDLINE_LINUX="pti=off"
# CPU脆弱性に基づく自動検出
GRUB_CMDLINE_LINUX="pti=auto"
3.6 検証方法
# 方法1: CPU脆弱性状態を確認
cat /sys/devices/system/cpu/vulnerabilities/meltdown
# 期待される出力: "Mitigation: PTI"
# 方法2: dmesgでKPTI有効化を確認
dmesg | grep -i "page table isolation"
# 期待値: "Kernel/User page tables isolation: enabled"
# 方法3: すべてのCPU脆弱性の包括的チェック
for vuln in /sys/devices/system/cpu/vulnerabilities/*; do
echo "$(basename $vuln): $(cat $vuln)"
done
3.7 KPTIとPCID最適化
モダンなx86 CPUのPCID(Page Context IDentifier)機能は、ページテーブル切り替え時の完全なTLB(Translation Lookaside Buffer)フラッシュを回避することで、KPTIのパフォーマンスコストを大幅に削減します:
# PCIDサポートを確認
grep -o 'pcid' /proc/cpuinfo | head -1
# "pcid"が表示されればサポートされている
# INVPCID命令サポートを確認(さらに高速)
grep -o 'invpcid_single' /proc/cpuinfo | head -1
TLBフラッシュの挙動:
┌──────────────────────────────────────────────────┐
│ PCIDなし: │
│ User→Kernel: すべてのTLBエントリをフラッシュ │
│ Kernel→User: すべてのTLBエントリをフラッシュ │
│ → すべてのシステムコール = 2回の完全TLBフラッシュ│
│ │
│ PCIDあり: │
│ User→Kernel: PCIDタグ切り替え、フラッシュなし │
│ Kernel→User: PCIDタグ切り替え、フラッシュなし │
│ → TLBエントリにタグ付け、フラッシュ不要 │
│ → KPTIオーバーヘッドを約50%削減 │
└──────────────────────────────────────────────────┘
3.8 パフォーマンスへの影響
| ワークロードタイプ | 影響(PCIDなし) | 影響(PCIDあり) |
|---|---|---|
| システムコール多用(DB等) | 15-30% | 2-5% |
| I/O集中型 | 10-20% | 1-3% |
| 計算集中型 | < 1% | < 0.5% |
| ネットワーク(小パケット多数) | 10-25% | 2-5% |
| 混合ワークロード | 5-15% | 1-3% |
推奨: Intel CPUではKPTIを常に有効にすること。PCIDが利用可能なモダンハードウェアではパフォーマンスへの影響は最小限です。
4. Spectre対策 — Retpoline、IBRS、STIBP
4.1 概要
Spectre(CVE-2017-5753およびCVE-2017-5715)は、事実上すべてのモダンプロセッサに影響する投機的実行の脆弱性クラスです。主にIntelの問題であるMeltdownとは異なり、SpectreはIntel、AMD、ARM、およびその他のアーキテクチャに影響します。Spectreは分岐予測を悪用して、サイドチャネルを通じて機密データを漏洩するコードをCPUに投機的に実行させます。
4.2 Spectreの亜種
Spectre Variant 1(境界チェックバイパス — CVE-2017-5753):
─────────────────────────────────────────────────────────
if (index < array_size) { ← 分岐はtakenと予測される
value = array[index]; ← 投機的に境界外アクセス
leak = probe[value * 4096]; ← 依存データをキャッシュにロード
}
// 分岐予測ミスでロールバックされても、
// キャッシュ状態がarray[index]の値を暴露する
Spectre Variant 2(分岐ターゲットインジェクション — CVE-2017-5715):
─────────────────────────────────────────────────────────────
攻撃者がBTB(Branch Target Buffer)を訓練し、
間接分岐を攻撃者が選んだ「ガジェット」コードにリダイレクト。
call [function_pointer] ← BTBが攻撃者のガジェットを予測
│ ← CPUが投機的にガジェットを実行
▼
ガジェット: mov rax, [secret]; mov rbx, [probe + rax*4096]
4.3 Retpoline — リターントランポリン
RetpolineはSpectre Variant 2に対するソフトウェアのみの緩和策です。間接ジャンプとコールを、BTBの代わりにRSB(Return Stack Buffer)を使用する構造に置き換え、BTBポイズニングを防止します:
; 通常の間接コール(Spectre v2に脆弱):
call [rax]
; Retpolineによる置換:
call retpoline_rax_trampoline
retpoline_rax_trampoline:
call .setup_target
.capture_spec:
pause ; 投機トラップ — 無限ループ
lfence ; メモリバリア
jmp .capture_spec ; 投機的実行をこのループに閉じ込める
.setup_target:
mov [rsp], rax ; リターンアドレスを実際のターゲットで上書き
ret ; RSB(BTBではなく)を使ってターゲットにジャンプ
Retpolineの有効化
# カーネル設定
CONFIG_RETPOLINE=y
# ブート時に確認
dmesg | grep -i retpoline
# 期待される出力: "Spectre V2 : Mitigation: Retpolines"
# 現在のSpectre v2緩和策を確認
cat /sys/devices/system/cpu/vulnerabilities/spectre_v2
# コンパイラサポートが必要
# GCC 7.3以降またはGCC 8.1以降がretpolineサポートに必要
4.4 IBRS — 間接分岐制限投機
IBRSはCPUマイクロコードアップデートを通じて提供されるハードウェアベースの緩和策です:
# IBRSモード:
# IBRS — カーネルエントリ時にセット、カーネル終了時にクリア(レガシー)
# IBRS_FW — ファームウェアコールに対してのみセット
# Enhanced IBRS (eIBRS) — 常にアクティブ、エントリ/終了の切り替え不要
# IBRSサポートを確認
grep -o 'ibrs' /proc/cpuinfo | head -1
# IBRSのブートパラメータ
GRUB_CMDLINE_LINUX="spectre_v2=ibrs" # IBRSを強制
GRUB_CMDLINE_LINUX="spectre_v2=retpoline" # retpolineを強制
GRUB_CMDLINE_LINUX="spectre_v2=auto" # 最適を自動選択
GRUB_CMDLINE_LINUX="spectre_v2=off" # 危険: 無効化
4.5 STIBP — シングルスレッド間接分岐予測器
STIBPは、同じ物理コア上のシブリングスレッド(ハイパースレッド)間で分岐予測が影響し合うことを防止します:
# STIBPはSMT(ハイパースレッディング)システムで重要
# STIBPなしでは、同じコア上のvCPU間で攻撃が可能
# STIBPサポートを確認
grep -o 'stibp' /proc/cpuinfo | head -1
# ブートパラメータ制御
GRUB_CMDLINE_LINUX="spectre_v2_user=on" # ユーザ空間緩和策を有効化
GRUB_CMDLINE_LINUX="spectre_v2_user=prctl" # prctlによるプロセスごとの制御
GRUB_CMDLINE_LINUX="spectre_v2_user=seccomp" # seccompモードに基づく
4.6 IBPB — 間接分岐予測バリア
IBPBは異なるセキュリティコンテキスト間(プロセス間など)で切り替え時に分岐予測状態をフラッシュします:
# IBPBサポートを確認
grep -o 'ibpb' /proc/cpuinfo | head -1
# IBPBは通常、他の緩和策と組み合わせて使用される
cat /sys/devices/system/cpu/vulnerabilities/spectre_v2
# "IBPB: conditional"または"IBPB: always-on"を探す
4.7 Spectre v1対策
Spectre Variant 1は主に以下で緩和されます:
- usercopyハードニング — ユーザ−カーネル間コピーの境界チェック
- array_index_nospec() — 境界チェックを超えた投機を防止するコンパイラバリア
- 投機バリア — 機密コードパスにおける
lfence命令
/* カーネルコード例: array_index_nospec()の使用 */
#include <linux/nospec.h>
int safe_array_access(unsigned long index, unsigned long array_size)
{
if (index < array_size) {
/* インデックスをクランプして投機的な境界外アクセスを防止 */
index = array_index_nospec(index, array_size);
return my_array[index];
}
return -EINVAL;
}
4.8 包括的Spectre状態チェックスクリプト
#!/bin/bash
# spectre_check.sh — すべてのSpectre関連緩和策をチェック
echo "============================================="
echo " Spectre 脆弱性 & 緩和策レポート"
echo "============================================="
echo ""
echo "CPU: $(grep 'model name' /proc/cpuinfo | head -1 | cut -d: -f2 | xargs)"
echo "マイクロコード: $(grep 'microcode' /proc/cpuinfo | head -1 | cut -d: -f2 | xargs)"
echo ""
echo "--- CPUハードウェア機能 ---"
for feature in ibrs ibpb stibp ssbd ibrs_enhanced; do
if grep -qo "$feature" /proc/cpuinfo; then
echo " $feature: サポートあり"
else
echo " $feature: なし"
fi
done
echo ""
echo "--- 脆弱性ステータス ---"
for vuln in /sys/devices/system/cpu/vulnerabilities/*; do
name=$(basename "$vuln")
status=$(cat "$vuln" 2>/dev/null || echo "N/A")
printf " %-25s %s\n" "$name:" "$status"
done
4.9 パフォーマンスへの影響
| 緩和策 | システムコールオーバーヘッド | ワークロードへの影響 | 備考 |
|---|---|---|---|
| Retpoline | 約2-5% | 2-14% | 間接コール頻度に依存 |
| IBRS(レガシー) | 約10-20% | 10-25% | 非常に高コスト、可能な限り回避 |
| eIBRS | 約1-2% | 1-3% | ハードウェア最適化、推奨 |
| STIBP | 約1-5% | 1-8% | 主にSMTワークロードに影響 |
| IBPB | 約1-2% | 1-3% | コンテキストスイッチ時のみ |
ベストプラクティス:
- CPUがサポートしていればeIBRSを使用(モダンなIntel/AMD)
- 古いCPUではretpolineにフォールバック
- 常にIBPBを有効化(プロセス間保護)
- 高セキュリティシステムではSMT無効化(
nosmt)を検討
# 高セキュリティ設定(最大限の保護、オーバーヘッド大)
GRUB_CMDLINE_LINUX="spectre_v2=on spectre_v2_user=on spec_store_bypass_disable=on l1tf=full,force nosmt"
# バランス設定(適切な保護、中程度のオーバーヘッド)
GRUB_CMDLINE_LINUX="spectre_v2=auto spectre_v2_user=auto spec_store_bypass_disable=auto"
5. スタックプロテクタ — CONFIG_STACKPROTECTOR
5.1 概要
スタックプロテクタ(スタックカナリアまたはスタックガードとも呼ばれる)は、スタックバッファオーバーフロー攻撃に対するコンパイラベースの防御です。ローカル変数と保存されたリターンアドレスの間にランダムな「カナリア」値をスタック上に配置します。関数がリターンする前にカナリアがチェックされ、変更されていた場合(バッファオーバーフローの発生を示す)、破損したリターンアドレスが使用される前にカーネルパニックが発生します。
5.2 スタックカナリアの動作原理
スタックプロテクタなしのスタックレイアウト:
┌────────────────────────┐ 高アドレス
│ リターンアドレス │ ← 攻撃者の標的
├────────────────────────┤
│ 保存フレームポインタ │
├────────────────────────┤
│ ローカル変数B │
├────────────────────────┤
│ ローカル変数A │ ← バッファオーバーフローの起点
├────────────────────────┤
│ バッファ(char buf[64])│
└────────────────────────┘ 低アドレス
スタックプロテクタありのスタックレイアウト:
┌────────────────────────┐ 高アドレス
│ リターンアドレス │
├────────────────────────┤
│ 保存フレームポインタ │
├────────────────────────┤
│ *** カナリア値 *** │ ← リターン前にチェックされるランダム値
├────────────────────────┤
│ ローカル変数B │
├────────────────────────┤
│ ローカル変数A │
├────────────────────────┤
│ バッファ(char buf[64])│ ← オーバーフローがカナリアを上書き
└────────────────────────┘ 低アドレス
カナリアが破壊された場合 → __stack_chk_fail() → カーネルパニック!
5.3 スタックプロテクタの亜種
# 基本的なスタックプロテクタ — 文字配列を持つ関数を保護
CONFIG_STACKPROTECTOR=y
# 強力なスタックプロテクタ — より多くの関数を保護
# 以下の関数が保護される:
# - 任意の型のローカル配列
# - ローカルフレームアドレスへの参照
# - alloca()の呼び出し
CONFIG_STACKPROTECTOR_STRONG=y # 本番環境に推奨
# タスクごとのスタックカナリア(ブートごとではなくタスクごとにランダム化)
CONFIG_STACKPROTECTOR_PER_TASK=y # 追加のランダム化
5.4 検証方法
# カーネル設定を確認
grep STACKPROTECTOR /boot/config-$(uname -r)
# 期待値:
# CONFIG_STACKPROTECTOR=y
# CONFIG_STACKPROTECTOR_STRONG=y
# ユーザ空間バイナリにはchecksecを使用
checksec --file=/usr/bin/ls
# 出力で"Canary found"を探す
5.5 パフォーマンスへの影響
| 亜種 | オーバーヘッド | 推奨 |
|---|---|---|
| CONFIG_STACKPROTECTOR(基本) | < 1% | 最低限必要 |
| CONFIG_STACKPROTECTOR_STRONG | 1-2% | すべてのシステムに推奨 |
| -fstack-protector-all | 5-10% | カーネルには非推奨 |
6. 制御フロー整合性(CFI)
6.1 概要
制御フロー整合性(CFI: Control Flow Integrity)は、間接関数呼び出しとジャンプの有効なターゲットセットを制限するセキュリティメカニズムです。プログラムの意図した制御フローグラフに従うことを保証することで、ROP(Return-Oriented Programming)やJOP(Jump-Oriented Programming)などのコード再利用攻撃を防止します。
6.2 CFIが防止する攻撃タイプ
コード再利用攻撃:
┌──────────────────────────────────────────────────────┐
│ Return-Oriented Programming (ROP): │
│ 攻撃者がRET命令で終わる小さなコード断片 │
│ (「ガジェット」)をチェーンする │
│ → 任意のコード実行を達成 │
│ │
│ Jump-Oriented Programming (JOP): │
│ 攻撃者が間接ジャンプをハイジャックしてガジェットを │
│ チェーンする │
│ → シャドウスタックがあっても動作 │
│ │
│ Call-Oriented Programming (COP): │
│ 攻撃者が間接コールを誤ったターゲットにリダイレクト │
│ → 正当な関数を誤った引数で呼び出す │
└──────────────────────────────────────────────────────┘
CFI防御:
┌──────────────────────────────────────────────────────┐
│ 各間接コール/ジャンプの前に: │
│ 1. ターゲットが有効な関数エントリかチェック │
│ 2. ターゲットが正しい型シグネチャを持つかチェック │
│ (フォワードエッジCFI) │
│ 3. 無効な場合 → トラップ/パニック │
│ │
│ 各リターンの前に: │
│ 1. リターンアドレスをシャドウスタックと照合 │
│ (バックワードエッジCFI) │
│ 2. 不一致の場合 → トラップ/パニック │
└──────────────────────────────────────────────────────┘
6.3 LinuxカーネルにおけるCFI
Clang CFI(kCFI)
# Clang CFI用のカーネル設定
CONFIG_CFI_CLANG=y # Clangのフォワードエッジ CFIを有効化
CONFIG_CFI_PERMISSIVE=n # 厳密モード(本番環境に推奨)
# テスト中は=yにして違反をログに記録
# 要件:
# - Clangコンパイラ(GCCはkCFIをサポートしない)
# - リンク時最適化(LTO)を有効にする必要あり
CONFIG_LTO_CLANG=y
CONFIG_LTO_CLANG_THIN=y # Thin LTO(ビルド時間が短い)
Intel CET(Control-flow Enforcement Technology)
# Intel CETを使用したハードウェアベースCFI
CONFIG_X86_KERNEL_IBT=y # 間接分岐追跡(フォワードエッジ)
CONFIG_X86_USER_SHADOW_STACK=y # シャドウスタック(バックワードエッジ、ユーザ空間)
# IBTは有効な間接分岐ターゲットにENDBR64命令を追加
# ENDBR64に着地しない間接分岐は#CP例外をトリガー
6.4 シャドウスタック(バックワードエッジCFI)
シャドウスタックのメカニズム:
┌──────────────┐ ┌──────────────┐
│ 通常スタック │ │シャドウスタック│
│ │ │ │
│ ローカル変数 │ │ │
│ 保存 rbp │ │ │
│ ret addr: A │◄──►│ ret addr: A │ ← 一致が必要!
│ 引数 │ │ │
│ ローカル変数 │ │ │
│ 保存 rbp │ │ │
│ ret addr: B │◄──►│ ret addr: B │ ← 一致が必要!
└──────────────┘ └──────────────┘
攻撃者が通常スタックのリターンアドレスを上書きした場合:
通常スタック: ret addr → 0xEVIL
シャドウスタック: ret addr → 0xLEGIT
→ 不一致 → #CP例外 → プロセス終了
6.5 パフォーマンスへの影響
| CFIタイプ | オーバーヘッド | 備考 |
|---|---|---|
| kCFI(フォワードエッジ) | 1-3% | Clang + LTOが必要 |
| IBT(ハードウェアフォワードエッジ) | < 1% | Intel第12世代以降のCPU |
| シャドウスタック(バックワードエッジ) | < 1% | Intel第12世代以降のCPU |
| 複合CFI | 1-4% | 最高の保護 |
7. SeccompとSeccomp-BPF
7.1 概要
Seccomp(Secure Computing Mode)は、プロセスが実行できるシステムコールを制限するLinuxカーネル機能です。各プロセスに公開されるカーネル攻撃面を限定することで、脆弱性の影響を大幅に低減します。プロセスが侵害されても、攻撃者は許可されたシステムコールのみを使用できます。
7.2 Seccompモード
モード0: 無効
→ プロセスはすべてのシステムコールを使用可能
モード1: 厳密モード(オリジナルseccomp)
→ read()、write()、exit()、sigreturn()のみ許可
→ その他のシステムコール → SIGKILL
→ 非常に制限的、直接使用されることは稀
モード2: フィルタモード(seccomp-bpf)
→ カスタムBPFフィルタで許可するシステムコールを定義可能
→ システムコールごとの判定: ALLOW、KILL、TRAP、ERRNO、TRACE、LOG
→ 最も一般的に使用されるモード(Docker、Chrome、systemd等)
7.3 Seccomp-BPFアーキテクチャ
┌──────────────────────────────────────────────────────┐
│ ユーザプロセス │
│ │
│ 1. prctl()またはseccomp()でBPFフィルタをインストール │
│ 2. システムコールを発行 │
│ │
└────────────────────┬─────────────────────────────────┘
│ syscall
▼
┌──────────────────────────────────────────────────────┐
│ カーネル │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ BPF Seccompフィルタ │ │
│ │ │ │
│ │ 検査対象: システムコール番号、引数 │ │
│ │ │ │
│ │ 判定: │ │
│ │ SECCOMP_RET_ALLOW → システムコール実行 │ │
│ │ SECCOMP_RET_KILL → プロセス終了 │ │
│ │ SECCOMP_RET_ERRNO → エラーコード返却 │ │
│ │ SECCOMP_RET_TRAP → SIGSYSシグナル送信 │ │
│ │ SECCOMP_RET_TRACE → ptraceトレーサに通知 │ │
│ │ SECCOMP_RET_LOG → 許可するがログ記録 │ │
│ └─────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────┘
7.4 libseccompを使用したプログラミング例
/* seccomp_libseccomp.c — libseccompでフィルタを簡単に作成 */
#include <seccomp.h>
#include <stdio.h>
#include <unistd.h>
int main(void)
{
scmp_filter_ctx ctx;
/* デフォルトアクション: killでフィルタを作成 */
ctx = seccomp_init(SCMP_ACT_KILL);
if (ctx == NULL) {
fprintf(stderr, "seccomp_init失敗\n");
return 1;
}
/* 特定のシステムコールを許可 */
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigreturn), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(brk), 0);
/* open()は読み取り専用アクセスのみ許可 */
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 1,
SCMP_A1(SCMP_CMP_MASKED_EQ, O_WRONLY | O_RDWR, 0));
/* フィルタをロード */
if (seccomp_load(ctx) < 0) {
fprintf(stderr, "seccomp_load失敗\n");
seccomp_release(ctx);
return 1;
}
printf("libseccomp経由でSeccompフィルタがロードされました!\n");
seccomp_release(ctx);
return 0;
}
/* コンパイル: gcc -o seccomp_demo seccomp_libseccomp.c -lseccomp */
7.5 DockerとKubernetesでのSeccomp
# カスタムseccompプロファイルでDockerコンテナを実行
docker run --security-opt seccomp=my-profile.json nginx
# seccompなしでDockerコンテナを実行(危険 — デバッグ用のみ)
docker run --security-opt seccomp=unconfined nginx
# Seccompプロファイル付きKubernetes Pod
apiVersion: v1
kind: Pod
metadata:
name: seccomp-pod
spec:
securityContext:
seccompProfile:
type: RuntimeDefault # コンテナランタイムのデフォルトプロファイルを使用
containers:
- name: app
image: myapp:latest
securityContext:
seccompProfile:
type: Localhost
localhostProfile: profiles/my-seccomp.json
7.6 systemdサービスのSeccompハードニング
# /etc/systemd/system/myservice.service
[Unit]
Description=ハードニングされたサービス
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/myservice
User=myservice
Group=myservice
# Seccomp: 特定のシステムコールグループのみを許可
SystemCallFilter=@system-service
SystemCallFilter=~@privileged @resources
SystemCallErrorNumber=EPERM
# 追加のハードニング
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
MemoryDenyWriteExecute=yes
[Install]
WantedBy=multi-user.target
# 利用可能なsystemdシステムコールグループの一覧
systemd-analyze syscall-filter
# @system-service: 一般的なシステムサービスコール
# @privileged: 特権が必要なコール
# @network-io: ネットワーク関連コール
# @file-system: ファイルシステム操作
# @process: プロセス管理
# systemdサービスのセキュリティを分析
systemd-analyze security myservice
# セキュリティスコアと推奨事項が提供される
8. POSIX Capabilities
8.1 概要
POSIX Capabilitiesは、モノリシックなroot権限を個別に有効化・無効化できる明確で粒度の細かい単位に分解します。root/非rootの二元的モデルの代わりに、Capabilitiesによりプロセスは必要な権限のみを正確に持つことができます。
8.2 root権限の問題
従来のUNIX権限モデル:
┌──────────────────────────────────────────┐
│ UID 0(root) │
│ ┌────────────────────────────────────┐ │
│ │ すべての権限 — 分割不可能 │ │
│ │ • ポート1024未満へのバインド │ │
│ │ • 任意のプロセスのキル │ │
│ │ • ファイルシステムのマウント │ │
│ │ • カーネルモジュールのロード │ │
│ │ • ファイル所有権の変更 │ │
│ │ • DACパーミッションの上書き │ │
│ │ • ネットワークインターフェース設定│ │
│ │ • システム再起動 │ │
│ │ • ... これらすべて、常に │ │
│ └────────────────────────────────────┘ │
└──────────────────────────────────────────┘
問題: WebサーバはCAP_NET_BIND_SERVICE(ポート80へのバインド)
のみが必要だが、rootで実行すると40以上の全Capabilityが付与される!
Capabilityモデル:
┌──────────────────────────────────────────┐
│ 最小限必要なCapability │
│ ┌─────────────────────┐ │
│ │ CAP_NET_BIND_SERVICE│ ← これだけ! │
│ └─────────────────────┘ │
└──────────────────────────────────────────┘
8.3 Capabilityの管理
# 現在のプロセスのCapabilityを表示
cat /proc/self/status | grep Cap
# Capability16進値のデコード
capsh --decode=000001ffffffffff
# ファイルCapabilityの設定(setuidの代わり)
# rootなしでnginxがポート80にバインドできるようにする:
sudo setcap 'cap_net_bind_service=+ep' /usr/sbin/nginx
# ファイルCapabilityの確認
getcap /usr/sbin/nginx
# /usr/sbin/nginx = cap_net_bind_service+ep
# ファイルCapabilityの削除
sudo setcap -r /usr/sbin/nginx
# Capabilityが設定されたすべてのバイナリを検索
sudo getcap -r / 2>/dev/null
8.4 DockerでのCapability
# Dockerはデフォルトで多くのCapabilityをドロップする
# 最小限のCapabilityでコンテナを実行
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE nginx
# Capabilityなしでコンテナを実行
docker run --cap-drop=ALL busybox id
# Capability制限付きKubernetes Pod
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
spec:
containers:
- name: app
image: myapp:latest
securityContext:
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
runAsNonRoot: true
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
8.5 Capability監査
#!/bin/bash
# audit_capabilities.sh — setuidとCapabilityバイナリの検索
echo "=== ファイルCapabilityを持つバイナリ ==="
getcap -r / 2>/dev/null
echo ""
echo "=== setuidバイナリ(Capabilityに置き換えるべき) ==="
find / -perm -4000 -type f 2>/dev/null | while read bin; do
echo " SETUID: $bin (所有者: $(stat -c '%U' "$bin"))"
done
echo ""
echo "=== 昇格されたCapabilityを持つプロセス ==="
for pid in /proc/[0-9]*; do
pid_num=$(basename "$pid")
cap_eff=$(cat "$pid/status" 2>/dev/null | grep CapEff | awk '{print $2}')
if [ "$cap_eff" != "0000000000000000" ] && [ -n "$cap_eff" ]; then
cmd=$(cat "$pid/comm" 2>/dev/null)
echo " PID $pid_num ($cmd): CapEff=$cap_eff"
fi
done
9. No-Execute(NX)ビット
9.1 概要
No-Execute(NX)ビット(Intelではenable Execute Disable = XD、ARMではEVPとも呼ばれる)は、メモリページを実行不可としてマークするハードウェア機能です。これにより、スタック、ヒープ、データセグメントなどのデータ領域に格納されたコードをCPUが実行することを防止し、コードインジェクション攻撃に対する基本的な防御を提供します。
9.2 NXの動作原理
NXビットなし:
┌──────────────────────────────────────────────────┐
│ すべてのメモリが書き込み可能かつ実行可能 │
│ │
│ スタック: [シェルコード注入] ← 実行可能! │
│ ヒープ: [シェルコード注入] ← 実行可能! │
│ .data: [シェルコード注入] ← 実行可能! │
│ │
│ 攻撃者がスタックにシェルコードを書き込む │
│ → CPUがそれを実行する │
└──────────────────────────────────────────────────┘
NXビットあり:
┌──────────────────────────────────────────────────┐
│ メモリページに明示的な実行権限 │
│ │
│ .text: R-X (読み取り+実行、書き込み不可) │
│ .data: RW- (読み取り+書き込み、実行不可) │
│ スタック: RW- (読み取り+書き込み、実行不可)← NX!│
│ ヒープ: RW- (読み取り+書き込み、実行不可)← NX!│
│ │
│ 攻撃者がスタックにシェルコードを書き込む │
│ → CPUが実行を拒否 → セグメンテーション違反 │
└──────────────────────────────────────────────────┘
9.3 検証方法
# NXがサポートされアクティブか確認
grep -o 'nx' /proc/cpuinfo | head -1
# "nx" = NXはサポートされている
# dmesg経由で確認
dmesg | grep -i "NX"
# 期待される出力: "NX (Execute Disable) protection: active"
# 特定バイナリのメモリマッピングを確認
cat /proc/<PID>/maps | head -20
# r-xp = 読み取り+実行(コードセグメント)
# rw-p = 読み取り+書き込み、実行なし(データ/スタック)
# checksecでバイナリのNXを確認
checksec --file=/usr/bin/ls
# NX: NX enabled
9.4 パフォーマンスへの影響
NXはランタイムパフォーマンスオーバーヘッドがゼロです。ハードウェアのページテーブル機構で直接実装されており、CPUはすべてのメモリアクセスで行われる通常のページテーブルウォークの一部としてNXビットをチェックします。
10. Write-or-Execute(W^X)ポリシー
10.1 概要
W^X(Write XOR Execute)ポリシーは、メモリページは書き込み可能と実行可能を同時に持つべきではないというメモリ保護の原則です。NXの概念を拡張し、攻撃者が書き込み可能なページにシェルコードを書き込んでから実行可能にする(またはその逆の)シナリオを防止します。
10.2 カーネルメモリにおけるW^X
カーネルメモリでのW^X適用:
┌──────────────────────────────────────────────────────┐
│ メモリ領域 権限 W^X状態 │
│ ───────────── ───────── ────────── │
│ .text(コード) R-X OK: 実行可、書込不可 │
│ .rodata R-- OK: 読み取り専用 │
│ .data RW- OK: 書込可、実行不可 │
│ .bss RW- OK: 書込可、実行不可 │
│ スタック RW- OK: 書込可、実行不可 │
│ ヒープ/slab RW- OK: 書込可、実行不可 │
│ モジュール.text R-X OK: 実行可、書込不可 │
│ モジュール.data RW- OK: 書込可、実行不可 │
│ │
│ 違反: RWX NG!書込と実行の両方 │
└──────────────────────────────────────────────────────┘
10.3 カーネル設定
# カーネルコードとデータに対する厳密なW^X
CONFIG_STRICT_KERNEL_RWX=y # カーネルメモリにW^Xを適用
CONFIG_STRICT_MODULE_RWX=y # カーネルモジュールにW^Xを適用
# W^X違反を検出するデバッグオプション
CONFIG_DEBUG_WX=y # ブート時にW+Xマッピングについて警告
# カーネルテキストの書き込み防止
CONFIG_STRICT_DEVMEM=y # /dev/memアクセスを制限
CONFIG_IO_STRICT_DEVMEM=y # /dev/memをI/O領域のみに制限
10.4 検証方法
# ブート時のカーネルW^X違反を確認
dmesg | grep -i "W+X"
# 出力がなければ → W^X違反は検出されていない
# カーネル設定を確認
grep STRICT_KERNEL_RWX /boot/config-$(uname -r)
grep STRICT_MODULE_RWX /boot/config-$(uname -r)
grep DEBUG_WX /boot/config-$(uname -r)
# 特定プロセスのメモリマップでW+Xページを確認
grep 'rwx' /proc/<PID>/maps
# 理想的にはNO results(RWXマッピングなし)
10.5 JITコンパイラとW^X
JIT(Just-In-Time)コンパイラは実行時に実行可能コードを生成する必要があり、W^Xに違反するように見えます。安全なアプローチ:
W^Xを遵守した安全なJITコンパイル:
┌──────────────────────────────────────────────────────┐
│ ステップ1: 書込可能メモリを確保(RW-) │
│ mmap(... PROT_READ | PROT_WRITE ...) │
│ │
│ ステップ2: 生成コードをページに書き込む │
│ memcpy(jit_buffer, generated_code, size) │
│ │
│ ステップ3: 実行可能にし、書き込み権限を削除 │
│ mprotect(jit_buffer, size, │
│ PROT_READ | PROT_EXEC) │
│ │
│ 注意: ページは同時にRWXになることは決してない! │
│ RW- → コード書き込み → R-X → コード実行 │
└──────────────────────────────────────────────────────┘
10.6 systemd MemoryDenyWriteExecute
# サービスがW+Xマッピングを作成するのを防止
# systemdサービスファイル内:
[Service]
MemoryDenyWriteExecute=yes
# これにより以下が防止される:
# - PROT_WRITE | PROT_EXECでのmmap()
# - 書き込み可能ページへのPROT_EXEC追加のmprotect()
# - サービス全体にW^Xを効果的に適用
11. アドレスサニタイザ — KASAN、KMSAN、KCSAN
11.1 概要
カーネルアドレスサニタイザは、実行時にメモリ安全性のバグを検出するLinuxカーネルに組み込まれた動的解析ツールです。主に開発とテスト時に使用されますが(本番環境では使用しない)、カーネルビルドを検証したりカーネルセキュリティに貢献するセキュリティエンジニアにとって理解は不可欠です。
11.2 KASAN — カーネルアドレスサニタイザ
KASANは境界外アクセス、Use-After-Free、Use-After-Scope、ダブルフリーのバグを検出します。
# KASAN用カーネル設定
CONFIG_KASAN=y
CONFIG_KASAN_GENERIC=y # ソフトウェアベース(全アーキテクチャで動作)
# または
CONFIG_KASAN_SW_TAGS=y # タグベース(MTE対応のARM64)
# または
CONFIG_KASAN_HW_TAGS=y # ハードウェアタグベース(ARM64 MTE)
CONFIG_KASAN_INLINE=y # インライン計測(アウトラインより高速)
CONFIG_KASAN_STACK=y # スタック境界外チェック
CONFIG_KASAN_VMALLOC=y # vmallocアロケーションの計測
# ブートパラメータ
GRUB_CMDLINE_LINUX="kasan.fault=panic" # 最初のKASANレポートでパニック
GRUB_CMDLINE_LINUX="kasan.fault=report" # レポートするが継続(デフォルト)
KASANバグレポート例
BUG: KASAN: slab-out-of-bounds in vulnerable_function+0x42/0x80
Read of size 4 at addr ffff88800a4c0580 by task test/1234
CPU: 2 PID: 1234 Comm: test Not tainted 6.1.0-kasan #1
Call Trace:
dump_stack_lvl+0x34/0x44
print_address_description+0x65/0x2e0
kasan_report+0xba/0xf0
vulnerable_function+0x42/0x80
Allocated by task 1234:
kmalloc+0xa1/0xd0
vulnerable_function+0x20/0x80
11.3 KMSAN — カーネルメモリサニタイザ
KMSANは、情報漏洩につながる可能性のあるカーネル内での未初期化メモリの使用を検出します:
# KMSAN用カーネル設定
CONFIG_KMSAN=y
CONFIG_KMSAN_CHECK_PARAM_RETVAL=y # 関数パラメータのチェック
# KMSANはKASANと非互換 — どちらか一方を選択
# KMSANはClangコンパイラが必要(GCCは不可)
11.4 KCSAN — カーネル並行性サニタイザ
KCSANは、適切な同期なしの共有データへの並行アクセス(データレース)を検出します:
# KCSAN用カーネル設定
CONFIG_KCSAN=y
CONFIG_KCSAN_STRICT=y # より積極的なチェック
CONFIG_KCSAN_WEAK_MEMORY=y # メモリ順序の問題を検出
11.5 比較表
| 機能 | KASAN | KMSAN | KCSAN |
|---|---|---|---|
| 検出対象 | メモリ安全性バグ | 未初期化メモリ | データレース |
| 発見するバグ | OOB、UAF、ダブルフリー | 情報漏洩 | 並行性バグ |
| コンパイラ | GCCまたはClang | Clangのみ | GCCまたはClang |
| メモリオーバーヘッド | カーネルメモリの1/8 | カーネルメモリの2倍 | 最小限 |
| CPUオーバーヘッド | 1.5-3倍の低速化 | 2-3倍の低速化 | 約2倍の低速化 |
| 本番使用 | 不可(デバッグ専用) | 不可(デバッグ専用) | 不可(デバッグ専用) |
12. ロックダウンモード
12.1 概要
カーネルロックダウンは、rootユーザでさえ実行中のカーネルに対して行える操作を制限するセキュリティ機能です。rootがランタイムでカーネルを変更することを防止し、rootが侵害された場合でもシステムの整合性を維持するために不可欠です。
12.2 ロックダウンレベル
┌──────────────────────────────────────────────────────┐
│ ロックダウンレベル: │
│ │
│ レベル0: none(無効) │
│ → 制限なし │
│ → rootはカーネルに対して何でもできる │
│ │
│ レベル1: integrity(整合性) │
│ → 署名されていないカーネル変更を防止 │
│ → 署名されていないモジュールロードをブロック │
│ → /dev/memと/dev/kmemアクセスをブロック │
│ → 署名されていないイメージのkexecをブロック │
│ → ハイバネーションをブロック(イメージが改変可能) │
│ → debugfsの書き込みアクセスをブロック │
│ │
│ レベル2: confidentiality(機密性) │
│ → integrityのすべてに加えて: │
│ → /proc/kcoreアクセスをブロック │
│ → /dev/portアクセスをブロック │
│ → eBPFのカーネルメモリアクセスをブロック │
│ → perfのカーネルデータアクセスをブロック │
│ → raw I/Oポートアクセスをブロック │
│ → カーネルシンボルアドレスの読み取りを防止 │
└──────────────────────────────────────────────────────┘
12.3 設定
# カーネル設定
CONFIG_SECURITY_LOCKDOWN_LSM=y
CONFIG_SECURITY_LOCKDOWN_LSM_EARLY=y # init前に有効化
# ブートパラメータ
GRUB_CMDLINE_LINUX="lockdown=integrity" # レベル1
GRUB_CMDLINE_LINUX="lockdown=confidentiality" # レベル2
GRUB_CMDLINE_LINUX="lockdown=none" # 無効
# ランタイムで有効化(増加のみ可能、減少は不可)
echo integrity > /sys/kernel/security/lockdown
echo confidentiality > /sys/kernel/security/lockdown
# リブートなしでは"none"に戻せない
12.4 検証方法
# ロックダウン状態を確認
cat /sys/kernel/security/lockdown
# [none] integrity confidentiality
# 括弧で囲まれた値が現在のレベル
# セキュアブートがロックダウンをトリガーしたか確認
dmesg | grep -i "lockdown"
# "Kernel is locked down from EFI Secure Boot mode"
# セキュアブート状態
mokutil --sb-state
# "SecureBoot enabled" → ロックダウンが自動的に"integrity"に設定
13. 整合性測定アーキテクチャ(IMA)
13.1 概要
IMA(Integrity Measurement Architecture)は、ファイルがアクセスされる際にハッシュ計算(測定)を行い、ファイルが変更されていないか(偶発的または悪意ある変更かを問わず)を検出するカーネルサブシステムです。IMAはファイルの測定、検証、監査を行い、システムの整合性を維持します。
13.2 IMAコンポーネント
┌──────────────────────────────────────────────────────┐
│ IMAサブシステム │
│ │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ 測定 │ │ 検証 │ │ 監査 │ │
│ │ (Measure) │ │(Appraise) │ │ (Audit) │ │
│ │ │ │ │ │ │ │
│ │ファイルを │ │アクセスを │ │ファイル │ │
│ │ハッシュし │ │許可する前 │ │アクセスを │ │
│ │TPM PCR │ │に署名を │ │監査ログに │ │
│ │レジスタを │ │検証 │ │記録 │ │
│ │拡張 │ │ │ │ │ │
│ └────────────┘ └────────────┘ └────────────┘ │
│ │
│ Measure: ファイルハッシュを記録(検出) │
│ Appraise: ファイル整合性を強制(防止) │
│ Audit: 整合性イベントをログ(可視性) │
└──────────────────────────────────────────────────────┘
13.3 カーネル設定
# コアIMA設定
CONFIG_INTEGRITY=y
CONFIG_IMA=y
CONFIG_IMA_MEASURE_PCR_IDX=10 # 拡張するTPM PCRレジスタ
CONFIG_IMA_LSM_RULES=y # LSMベースのIMAルールを許可
CONFIG_IMA_DEFAULT_HASH_SHA256=y # SHA-256を使用(推奨)
# IMA Appraisal(整合性の強制)
CONFIG_IMA_APPRAISE=y
CONFIG_IMA_APPRAISE_REQUIRE_FIRMWARE_SIGS=y
CONFIG_IMA_APPRAISE_REQUIRE_KEXEC_SIGS=y
CONFIG_IMA_APPRAISE_REQUIRE_MODULE_SIGS=y
# EVM(Extended Verification Module)— ファイルメタデータの保護
CONFIG_EVM=y
13.4 IMAポリシー設定
# IMAブートパラメータ
GRUB_CMDLINE_LINUX="ima_policy=tcb" # Trusted Computing Baseポリシー
GRUB_CMDLINE_LINUX="ima_policy=appraise_tcb" # Appraise + TCB
GRUB_CMDLINE_LINUX="ima_appraise=enforce" # 強制モード
GRUB_CMDLINE_LINUX="ima_appraise=fix" # 修正モード(初期セットアップ)
GRUB_CMDLINE_LINUX="ima_appraise=log" # 違反のみログ
GRUB_CMDLINE_LINUX="ima_hash=sha256" # ハッシュアルゴリズム
# カスタムIMAポリシー
cat > /etc/ima/ima-policy.conf << 'EOF'
# 実行されるすべてのファイルを測定
measure func=BPRM_CHECK
measure func=FILE_MMAP mask=MAY_EXEC
measure func=MODULE_CHECK
measure func=FIRMWARE_CHECK
# 実行されるすべてのファイルを検証
appraise func=BPRM_CHECK fowner=0
appraise func=MODULE_CHECK appraise_type=imasig
appraise func=FIRMWARE_CHECK appraise_type=imasig
# rootによるファイルオープンを監査
audit func=FILE_CHECK mask=MAY_READ uid=0
EOF
13.5 IMA用ファイル署名
# IMA署名鍵の生成
openssl genrsa -out /etc/keys/ima-privkey.pem 2048
openssl rsa -in /etc/keys/ima-privkey.pem -pubout \
-out /etc/keys/ima-pubkey.pem
# IMA用にファイルを署名
evmctl ima_sign --key /etc/keys/ima-privkey.pem /usr/bin/myapp
# IMA署名の検証
evmctl ima_verify --key /etc/keys/ima-pubkey.pem /usr/bin/myapp
# IMA測定ログの表示
cat /sys/kernel/security/ima/ascii_runtime_measurements
# IMA違反の確認
cat /sys/kernel/security/ima/violations
14. dm-verityとdm-integrity
14.1 dm-verity概要
dm-verityは、暗号化ハッシュツリー(マークルツリー)を使用してブロックデバイスの透過的な整合性チェックを提供するdevice-mapperターゲットです。Android、ChromeOS、コンテナ最適化オペレーティングシステムで広く使用され、読み取り専用ファイルシステムの整合性を保証します。
14.2 dm-verityの動作原理
マークルツリー構造:
┌──────────┐
│ルートハッシュ│ ← 信頼済み(ブートパラメータ
│(署名済み)│ または署名パーティションに格納)
└────┬─────┘
┌─────┴─────┐
┌────┴───┐ ┌────┴───┐
│Hash 0-1│ │Hash 2-3│ ← 内部ノード
└───┬────┘ └───┬────┘
┌──────┴──┐ ┌────┴────┐
┌───┴──┐ ┌───┴──┐ ┌───┴──┐ ┌───┴──┐
│Hash 0│ │Hash 1│ │Hash 2│ │Hash 3│ ← リーフノード
└───┬──┘ └───┬──┘ └───┬──┘ └───┬──┘
│ │ │ │
┌───┴──┐ ┌───┴──┐ ┌───┴──┐ ┌───┴──┐
│Data 0│ │Data 1│ │Data 2│ │Data 3│ ← 実際のディスクブロック
└──────┘ └──────┘ └──────┘ └──────┘
ブロックN読み取り時:
1. ブロックNのハッシュを計算
2. リーフハッシュNと照合
3. 親ノードのハッシュを計算
4. ルートハッシュまで検証
5. 不一致がある場合 → I/Oエラー(ブロック改ざん検出!)
14.3 dm-verityのセットアップ
# 必要なツールのインストール
sudo apt-get install cryptsetup # または yum install cryptsetup
# ステップ1: デバイスのハッシュツリーを作成
veritysetup format /dev/sdb1 /dev/sdb2
# /dev/sdb1 = データデバイス(保護するファイルシステム)
# /dev/sdb2 = ハッシュデバイス(マークルツリーを格納)
# 出力にルートハッシュが含まれる — 保存すること!
# ステップ2: verityデバイスをアクティベート
veritysetup open /dev/sdb1 verified-root /dev/sdb2 \
4a4e5f1c3b2d... # ステップ1のルートハッシュ
# ステップ3: 検証済みファイルシステムをマウント
mount -o ro /dev/mapper/verified-root /mnt/verified
# ステップ4: セットアップを検証
veritysetup status verified-root
14.4 dm-integrity
dm-integrityはブロックデバイスに対してセクターごとの整合性タグ(チェックサム)を提供し、サイレントデータ破壊から保護します:
# 整合性保護されたデバイスの作成
integritysetup format --integrity sha256 /dev/sdc1
# 整合性デバイスのオープン
integritysetup open /dev/sdc1 integrity-dev
# ファイルシステムの作成
mkfs.ext4 /dev/mapper/integrity-dev
mount /dev/mapper/integrity-dev /mnt/integrity
# dm-cryptと組み合わせて認証付き暗号化
# (整合性付きLUKS2)
cryptsetup luksFormat --type luks2 \
--integrity hmac-sha256 \
/dev/sdc1
15. セキュアブートとUEFI
15.1 概要
UEFIセキュアブートは、暗号的に署名され信頼されたソフトウェアのみがブートプロセス中に実行できることを保証するセキュリティ標準です。ファームウェアからブートローダー、カーネルまでの信頼のチェーンを確立し、ブートキットやルートキットが最初期段階でロードされることを防止します。
15.2 信頼のチェーン
┌─────────────────────────────────────────────────────────┐
│ UEFIセキュアブート │
│ 信頼のチェーン │
│ │
│ ┌──────────────┐ │
│ │Platform Key │ PK — ハードウェアベンダーが所有 │
│ │ (PK) │ 他のすべての鍵を制御 │
│ └──────┬───────┘ │
│ │ 署名 │
│ ┌──────▼───────┐ │
│ │ Key Exchange │ KEK — Microsoft、Canonical等 │
│ │ Key (KEK) │ dbとdbxを変更可能 │
│ └──────┬───────┘ │
│ │ 署名 │
│ ┌──────▼───────┐ │
│ │ 署名 │ db — 許可されたブートソフトウェア │
│ │データベース │ 証明書/ハッシュを含む │
│ │ (db) │ │
│ └──────┬───────┘ │
│ │ 検証 │
│ ┌──────▼───────────────────────────────────────┐ │
│ │ UEFIファームウェアが検証: │ │
│ │ 1. ブートローダー(GRUB/shim) ← dbで署名 │ │
│ │ 2. カーネル(vmlinuz) ← db/MOKで署名 │ │
│ │ 3. カーネルモジュール ← カーネル鍵で署名 │ │
│ │ 4. initramfs ← IMAで検証 │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ dbx = 失効データベース(ブロックされた署名) │
│ MOK = Machine Owner Key(ユーザ登録鍵) │
└─────────────────────────────────────────────────────────┘
15.3 セキュアブートの状態管理
# セキュアブートの状態確認
mokutil --sb-state
# SecureBoot enabled
# bootctl経由で確認(systemd-boot)
bootctl status
# 登録済み鍵の一覧
mokutil --list-enrolled
# セキュアブートデータベースの確認
efi-readvar -v PK # Platform Key
efi-readvar -v KEK # Key Exchange Keys
efi-readvar -v db # 許可された署名
efi-readvar -v dbx # 失効した署名
15.4 カスタム鍵の登録(MOK)
# カスタムモジュール署名用のMachine Owner Keyを生成
openssl req -new -x509 -newkey rsa:2048 \
-keyout /root/mok-signing-key.priv \
-outform DER -out /root/mok-signing-key.der \
-nodes -days 36500 \
-subj "/CN=My Machine Owner Key/"
# MOKデータベースに鍵をインポート
mokutil --import /root/mok-signing-key.der
# パスワードを入力(次回リブート時に必要)
# リブートしてMOK登録プロンプトに従う
# shimブートローダーが青い画面を表示し、鍵登録の確認を求める
16. カーネルモジュール署名
16.1 概要
カーネルモジュール署名は、信頼された鍵で署名されたモジュールのみがカーネルにロードできることを保証します。root権限を持っていても、悪意あるカーネルモジュール(ルートキット)のロードを防止します。
16.2 カーネル設定
# モジュール署名設定
CONFIG_MODULE_SIG=y # モジュール署名検証を有効化
CONFIG_MODULE_SIG_FORCE=y # 署名されていないモジュールを拒否(推奨)
CONFIG_MODULE_SIG_ALL=y # ビルド時にすべてのモジュールを署名
CONFIG_MODULE_SIG_SHA256=y # 署名にSHA-256を使用
CONFIG_MODULE_SIG_KEY="certs/signing_key.pem" # 署名鍵パス
16.3 モジュールの署名と検証
# モジュールを手動で署名
/usr/src/kernels/$(uname -r)/scripts/sign-file \
sha256 \
/path/to/signing_key.pem \
/path/to/signing_cert.der \
/path/to/module.ko
# モジュール署名の検証
modinfo /path/to/module.ko | grep sig
# sig_hashalgo: sha256
# 署名されているか確認
modinfo -F sig_hashalgo /path/to/module.ko
# "sha256" = 署名済み、空 = 未署名
16.4 ランタイムモジュールロード制限
# ランタイムでモジュールロードを完全に無効化
echo 1 > /proc/sys/kernel/modules_disabled
# 警告: リブートまで不可逆!
# モジュールブラックリスト(特定モジュールのロード防止)
cat > /etc/modprobe.d/blacklist-insecure.conf << 'EOF'
# 一般的でないファイルシステムを無効化(攻撃面の削減)
install cramfs /bin/false
install freevxfs /bin/false
install jffs2 /bin/false
install hfs /bin/false
install hfsplus /bin/false
install squashfs /bin/false
install udf /bin/false
# 一般的でないネットワークプロトコルを無効化
install dccp /bin/false
install sctp /bin/false
install rds /bin/false
install tipc /bin/false
# USBストレージを無効化(不要な場合)
install usb-storage /bin/false
# Firewireを無効化(不要な場合)
install firewire-core /bin/false
install firewire-ohci /bin/false
EOF
17. sysctlセキュリティパラメータ
17.1 概要
sysctlインターフェースはカーネルパラメータのランタイムチューニングを可能にします。多くのパラメータがシステムのセキュリティ態勢に直接影響します。このセクションでは、最も重要なセキュリティ関連sysctlパラメータをカテゴリ別に解説します。
17.2 ネットワークセキュリティパラメータ
# /etc/sysctl.d/80-network-security.conf
# ─── IPフォワーディング ───
# IPフォワーディングを無効化(ルータ/ファイアウォールでない場合)
net.ipv4.ip_forward = 0
net.ipv6.conf.all.forwarding = 0
# ─── ソースルーティング ───
# ソースルーティングを無効化(IPスプーフィング攻撃を防止)
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0
# ─── ICMPリダイレクト ───
# ICMPリダイレクトを受け入れない(MITM攻撃を防止)
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
# ICMPリダイレクトを送信しない
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
# ICMPブロードキャスト要求を無視(Smurf攻撃防止)
net.ipv4.icmp_echo_ignore_broadcasts = 1
# 不正なICMPエラー応答を無視
net.ipv4.icmp_ignore_bogus_error_responses = 1
# ─── リバースパスフィルタリング ───
# 厳密なリバースパスフィルタリングを有効化(アンチスプーフィング)
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# ─── SYNフラッド防御 ───
# TCP SYNクッキーを有効化(SYNフラッド緩和)
net.ipv4.tcp_syncookies = 1
# ─── ルータアドバタイズメント(IPv6) ───
# ルータアドバタイズメントを受け入れない
net.ipv6.conf.all.accept_ra = 0
net.ipv6.conf.default.accept_ra = 0
17.3 カーネルセキュリティパラメータ
# /etc/sysctl.d/80-kernel-security.conf
# ─── カーネルアドレス保護 ───
# カーネルポインタ表示を制限
kernel.kptr_restrict = 2 # すべてのユーザから隠す
# dmesgアクセスを制限
kernel.dmesg_restrict = 1 # rootのみdmesgを読める
# ─── プロセスセキュリティ ───
# ptraceアクセスを制限
kernel.yama.ptrace_scope = 2 # 0=全員, 1=親のみ, 2=管理者のみ, 3=なし
# コアダンプアクセスを制限
fs.suid_dumpable = 0 # setuidプログラムのコアダンプなし
# ─── パフォーマンス監視 ───
# perf_eventアクセスを制限
kernel.perf_event_paranoid = 3 # perfをrootに制限
# ─── カーネルパニック ───
# カーネルパニック後の自動リブート(秒)
kernel.panic = 10
# oopsでパニック(セキュリティ上oopsをパニックとして扱う)
kernel.panic_on_oops = 1
# ─── ランダム化 ───
# ユーザ空間の完全なASLRを有効化
kernel.randomize_va_space = 2 # 0=無効, 1=スタック, 2=完全
# ─── シンボリックリンク/ハードリンク保護 ───
# ワールドライタブルディレクトリでのシンボリックリンク攻撃を防止
fs.protected_symlinks = 1
fs.protected_hardlinks = 1
# スティッキーディレクトリでのFIFO/通常ファイル攻撃を防止
fs.protected_fifos = 2
fs.protected_regular = 2
# ─── SysRq ───
# マジックSysRqキーを無効化
kernel.sysrq = 0 # 0=無効, 176=安全なサブセット
# ─── BPF ───
# BPFを特権ユーザに制限
kernel.unprivileged_bpf_disabled = 1
# BPF JITハードニングを有効化
net.core.bpf_jit_harden = 2
# ─── ユーザ名前空間 ───
# 非特権ユーザ名前空間を制限(多くの脆弱性を防止)
kernel.unprivileged_userns_clone = 0 # Debian/Ubuntu
# または
user.max_user_namespaces = 0 # RHEL/CentOS
# ─── Kexec ───
# kexecを無効化(ランタイムでの新カーネルロードを防止)
kernel.kexec_load_disabled = 1
17.4 すべての設定を適用・検証
# すべてのsysctl設定を適用
sudo sysctl --system
# 包括的なsysctlセキュリティ監査
#!/bin/bash
echo "=== sysctlセキュリティ監査 ==="
declare -A CHECKS=(
["kernel.kptr_restrict"]="2"
["kernel.dmesg_restrict"]="1"
["kernel.yama.ptrace_scope"]="2"
["kernel.randomize_va_space"]="2"
["kernel.perf_event_paranoid"]="3"
["kernel.panic_on_oops"]="1"
["kernel.unprivileged_bpf_disabled"]="1"
["kernel.sysrq"]="0"
["net.ipv4.ip_forward"]="0"
["net.ipv4.conf.all.accept_source_route"]="0"
["net.ipv4.conf.all.accept_redirects"]="0"
["net.ipv4.conf.all.rp_filter"]="1"
["net.ipv4.tcp_syncookies"]="1"
["fs.suid_dumpable"]="0"
["fs.protected_symlinks"]="1"
["fs.protected_hardlinks"]="1"
)
pass=0
fail=0
for key in "${!CHECKS[@]}"; do
expected="${CHECKS[$key]}"
actual=$(sysctl -n "$key" 2>/dev/null || echo "N/A")
if [ "$actual" = "$expected" ]; then
printf " [合格] %-45s = %s\n" "$key" "$actual"
((pass++))
else
printf " [不合格] %-45s = %s (期待値: %s)\n" "$key" "$actual" "$expected"
((fail++))
fi
done
echo ""
echo "結果: $pass 合格, $fail 不合格 / 合計 $((pass + fail)) チェック"
18. 本番環境向けハードニングチェックリスト
18.1 デプロイ前ハードニングチェックリスト
╔══════════════════════════════════════════════════════════════════════╗
║ LINUX カーネル ハードニング チェックリスト ║
║ 本番環境向け ║
╠══════════════════════════════════════════════════════════════════════╣
║ ║
║ ブートセキュリティ ║
║ ┌─┐ UEFIセキュアブート有効 ║
║ ┌─┐ ブートローダーパスワード設定(GRUB) ║
║ ┌─┐ カーネルイメージ署名済み ║
║ ┌─┐ ロックダウンモード = integrityまたはconfidentiality ║
║ ┌─┐ ルートファイルシステム整合性(dm-verityまたはIMA) ║
║ ║
║ メモリ保護 ║
║ ┌─┐ KASLR有効(cmdlineに"nokaslr"なし) ║
║ ┌─┐ KPTI有効(pti=onまたはauto) ║
║ ┌─┐ Stack Protector Strong有効 ║
║ ┌─┐ NXビット有効 ║
║ ┌─┐ 厳密W^X適用 ║
║ ┌─┐ ASLRレベル2(kernel.randomize_va_space = 2) ║
║ ┌─┐ mmap_min_addr >= 65536 ║
║ ║
║ 投機的実行 ║
║ ┌─┐ Spectre v1緩和済み ║
║ ┌─┐ Spectre v2緩和済み(retpolineまたはeIBRS) ║
║ ┌─┐ Meltdown緩和済み(KPTI) ║
║ ┌─┐ L1TF緩和済み ║
║ ┌─┐ MDS緩和済み ║
║ ┌─┐ CPUマイクロコード最新版に更新 ║
║ ║
║ システムコールフィルタリング ║
║ ┌─┐ サービスにSeccompプロファイル適用 ║
║ ┌─┐ Capability最小化(ALLをdrop、必要なもののみadd) ║
║ ┌─┐ 不要なsetuid/setgidバイナリなし ║
║ ┌─┐ サービスにno_new_privs設定 ║
║ ║
║ モジュールセキュリティ ║
║ ┌─┐ モジュール署名強制 ║
║ ┌─┐ 不要なモジュールをブラックリスト化 ║
║ ┌─┐ modules_disabled=1(ブート後、該当する場合) ║
║ ┌─┐ 一般的でないファイルシステム無効化 ║
║ ┌─┐ 一般的でないネットワークプロトコル無効化 ║
║ ║
║ ネットワークハードニング ║
║ ┌─┐ IPフォワーディング無効 ║
║ ┌─┐ ソースルーティング無効 ║
║ ┌─┐ ICMPリダイレクト無効 ║
║ ┌─┐ リバースパスフィルタリング有効 ║
║ ┌─┐ TCP SYNクッキー有効 ║
║ ┌─┐ IPv6ルータアドバタイズメント無効 ║
║ ║
║ 情報漏洩防止 ║
║ ┌─┐ kptr_restrict = 2 ║
║ ┌─┐ dmesg_restrict = 1 ║
║ ┌─┐ ptrace_scope >= 1 ║
║ ┌─┐ perf_event_paranoid >= 2 ║
║ ┌─┐ suid_dumpable = 0 ║
║ ┌─┐ 非特権BPF無効 ║
║ ┌─┐ 非特権ユーザ名前空間無効 ║
║ ║
║ 整合性と監査 ║
║ ┌─┐ IMAがappraiseポリシーで有効 ║
║ ┌─┐ auditデーモン稼働中 ║
║ ┌─┐ 重要ファイルの変更監視 ║
║ ┌─┐ 定期的な脆弱性スキャン(lynis、openscap) ║
║ ┌─┐ カーネルを最新安定版/LTSに更新 ║
║ ║
╚══════════════════════════════════════════════════════════════════════╝
18.2 自動ハードニングスクリプト
#!/bin/bash
# kernel_harden.sh — 本番環境向けカーネルハードニング適用
# rootで実行すること
set -euo pipefail
echo "=== Linuxカーネルハードニングスクリプト ==="
echo "日時: $(date)"
echo "カーネル: $(uname -r)"
echo ""
# ─── sysctlハードニング ───
cat > /etc/sysctl.d/99-hardening.conf << 'SYSCTL'
# === カーネルセキュリティ ===
kernel.kptr_restrict = 2
kernel.dmesg_restrict = 1
kernel.printk = 3 3 3 3
kernel.yama.ptrace_scope = 2
kernel.perf_event_paranoid = 3
kernel.panic = 10
kernel.panic_on_oops = 1
kernel.randomize_va_space = 2
kernel.sysrq = 0
kernel.unprivileged_bpf_disabled = 1
kernel.kexec_load_disabled = 1
fs.suid_dumpable = 0
fs.protected_symlinks = 1
fs.protected_hardlinks = 1
fs.protected_fifos = 2
fs.protected_regular = 2
vm.mmap_min_addr = 65536
# === ネットワークセキュリティ ===
net.ipv4.ip_forward = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.tcp_syncookies = 1
net.ipv4.conf.all.log_martians = 1
net.ipv6.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_ra = 0
# === BPFハードニング ===
net.core.bpf_jit_harden = 2
SYSCTL
sysctl --system > /dev/null 2>&1
echo "[+] sysctlハードニング適用完了"
# ─── モジュールブラックリスト ───
cat > /etc/modprobe.d/hardening-blacklist.conf << 'MODPROBE'
# 一般的でないファイルシステム
install cramfs /bin/false
install freevxfs /bin/false
install jffs2 /bin/false
install hfs /bin/false
install hfsplus /bin/false
install udf /bin/false
# 一般的でないネットワークプロトコル
install dccp /bin/false
install sctp /bin/false
install rds /bin/false
install tipc /bin/false
# Firewire
install firewire-core /bin/false
install firewire-ohci /bin/false
MODPROBE
echo "[+] モジュールブラックリスト設定完了"
# ─── ブートディレクトリのパーミッション強化 ───
chmod 700 /boot
chmod 600 /boot/grub2/grub.cfg 2>/dev/null || true
chmod 600 /boot/grub/grub.cfg 2>/dev/null || true
echo "[+] ブートディレクトリパーミッション強化完了"
echo ""
echo "=== ハードニング完了 ==="
echo "すべての変更を適用するためにリブートしてください。"
19. CISベンチマーク主要項目
19.1 概要
CIS(Center for Internet Security)はLinuxディストリビューション向けのハードニングベンチマークを公開しています。これらのベンチマークは、スコア付きおよびスコアなしの推奨事項として体系的な設定ガイダンスを提供します。
19.2 CISベンチマークのカテゴリ構造
CISベンチマーク構造(Linux):
┌──────────────────────────────────────────────────────┐
│ 1. 初期設定 │
│ 1.1 ファイルシステム設定 │
│ 1.2 ソフトウェアアップデート │
│ 1.3 ファイルシステム整合性チェック │
│ 1.4 セキュアブート設定 │
│ 1.5 追加プロセスハードニング │
│ 1.6 必須アクセス制御(SELinux/AppArmor) │
│ │
│ 3. ネットワーク設定 │
│ 3.1 ネットワークパラメータ(ホスト) │
│ 3.2 ネットワークパラメータ(ホスト&ルータ) │
│ 3.3 一般的でないネットワークプロトコル │
│ 3.4 ファイアウォール設定 │
│ │
│ 4. ロギングと監査 │
│ 4.1 システムアカウンティング設定 │
│ 4.2 ロギング設定 │
│ │
│ 5. アクセス、認証、認可 │
│ 5.1 時間ベースジョブスケジューラ設定 │
│ 5.2 SSHサーバ設定 │
│ 5.3 PAM設定 │
│ 5.4 ユーザアカウントと環境 │
└──────────────────────────────────────────────────────┘
19.3 CISレベル1 — カーネル関連項目
# ─── CIS 1.1.x: ファイルシステム設定 ───
# 1.1.1 未使用ファイルシステムの無効化
cat > /etc/modprobe.d/CIS-cramfs.conf << 'EOF'
install cramfs /bin/true
blacklist cramfs
EOF
# 1.1.2 /tmpが設定されていることを確認(別パーティションまたはtmpfs)
systemctl --now enable tmp.mount
# ─── CIS 1.4.x: セキュアブート設定 ───
# 1.4.1 ブートローダーパスワードの設定
# grub2-setpassword(RHEL)またはgrub-mkpasswd-pbkdf2(Ubuntu)
# 1.4.2 ブートローダー設定のパーミッション
chmod 600 /boot/grub2/grub.cfg
# ─── CIS 1.5.x: 追加プロセスハードニング ───
# 1.5.1 ASLR有効確認
sysctl -w kernel.randomize_va_space=2
# 1.5.4 コアダンプの制限
echo "* hard core 0" > /etc/security/limits.d/cis-core.conf
sysctl -w fs.suid_dumpable=0
19.4 CISレベル2 — ネットワークカーネルパラメータ
# ─── CIS 3.1.x: ネットワークパラメータ(ホスト) ───
sysctl -w net.ipv4.ip_forward=0
sysctl -w net.ipv6.conf.all.forwarding=0
sysctl -w net.ipv4.conf.all.send_redirects=0
sysctl -w net.ipv4.conf.default.send_redirects=0
# ─── CIS 3.2.x: ネットワークパラメータ(ホスト&ルータ) ───
sysctl -w net.ipv4.conf.all.accept_source_route=0
sysctl -w net.ipv4.conf.all.accept_redirects=0
sysctl -w net.ipv4.conf.all.secure_redirects=0
sysctl -w net.ipv4.conf.all.log_martians=1
sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=1
sysctl -w net.ipv4.icmp_ignore_bogus_error_responses=1
sysctl -w net.ipv4.conf.all.rp_filter=1
sysctl -w net.ipv4.tcp_syncookies=1
sysctl -w net.ipv6.conf.all.accept_ra=0
# ─── CIS 3.3.x: 一般的でないネットワークプロトコル ───
for proto in dccp sctp rds tipc; do
echo "install $proto /bin/true" > "/etc/modprobe.d/CIS-$proto.conf"
done
19.5 CISコンプライアンス検証スクリプト
#!/bin/bash
# cis_kernel_check.sh — CISカーネルハードニング項目の検証
echo "╔══════════════════════════════════════════╗"
echo "║ CISベンチマーク カーネル準拠チェック ║"
echo "╚══════════════════════════════════════════╝"
echo ""
pass=0; fail=0; warn=0
check() {
local desc="$1" param="$2" expected="$3"
local actual
actual=$(sysctl -n "$param" 2>/dev/null || echo "N/A")
if [ "$actual" = "$expected" ]; then
printf " [合格] %s = %s\n" "$desc" "$actual"
((pass++))
elif [ "$actual" = "N/A" ]; then
printf " [警告] %s: パラメータが見つかりません\n" "$desc"
((warn++))
else
printf " [不合格] %s = %s (期待値: %s)\n" "$desc" "$actual" "$expected"
((fail++))
fi
}
echo "--- 1.5 プロセスハードニング ---"
check "ASLR有効" "kernel.randomize_va_space" "2"
check "コアダンプ制限" "fs.suid_dumpable" "0"
echo ""
echo "--- 3.1 ネットワークパラメータ(ホスト) ---"
check "IPフォワーディング無効" "net.ipv4.ip_forward" "0"
check "リダイレクト送信無効" "net.ipv4.conf.all.send_redirects" "0"
echo ""
echo "--- 3.2 ネットワークパラメータ(ホスト+ルータ) ---"
check "ソースルート無効" "net.ipv4.conf.all.accept_source_route" "0"
check "ICMPリダイレクト無効" "net.ipv4.conf.all.accept_redirects" "0"
check "セキュアリダイレクト無効" "net.ipv4.conf.all.secure_redirects" "0"
check "マーシャンログ有効" "net.ipv4.conf.all.log_martians" "1"
check "ICMPブロードキャスト無視" "net.ipv4.icmp_echo_ignore_broadcasts" "1"
check "RPフィルタ有効" "net.ipv4.conf.all.rp_filter" "1"
check "SYNクッキー有効" "net.ipv4.tcp_syncookies" "1"
check "IPv6 RA無効" "net.ipv6.conf.all.accept_ra" "0"
echo ""
echo "--- カーネルセキュリティ ---"
check "kptr_restrict" "kernel.kptr_restrict" "2"
check "dmesg_restrict" "kernel.dmesg_restrict" "1"
check "Ptraceスコープ" "kernel.yama.ptrace_scope" "2"
check "非特権BPF無効" "kernel.unprivileged_bpf_disabled" "1"
echo ""
echo "═══════════════════════════════════════"
printf "結果: %d 合格, %d 不合格, %d 警告 (合計: %d)\n" \
"$pass" "$fail" "$warn" "$((pass + fail + warn))"
score=$(( (pass * 100) / (pass + fail + warn) ))
echo "コンプライアンススコア: ${score}%"
20. セキュリティ監査ツール
20.1 checksec — バイナリセキュリティ機能チェッカー
checksecはバイナリと実行中のカーネルのセキュリティ機能(RELRO、Stack Canary、NX、PIE、ASLR、Fortified Source)を検査します。
# checksecのインストール
sudo apt-get install checksec # Debian/Ubuntu
sudo yum install checksec # RHEL/CentOS
# 単一バイナリをチェック
checksec --file=/usr/bin/ssh
# RELRO STACK CANARY NX PIE ...
# Full RELRO Canary found NX enabled PIE enabled ...
# ディレクトリ内の全バイナリをチェック
checksec --dir=/usr/bin/
# 実行中のカーネルをチェック
checksec --kernel
# 実行中のプロセスをチェック
checksec --proc=<PID>
# すべてのプロセスをチェック
checksec --proc-all
# 各種フォーマットで出力
checksec --file=/usr/bin/ssh --format=json
checksec出力フィールドの意味:
┌──────────────┬──────────────────────────────────────────┐
│ フィールド │ 説明 │
├──────────────┼──────────────────────────────────────────┤
│ RELRO │ 読み取り専用リロケーション(Full = 最良) │
│ STACK CANARY │ スタックバッファオーバーフロー検出 │
│ NX │ No-Executeビット(DEP) │
│ PIE │ 位置独立実行可能ファイル(ASLR用) │
│ RPATH │ ハードコードされたライブラリパス(No=最良) │
│ RUNPATH │ ランタイムライブラリパス(No = 最良) │
│ Symbols │ デバッグシンボル削除済み(No Symbols=最良) │
│ FORTIFY │ libcバッファオーバーフローチェック │
└──────────────┴──────────────────────────────────────────┘
20.2 Lynis — セキュリティ監査ツール
Lynisは、Linuxシステムの包括的なセキュリティスキャンを実行するセキュリティ監査ツールです。
# Lynisのインストール
sudo apt-get install lynis
# またはGitから
git clone https://github.com/CISOfy/lynis.git
# 完全なシステム監査を実行
sudo lynis audit system
# 特定のテストカテゴリを実行
sudo lynis audit system --tests-from-group kernel
sudo lynis audit system --tests-from-group networking
# 警告と提案のみ表示
sudo lynis show warnings
sudo lynis show suggestions
# Lynisカーネル関連チェック:
# [KRNL-5830] カーネルモジュール可用性チェック
# [KRNL-5677] CPU脆弱性緩和策チェック
# [KRNL-5820] sysctlカーネルパラメータチェック
# [KRNL-5788] ASLRが有効かチェック
20.3 OpenSCAP — SCAPベースのコンプライアンススキャナ
OpenSCAPは、自動化されたセキュリティコンプライアンスチェック用のNIST認定SCAPツールキットです。
# OpenSCAPのインストール
sudo yum install openscap-scanner scap-security-guide # RHEL/CentOS
sudo apt-get install libopenscap8 ssg-debian # Debian/Ubuntu
# CISレベル2コンプライアンススキャン
sudo oscap xccdf eval \
--profile xccdf_org.ssgproject.content_profile_cis_server_l2 \
--results /tmp/cis-results.xml \
--report /tmp/cis-report.html \
/usr/share/xml/scap/ssg/content/ssg-rhel8-ds.xml
# STIGコンプライアンススキャン
sudo oscap xccdf eval \
--profile xccdf_org.ssgproject.content_profile_stig \
--results /tmp/stig-results.xml \
--report /tmp/stig-report.html \
/usr/share/xml/scap/ssg/content/ssg-rhel8-ds.xml
# 修正スクリプト生成(Ansible)
sudo oscap xccdf generate fix \
--fix-type ansible \
--profile xccdf_org.ssgproject.content_profile_cis_server_l2 \
--output /tmp/cis-remediation.yml \
/usr/share/xml/scap/ssg/content/ssg-rhel8-ds.xml
# 修正スクリプト生成(Bash)
sudo oscap xccdf generate fix \
--fix-type bash \
--profile xccdf_org.ssgproject.content_profile_cis_server_l2 \
--output /tmp/cis-remediation.sh \
/usr/share/xml/scap/ssg/content/ssg-rhel8-ds.xml
20.4 セキュリティ監査ツール比較
| 機能 | checksec | Lynis | OpenSCAP |
|---|---|---|---|
| 焦点 | バイナリハードニング | システム全体監査 | コンプライアンスチェック |
| 準拠規格 | なし(ベストプラクティス) | カスタム + CIS | CIS、STIG、PCI-DSS |
| 出力形式 | テキスト、JSON、CSV | テキスト、レポートファイル | XML、HTML、Ansible |
| 修正 | なし | 提案 | Ansible/Bashスクリプト |
| 認証 | なし | なし | NIST認定 |
| カーネルチェック | 基本 | 包括的 | 規格固有 |
| 速度 | 高速(秒) | 中程度(分) | 中程度(分) |
20.5 統合セキュリティ監査スクリプト
#!/bin/bash
# full_security_audit.sh — 包括的カーネルセキュリティ監査
echo "=================================================="
echo " Linuxカーネルセキュリティ監査"
echo " 日時: $(date)"
echo " カーネル: $(uname -r)"
echo " ホスト名: $(hostname)"
echo "=================================================="
# 1. CPU脆弱性ステータス
echo ""
echo "=== CPU脆弱性緩和策 ==="
for vuln in /sys/devices/system/cpu/vulnerabilities/*; do
name=$(basename "$vuln")
status=$(cat "$vuln" 2>/dev/null || echo "N/A")
printf " %-25s %s\n" "$name:" "$status"
done
# 2. カーネルセキュリティ機能
echo ""
echo "=== カーネルセキュリティ設定 ==="
KCONFIG="/boot/config-$(uname -r)"
if [ -f "$KCONFIG" ]; then
for opt in CONFIG_RANDOMIZE_BASE CONFIG_PAGE_TABLE_ISOLATION \
CONFIG_RETPOLINE CONFIG_STACKPROTECTOR_STRONG \
CONFIG_STRICT_KERNEL_RWX CONFIG_STRICT_MODULE_RWX \
CONFIG_SECURITY_LOCKDOWN_LSM CONFIG_MODULE_SIG \
CONFIG_MODULE_SIG_FORCE CONFIG_SECCOMP \
CONFIG_SECCOMP_FILTER CONFIG_IMA CONFIG_EVM; do
val=$(grep "^$opt=" "$KCONFIG" 2>/dev/null || echo "未設定")
printf " %-45s %s\n" "$opt" "$val"
done
fi
# 3. ロックダウンとセキュアブート
echo ""
echo "=== ロックダウン & セキュアブート ==="
echo " ロックダウン: $(cat /sys/kernel/security/lockdown 2>/dev/null || echo 'N/A')"
echo " セキュアブート: $(mokutil --sb-state 2>/dev/null || echo 'N/A')"
# 4. 特権バイナリ
echo ""
echo "=== 特権バイナリ ==="
echo " setuidバイナリ数: $(find / -perm -4000 -type f 2>/dev/null | wc -l)"
echo " Capabilityバイナリ数: $(getcap -r / 2>/dev/null | wc -l)"
# 5. ロード済みカーネルモジュール
echo ""
echo "=== ロード済みカーネルモジュール ==="
echo " 合計モジュール数: $(lsmod | wc -l)"
echo " 未署名モジュール:"
for mod in $(lsmod | awk 'NR>1 {print $1}'); do
sig=$(modinfo -F sig_hashalgo "$mod" 2>/dev/null)
if [ -z "$sig" ]; then
echo " 未署名: $mod"
fi
done
echo ""
echo "=== 監査完了 ==="
21. まとめ
Linuxカーネルハードニングは、ブートからランタイムまでシステムのライフサイクルのすべての段階で注意を要する多層的な規律です。本ガイドの主要な要点は以下の通りです:
-
多層防御 — 単一の機能では不十分です。ハードウェア緩和策(NX、CET)、ブート時保護(セキュアブート、IMA)、カーネル機能(KASLR、KPTI、CFI)、ランタイム制限(seccomp、capabilities、sysctl)を組み合わせてください。
-
攻撃面の最小化 — 未使用のカーネルモジュールを無効化し、seccompでシステムコールを制限し、capabilitiesを最小化し、カーネルインターフェースをロックダウンしてください。
-
検証と監査 — checksec、lynis、OpenSCAPなどのツールを使用してハードニングを定期的に検証してください。CI/CDパイプラインでコンプライアンスチェックを自動化してください。
-
常に最新に — カーネル、CPUマイクロコード、ファームウェアを最新の状態に保ってください。新しい脆弱性は定期的に発見され、緩和策は継続的に改善されています。
-
セキュリティとパフォーマンスのバランス — ほとんどのハードニング機能のパフォーマンスへの影響は最小限です(< 5%)。例外(PCIDなしのKPTI、レガシーIBRS)はハードウェアアップグレードで最適化できます。
-
ステージング環境でテスト — ハードニング変更を本番環境にデプロイする前に、必ずステージング環境でテストしてください。一部の機能(厳密なロックダウン、モジュール署名強制など)は設定を誤るとブート失敗を引き起こす可能性があります。
22. 参考文献
標準規格とベンチマーク
- CIS Benchmarks for Linux: https://www.cisecurity.org/benchmark/distribution_independent_linux
- NIST National Checklist Program: https://nvd.nist.gov/ncp/repository
- DISA STIGs for Linux: https://public.cyber.mil/stigs/
カーネルドキュメント
- Linux Kernel Security Subsystem: https://www.kernel.org/doc/html/latest/security/
- Kernel Self Protection Project: https://kernsec.org/wiki/index.php/Kernel_Self_Protection_Project
- Kernel Lockdown: https://man7.org/linux/man-pages/man7/kernel_lockdown.7.html
脆弱性データベース
- CVE Details: https://www.cvedetails.com/product/47/Linux-Linux-Kernel.html
- kernel.org Security: https://www.kernel.org/category/releases.html
ツール
- checksec: https://github.com/slimm609/checksec.sh
- Lynis: https://cisofy.com/lynis/
- OpenSCAP: https://www.open-scap.org/
- libseccomp: https://github.com/seccomp/libseccomp
CPU脆弱性緩和策
- Intel投機的実行サイドチャネル緩和策: https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/
- カーネルドキュメント(ハードウェア脆弱性): https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/
本ドキュメントはセキュリティ専門家およびシステム管理者を対象としています。ハードニング変更はデプロイ前に必ず非本番環境でテストしてください。本ガイドの情報は2026年4月時点のLinuxカーネルセキュリティの状態を反映しています。