カーネルモジュール署名とLockdownモード
root権限を奪われてもカーネルの改ざんを防げます。モジュール署名検証とLockdownモードが塞ぐ昇格経路、セキュアブートとの連携までを内部動作から解説。
- 1.モジュール署名はロード時にPKCS#7署名を鍵で検証し、未署名・改ざん済みモジュールの挿入を拒否する。鍵は`.builtin_trusted_keys`等のキーリングで管理される。
- 2.Lockdownモードはrootであってもカーネルメモリの読み書き・任意コード注入を禁じるLSMで、integrityとconfidentialityの2段階がある。
- 3.セキュアブート有効時はLockdownが自動でintegrityへ昇格し、/dev/kmemやkexec任意イメージなど十数個の危険インタフェースを一括封鎖する。confidentialityへは通常、明示設定が必要。
なぜ「rootを取られた後」を考える必要があるのか
Linuxケーパビリティは、rootの全特権を約40の機能単位に分解しますが、CAP_SYS_MODULE や CAP_SYS_RAWIO を持つプロセスは依然として強力です。カーネルモジュールを1本ロードできれば、任意のカーネルコードを実行できる。/dev/mem や /dev/kmem を叩ければ、カーネルのメモリを直接書き換えられる。伝統的なUNIXモデルでは「rootを取られたら終わり」でした。root自身がカーネルと等価の信頼を持つ設計だからです。
モジュール署名検証とLockdownモードは、この前提を崩します。root権限を持つ攻撃者やマルウェアであっても、カーネル自体の完全性・機密性は侵害できない よう、境界をユーザー空間とカーネル空間の間ではなく、特権ユーザー空間とカーネルの間 に引き直す仕組みです。カーネルモードとユーザーモードの権限境界を、rootの内側にもう一段刻み直す試みだと考えると理解しやすくなります。
モジュール署名検証の仕組み
カーネルモジュール(.ko ファイル)は、ビルド時に scripts/sign-file で末尾に PKCS#7形式の署名 を追加できます。署名対象はモジュール本体のバイナリで、署名データ自体は本体の後ろに追記され、末尾のマジック文字列 ~Module signature appended~ で存在が示されます。
[ELFセクション本体] [署名情報構造体] [証明書/署名データ] "~Module signature appended~"
insmod/modprobe 相当の init_module(2)/finit_module(2) システムコールが呼ばれると、カーネルは次の手順で検証します。
- モジュール末尾のマジック文字列を見つけ、署名の有無を判定する。
- 署名情報構造体からアルゴリズム(RSA/ECDSAなど)とハッシュ方式を読み取る。
- モジュール本体のハッシュを計算し、添付された証明書の公開鍵で署名を検証する。
- 証明書が カーネルの信頼キーリング(
.builtin_trusted_keys、および.secondary_trusted_keys)に登録された鍵、またはその鍵で発行されたものかを確認する。
信頼キーリングに載る鍵は、ビルド時に組み込まれる自己署名鍵か、MOK(Machine Owner Key、セキュアブートのユーザー登録鍵)経由でUEFI変数から読み込まれた鍵です。検証に失敗すると、CONFIG_MODULE_SIG_FORCE が有効な環境ではロード自体が拒否されます。無効な環境では警告ログのみで通ってしまうため、検証の有無と強制の有無は別設定 である点に注意が必要です。
ディストリビュータがビルドするカーネルは、そのディストリビュータ自身の鍵で標準モジュールに署名します。自前でビルドしたモジュール(ドライバの独自ビルドなど)を通したい場合、MOK登録(mokutil --import)で自分の鍵をUEFI変数経由でカーネルの信頼キーリングに追加する運用になります。これはブートチェーンの内部で見たセキュアブートのMOK機構と同一の鍵基盤を流用しています。
Lockdownモードが塞ぐ昇格経路
モジュール署名だけでは不十分です。未署名モジュールのロードを禁じても、root権限があれば /dev/kmem 経由でカーネルメモリを直接書き換え、署名検証そのものを迂回できる からです。この抜け道を体系的に塞ぐのが Lockdown LSM です。
LockdownはLSMフックとして実装され、有効化すると次のような操作を一括して禁止します。
| 塞がれる経路 | 通常時の用途 | Lockdown下の挙動 |
|---|---|---|
| /dev/mem, /dev/kmem, /dev/port | デバイスやメモリの直接デバッグ | オープン自体を拒否 |
| kexec_load(署名なしイメージ) | 再起動なしのカーネル差し替え | 署名済みイメージのみ許可 |
| ヒバネーション(休止状態) | ディスクへのメモリイメージ保存 | 無効化(復帰時の改ざんを防止) |
| ioperm/iopl | I/Oポートへの直接アクセス | 拒否 |
| 未署名カーネルモジュール | 自作/検証なしドライバの実験 | ロード自体を拒否 |
| ptraceによるカーネルアドレス取得 | デバッガのメモリ参照 | 機密情報の取得を制限 |
| /proc/kcore, /sys/kernel/debug配下 | カーネルメモリのダンプ・デバッグ | 読み取り制限(confidentialityで強化) |
| MSRの直接書き込み | CPUレジスタの低レベル操作 | 拒否 |
これらは個別に見れば「rootなら当然できて然るべき」操作に見えます。しかし共通するのは、すべてがカーネルコード実行やカーネルメモリ改ざんに直結する 点です。CAP_SYS_MODULE を封じても /dev/mem を書けば同じ結果に到達できてしまうため、Lockdownは「rootからカーネルへ到達できる経路」を一つずつ列挙して塞ぐアプローチを取ります。eBPFのような機能もカーネル内実行の一種であるため、Lockdown下では危険なヘルパー関数の利用が制限されます。
integrity と confidentiality の2段階
Lockdownには強度の異なる2つのモードがあります。
| モード | 目的 | 代表的な制限 |
|---|---|---|
| integrity | カーネルコード・データの改ざん防止 | 未署名モジュール拒否、/dev/mem書き込み拒否、kexec未署名拒否 |
| confidentiality | integrityに加え情報漏洩も防止 | /dev/mem読み取りも拒否、/proc/kcore無効化、ヒバネーション無効化 |
integrity は「カーネルを書き換えさせない」ことに主眼を置きます。一方 confidentiality はさらに厳しく、「カーネルメモリの中身を読み取らせない」ことまで含みます。デバッグ用途で /dev/mem を読み取り専用で使う運用はintegrityでは許容されますが、confidentialityでは鍵材料などの漏洩経路になり得るため禁止されます。
セキュアブートが有効なシステムでLinuxカーネルが起動すると、多くの構成では自動的に Lockdownがintegrityモードへ移行 します(efi_enabled(EFI_SECURE_BOOT) を検出したカーネルが起動時にintegrityへ引き上げる実装)。これは、セキュアブートが保証する「起動時のカーネルは改ざんされていない」という前提を、起動後も実行時を通じて維持する ための設計です。セキュアブートだけでは「起動した瞬間の完全性」しか保証できず、起動後にroot権限で /dev/kmem を書けば台無しになる。Lockdownが実行時の完全性を引き継ぐことで、ブートチェーンの内部の署名検証がカーネル起動後も意味を持ち続けます。confidentialityへの引き上げは自動では行われず、lockdown=confidentiality の明示指定や一部ディストリビューションの独自設定が必要です。
開発時の利便性とのトレードオフ
Lockdownとモジュール署名の強制は、正当な開発・デバッグ作業も同時に制限します。
- カーネルデバッグの困難化:
/dev/kmemやkgdbを使ったライブデバッグ、/proc/kcoreでのメモリダンプ解析が制限され、クラッシュ調査の手法を変える必要が生じる。 - 自作モジュールの開発: 開発中のモジュールを都度MOK登録するか、
CONFIG_MODULE_SIG_FORCEを無効にした開発用カーネルを別途用意する必要がある。 - サードパーティドライバ: 署名されていないプロプライエタリドライバ(一部のGPU・Wi-Fiドライバなど)は、MOK経由の鍵登録なしには読み込めない。
- ヒバネーションの喪失: confidentialityモードではヒバネーションが無効化されるため、休止状態からの復帰を運用に組み込んでいる環境では機能を失う。
実務では、開発機は署名強制を無効化した緩いカーネル設定、本番機・エッジ端末はLockdown confidentialityを有効にした厳格な設定、というように環境ごとにポリシーを分けるのが定石です。カーネルコマンドラインの lockdown=integrity / lockdown=confidentiality や CONFIG_SECURITY_LOCKDOWN_LSM 系の設定で切り替えられます。一度confidentialityへ入ると、リブートなしにintegrityへ緩めることはできません(一方向のラチェット)。
まとめ
モジュール署名検証は、ロードされるカーネルモジュールの末尾に付与されたPKCS#7署名を信頼キーリングの鍵で検証し、未署名・改ざん済みモジュールの挿入を拒否します。これだけでは /dev/kmem 経由の直接書き換えという迂回路が残るため、Lockdown LSMが /dev/mem・未署名kexec・ヒバネーション・ioperm・ptraceの機密情報取得など、rootからカーネルへ到達しうる経路を一括して塞ぎます。integrityは改ざん防止、confidentialityはそれに加えて情報漏洩防止まで担い、セキュアブート環境では多くの場合integrityへ自動移行します(confidentialityへは明示設定が必要)。これによりブートチェーンの内部が保証する起動時の完全性が、実行時にも延長される一方、カーネルデバッグや未署名ドライバ利用の自由度とはトレードオフの関係にあります。
OS Article
カーネルモジュール署名とLockdownモードを実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
Lockdown
比較で見る軸
難易度: advanced / カテゴリ: OS / タグ数: 6
導入後に効く点
Lockdownモードはrootであってもカーネルメモリの読み書き・任意コード注入を禁じるLSMで、integrityとconfidentialityの2段階がある。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- OS
- タグ数
- 6
判断チェックリスト
- 自社の用途が「Lockdown / セキュアブート」に近いか確認する。
- 強みである「モジュール署名はロード時にPKCS#7署名を鍵で検証し、未署名・改ざん済みモジュールの挿入を拒否する。鍵は`.builtin_trusted_keys`等のキーリングで管理される。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。