カーネルの堅牢化

このページの目次

オプションを有効にしても、関連するすべての攻撃が阻止されるわけではありません。まず、その仕組みが攻撃面、エラー検出、悪用条件、情報漏洩のいずれを対象としているかを判断し、実際に有効になっている状態を確認してください。

確認対象参照箇所
アドレス、権限、境界チェック第 1~3 節
検出カバレッジと lockdown第 4~5 節
seccomp、割り当て保護、観測第 6~8 節
堅牢化の仕組みは異なるフェーズに作用する 到達可能な攻撃面 権限 / seccomp / lockdown エラーの発生 境界チェック / sanitizer 悪用条件 KASLR / 読み取り専用・実行不可 その後の影響 ゼロクリア / エラー処理 同じ脆弱性でも多層的な制約を受けるが、どの層も完全な修正ではない ビルド時のサポート、起動時の有効化、ランタイムでの有効性は、それぞれ個別に検証すること。

1. KASLR と厳格なメモリ権限

KASLR は起動時にカーネルのアドレス配置の一部をランダム化します。ランダム化の範囲と粒度はアーキテクチャ、設定、実装によって異なり、コード、データ、モジュールがすべて同じランダムなベースアドレスによって制御されると一概には言えません。x86 における初期解凍/再配置コードは位置の選択に関与するため、ブートローダーが単独で完了したと記述するのは誤りです。

これは攻撃者がコードやデータの位置を予測しにくくしますが、アドレスの漏洩やエントロピーの不足は効果を弱めるため、アドレス情報の制限と組み合わせて使用する必要があります。kptr_restrict=2 は %pK ルールで制御される出力に対してアドレスを非表示にしますが、「root 以外は見えない」わけでも、すべてのカーネルアドレス出力がこの設定によって制御されることを保証するものでもありません。

CONFIG_STRICT_KERNEL_RWX やモジュール関連の厳格な権限などの仕組みは、書き込み可能領域と実行可能領域を制約します。読み取り専用データや実行不可なデータページは、コードの改ざんや注入されたデータの直接実行を制限しますが、すべてのコード再利用やデータ改ざんを自動的に阻止するわけではありません。カーネル自己保護 と kptr_restrict の説明 を参照してください。

ユーザー空間の /proc/sys/kernel/randomize_va_space が制御するのはユーザープロセスの ASLR であり、これがカーネルの KASLR が有効である証拠や、システムコールごとのカーネルスタックオフセットのランダム化が既に開始されている証拠にはなりません。

2. スタックプロテクターとオブジェクト境界チェック

コンパイラはオプションのルールに合致する関数のみに canary を挿入するため、すべての関数に canary があるわけではありません。チェックは通常、保護された関数の終了前に発生し、canary の破損が検出されると失敗処理に入ります。これは任意の場所での境界外書き込みをカバーするものではなく、データが誤用される前に即座に発見できることを保証するものでもありません。

カーネルの CONFIG_FORTIFY_SOURCE は、コンパイラがオブジェクトのサイズを推論できる場合に備えて、一部のメモリ/文字列操作を強化します。既知のエラーはコンパイル時に診断でき、一部の動的な境界外アクセスはランタイムでレポートおよび終了パスをトリガーします。未知のオブジェクト境界やカバーされていない操作は依然として境界であり、「すべての memcpy が安全である」と推論することはできません。また、これは glibc の _FORTIFY_SOURCE=3 用のコンパイルマクロでもありません。

CONFIG_HARDENED_USERCOPY は、カーネルとユーザー空間間のコピー時にオブジェクトと領域の制約をチェックし、不正なコピーのいくつかを解決します。しかし、これはコピー内容がビジネスプロトコルに準拠していることを証明するものではなく、渡された長さを自動的に信頼できるものにするものでもありません。

3. KPTI:ユーザー空間のページテーブルにおけるカーネルマッピングの制限

Meltdown 系問題は、特定のプロセッサにおける遷移的実行による漏洩に関与します。KPTI は、ユーザー空間で使用されるページテーブルがユーザーマッピングとカーネルに入るために必要な少数のマッピングのみを保持するようにし、カーネルに入る際に適切なカーネルページテーブルに切り替えます。

これにより、ユーザー空間での遷移的アクセスによる広範なカーネルマッピングへのアクセス条件が減少しますが、Spectre/Meltdown 系脆弱性に対する唯一の解決策ではありません。ページテーブルの切り替えと TLB 管理にはオーバーヘッドがあり、PCID などの機能で緩和できます。実際の影響はワークロードに応じて測定する必要があり、固定のパーセンテージを一律に適用することはできません。

有効化の有無はプロセッサの脆弱性情態、カーネルおよび起動ポリシーに依存し、「特定の世代の Intel/AMD 以降は自動的に無効化される」と一概に概括することはできません。/sys/devices/system/cpu/vulnerabilities/ の実際のレポートを確認し、Not affected(影響なし)、緩和済み、および残存するリスクを区別してください。x86 PTI を参照してください。

4. 検出ツールのカバレッジは異なる

ツール主に発見される問題重要な境界
KASAN境界外アクセスや解放後使用などのメモリエラーgeneric、ソフトウェアタグ、ハードウェアタグモードでの能力とコストが異なる
KMSAN未初期化値の使用と伝播対応するコンパイラ、アーキテクチャ、およびインスツルメンテーションのサポートが必要
UBSAN選択された未定義動作のチェック有効化されるサブチェックによってカバレッジが決まる;すべての整数オーバーフローをチェックすると総称することはできない
KFENCEサンプリングによるヒープメモリエラーの検出低オーバーヘッドはサンプリングに依存する。レポートされないからといって、すべてのアクセスに問題がないわけではない

符号なしのアンダーフロー自体は C 言語の未定義動作ではありません。カーネルのコンパイルオプションやサブチェックも整数の動作に影響します。1 回のテストでレポートされなかった場合、それはその実行とカバレッジ範囲内で問題が検出されなかったことを示すだけです。

これらのツールはすべてカーネル開発にのみ使用できるわけではありません。例えば、ハードウェアタグ KASAN や KFENCE は異なる生産環境でも適用可能ですが、実際のオーバーヘッドとサポート条件を評価する必要があり、一律に「2 倍遅い」と結論づけることはできません。KASAN、KMSAN、UBSAN、KFENCE を参照してください。

5. Lockdown:高権限ユーザーによるカーネルの信頼境界変更の制限

lockdown は、カーネルメモリへの読み書き、検証されていないコードの置換、または機密情報の露出を招くインターフェースを制限できます。integrity(整合性)モードと confidentiality(機密性)モードでは制約が異なり、後者は特定の読み取り経路をさらに制限します。すべての BPF やデバッグ機能が「すべて禁止」と一言で正確に記述できるわけではありません。

状態インターフェースは通常、securityfs 内の /sys/kernel/security/lockdown にあり、/proc/sys/kernel/lockdown ではありません。Secure Boot はディストリビューション、設定、パッチに応じて lockdown をトリガーする可能性がありますが、両者を無条件に等号で結ぶことはできません。署名検証、モジュールロードポリシー、および lockdown はそれぞれ個別に確認する必要があります。kernel_lockdown(7) を参照してください。

6. Seccomp:システムコール ABI によるインターフェースの縮小

seccomp filter はシステムコール番号、アーキテクチャ識別子、命令アドレス、およびスカラーパラメータを読み取り、古典的な BPF フィルタープログラムを使用して ALLOW、ERRNO、TRAP、KILL_PROCESS、USER_NOTIF などのアクションを返します。SECCOMP_RET_DENY という名前の一般的な戻り値アクションは存在しません。

インストールには通常、no_new_privs の設定か、対応する名前空間内の権限条件の満たす必要があります。フィルターはスレッドにアタッチされ、TSYNC などの方法でスレッドグループ間で同期できます。許可された fork/exec はフィルター制約を継承します。フィルターを重ねて適用する場合、後続の ALLOW でそれまでのより厳格な結果を緩和することはできません。

フィルターが何を見るか直接わからないこと
システムコール番号ABI と組み合わせなければ、呼び出しの意味を正しく特定できない
スカラーパラメータとポインタ値安定したパス文字列として逆参照できない
アーキテクチャ識別子ルールの判断に組み込む必要があり、無視できない

したがって、openat を許可しポインタ値を比較したからといって、指定されたパスのみを開くことを意味するわけではありません。

監視者のチェック後、ターゲットメモリは変更される可能性がある

USER_NOTIF は、監視者に通知を送信して処理または応答させるが、ターゲットプロセスの可変メモリを読み取ってから元のシステムコールを再開するため、TOCTOU(Time-of-Check to Time-of-Use)の問題に直面する。通知メカニズムは、ファイルアクセスを自動的に安全に制御するものではありません。LSM、ファイルディスクリプタの権限、および他の分離メカニズムと組み合わせて使用する必要がある。seccomp filter ドキュメント を参照。

チェック後にパスバッファを変更し、「現在のポインタを引き続き使用する」か「保持しているオブジェクトに対して操作を行う」かをそれぞれ選択する。実際に使用されるターゲットを比較することで、チェック時に成立していた事実がなぜ期限切れになるかを見ることができる。

図を準備しています
チェックされたオブジェクトと、その後に使用されるオブジェクトは同じか?

ターゲットプロセスのメモリスナップショットを取得しても、その後のパラメータは凍結されない。安全な操作は、実際に検証されたオブジェクトと権限にバインドされる必要があり、CONTINUE をそのようなバインドとして扱うことはできない。

7. ゼロクリアと freelist 保護

init_on_alloc / init_on_free は、対応する割り当てまたは解放パスでオブジェクトとページをゼロクリアし、旧データ露出などのリスクを低減しますが、ダングリングポインタを有効な状態に戻すものではなく、すべてのアロケーターや特殊なパスが同じ処理を採用する意味でもありません。

CONFIG_SLAB_FREELIST_RANDOM はフリーオブジェクトの配置を変更し、CONFIG_SLAB_FREELIST_HARDENED は freelist メタデータを強化します。ランダムな順序とポインタ保護は異なるメカニズムです。これらは一部のヒープ悪用を困難にしますが、UAF(Use-After-Free)の修正に取って代わるものではありません。

8. 読み取り専用で実行状態を確認する

from pathlib import Path

for name in ('/proc/sys/kernel/kptr_restrict',
             '/sys/kernel/security/lockdown',
             '/sys/devices/system/cpu/vulnerabilities/meltdown'):
    try:
        print(name, Path(name).read_text().strip())
    except OSError as exc:
        print(name, type(exc).__name__)

ターゲットのカーネル設定と /proc/cmdline を同時に確認し、実行状態と組み合わせて判断してください。設定に機能があるからといって、起動時にそれが採用されるわけではありません。特定のステータスファイルが見えない場合、それは単に権限や名前空間に起因する観測制限である可能性があります。