オプションを有効にしても、関連するすべての攻撃が阻止されるわけではありません。まず、その仕組みが攻撃面、エラー検出、悪用条件、情報漏洩のいずれを対象としているかを判断し、実際に有効になっている状態を確認してください。
| 確認対象 | 参照箇所 |
| アドレス、権限、境界チェック | 第 1~3 節 |
| 検出カバレッジと lockdown | 第 4~5 節 |
| seccomp、割り当て保護、観測 | 第 6~8 節 |
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 をそのようなバインドとして扱うことはできない。
{"id":"seccomp-check-use-race","title":"チェックされたオブジェクトと、その後に使用されるオブジェクトは同じか?","summary":"ターゲットプロセスのメモリスナップショットを取得しても、その後のパラメータは凍結されない。安全な操作は、実際に検証されたオブジェクトと権限にバインドされる必要があり、CONTINUE をそのようなバインドとして扱うことはできない。","height":1000,"html":"<h2 data-i18n=\"heading\"></h2><p class=\"intro\" data-i18n=\"intro\"></p><div class=\"presets\" role=\"group\" data-i18n-label=\"target\"><button data-mode=\"A\" data-i18n=\"a\"></button><button data-mode=\"B\" data-i18n=\"b\"></button></div><div class=\"actions\"><button id=\"check\" data-i18n=\"check\"></button></div><label for=\"mode\" data-i18n=\"mode\"></label><select id=\"mode\"><option value=\"continue\" data-i18n=\"continueCall\"></option><option value=\"held\" data-i18n=\"held\"></option></select><div class=\"track-row\"><span data-i18n=\"buffer\"></span><div id=\"buffer\" class=\"track\"></div></div><div class=\"track-row\"><span data-i18n=\"checked\"></span><div id=\"checked\" class=\"track\"></div></div><div class=\"actions\"><button id=\"perform\" data-i18n=\"perform\"></button></div><div class=\"card\"><header data-i18n=\"result\"></header><div id=\"result\" class=\"readout\"></div></div><div class=\"copy\"><p id=\"explanation\" role=\"status\"></p><p class=\"reserve\" aria-hidden=\"true\" data-i18n=\"note\"></p></div><div class=\"actions\"><button id=\"reset\" data-i18n=\"reset\"></button></div><details class=\"scope\"><summary data-i18n=\"scopeLabel\"></summary><p data-i18n=\"scope\"></p></details>","css":".intro{margin:8px 0 18px;color:var(--muted);font-size:14px}.caption,.hint{font-size:12px;color:var(--muted);margin-top:12px}.control{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px 12px;align-items:center;margin:14px 0;font-size:13px}.control label{font-size:13px}.control output{color:var(--accent);min-width:5em;text-align:right;font-variant-numeric:tabular-nums}.control input{grid-column:1/-1;width:100%;margin:0}.presets{display:flex;gap:4px;align-items:stretch}.presets button{flex:1 1 0;min-width:0;overflow-wrap:anywhere;font-size:13px}.actions{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0}.actions button{flex:1;min-width:0;font-size:13px;min-height:42px}.copy{display:grid;font-size:14px;margin:16px 0}.copy>*{grid-area:1/1;margin:0}.reserve{visibility:hidden}.scope{margin-top:14px;color:var(--muted);font-size:12px}.scope summary{padding:8px 0;cursor:pointer}.scope p{margin-top:10px}.two{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.card{border:1px solid var(--rule);border-radius:9px;padding:14px;min-width:0}.card header{font-size:14px;font-weight:600;margin-bottom:10px}.card button{font-size:12px;width:100%;min-width:0}.card small{display:block;font-size:12px;color:var(--muted)}.card code{font-size:12px;overflow-wrap:anywhere}.metrics{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.metrics>div{border-left:2px solid var(--accent);padding-left:10px;min-width:0}.metrics span{display:block;min-height:3.2em;color:var(--muted);font-size:12px}.metrics strong{font-size:23px;display:block;font-weight:500;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.formula{border-top:1px solid var(--rule);padding-top:12px;margin-top:14px;font-size:13px;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}.value{font:500 20px var(--viz-font-ui)}.legend{display:flex;flex-wrap:wrap;gap:6px 14px;font-size:12px;color:var(--muted);margin:12px 0}.legend span:before{content:'';display:inline-block;width:8px;height:8px;border-radius:2px;background:var(--accent);margin-right:6px}.legend .second:before{background:var(--second)}.check{display:flex;align-items:center;gap:8px;font-size:13px;margin:12px 0}.check input{width:16px;height:16px;flex-shrink:0;accent-color:var(--accent)}select,input[type=text],input[type=number]{background:var(--paper);color:var(--ink);font:inherit;font-size:13px;padding:10px;border:1px solid var(--rule);border-radius:7px;max-width:100%;min-width:0}select{width:100%;min-height:42px}.band{height:20px;display:flex;background:var(--surface);border-radius:4px;overflow:hidden}.band i{height:100%;display:block;background:var(--accent);transition:width .25s}.band i.second{background:var(--second)}button:disabled{cursor:default}.status{font-size:13px;min-height:4.8em}.mono{font-family:var(--viz-font-mono);font-variant-numeric:tabular-nums}.muted{color:var(--muted)}\n@media(max-width:480px){.two{gap:8px}.card{padding:12px 9px}.actions button,.presets button{font-size:12px}.metrics strong{font-size:20px}.metrics{gap:8px}}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{transition:none!important;animation:none!important}}\n.track-row{margin:16px 0}.track-row>span{display:block;font-size:12px;color:var(--muted);margin-bottom:7px}.track{display:flex;gap:5px;min-width:0}.cell{flex:1;min-width:0;min-height:48px;border:1px solid var(--rule);border-radius:5px;background:var(--surface);display:flex;align-items:center;justify-content:center;text-align:center;padding:5px 3px;font-size:12px;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.cell.on{background:var(--accent-soft);border-color:var(--accent)}.cell.gold{background:var(--second-soft);border-color:var(--second)}.cell.empty{border-style:dashed;color:var(--muted)}.cell.error{border-color:var(--second);text-decoration:line-through}.choices{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;margin:14px 0}.choices button{min-width:0;padding:10px 4px;font-size:12px;overflow-wrap:anywhere}.choices button[aria-current=true]{border-color:var(--accent);background:var(--accent-soft)}.relation{display:grid;grid-template-columns:minmax(0,1fr) 28px minmax(0,1fr);align-items:center;gap:6px;margin:12px 0}.relation .cell{min-height:72px}.relation>i{text-align:center;font-style:normal;color:var(--accent)}.readout{font-size:13px;white-space:pre-line;min-height:6.4em;overflow-wrap:anywhere}.plot{position:relative;border-left:1px solid var(--rule);border-bottom:1px solid var(--rule);padding:8px 0;margin:18px 0}.plot-row{height:28px;position:relative;margin:4px 0;background:var(--surface)}.plot-row i{position:absolute;inset-block:5px;background:var(--accent);min-width:2px;transition:width .2s,left .2s}.plot-row b{position:relative;padding:4px 6px;font:11px/28px var(--viz-font-ui);background:var(--paper);border-radius:3px}.axis{display:flex;justify-content:space-between;font-size:11px;color:var(--muted)}\n\n.readout{min-height:4.8em}","js":"const $=s=>document.querySelector(s);const set=(id,v)=>$('#'+id).textContent=v;const t=k=>viz.t(k);function cells(id,values){$('#'+id).replaceChildren(...values.map(v=>{const e=document.createElement('div');e.className='cell '+(v.cls||'');e.textContent=v.text;e.title=v.title||v.text;return e;}));}function pressed(mode){document.querySelectorAll('[data-mode]').forEach(e=>e.setAttribute('aria-pressed',String(e.dataset.mode===mode)));}let target='A',held=null,approved=false,result=null;function draw(){cells('buffer',[{text:'path → '+target,cls:'on'}]);cells('checked',[{text:held===null?t('unseen'):'ref → '+held+' · '+t(approved?'approved':'rejected'),cls:approved?'on':'gold'}]);set('result',result===null?t('pending'):result.via+' → '+result.object);$('#perform').disabled=!approved;pressed(target);set('explanation',t('note'));}document.querySelectorAll('[data-mode]').forEach(e=>e.onclick=()=>{target=e.dataset.mode;draw();});$('#check').onclick=()=>{held=target;approved=held==='A';draw();};$('#perform').onclick=()=>{if(!approved)return;const stable=$('#mode').value==='held';result={object:stable?held:target,via:stable?'ref':'path'};draw();};$('#reset').onclick=()=>{target='A';held=null;approved=false;result=null;draw();};draw();","audio":false,"strings":{"a":"A を指す","approved":"検証により許可","b":"B を指す","buffer":"可変パスバッファ","check":"参照の取得と検証","checked":"チェック時に保持されていたオブジェクト","continueCall":"元の呼び出し CONTINUE","heading":"チェックされたオブジェクトと、その後に使用されるオブジェクトは同じか?","held":"監視者が検証済みの参照を使用","intro":"まずオブジェクト A を取得して検証し、ターゲットプロセスのパスバッファを変更する。元の呼び出しを継続するか、監視者が検証済みの安定したオブジェクト参照を使用して操作するかをそれぞれ選択する。","mode":"操作の実行方法","note":"A の検証成功後に B に切り替わり、実行される。元の呼び出しは可変パラメータを再読み取りして B を取得する;参照を保持する操作は、すでに検証済みの A を引き続き使用する。","pending":"アクセス未了","perform":"選択された操作の実行","rejected":"検証により拒否","reset":"リセット","result":"直近の実際のアクセス","scope":"A/B は実際のファイルアクセスを行わない玩具オブジェクトであり、ポリシーは A のみを許可する。チェック動作は安定した参照を取得してから検証を行う;制御されたソリューションでは、監視者がその参照を通じて操作を実行し、後で元の文字列を再オープンしない。通知 ID、ADDFD、パス解決の制約、および並行プロトコルは省略されており、完全な seccomp 沙箱実装ではない。","scopeLabel":"モデルの範囲と規約","target":"ターゲットプロセスの現在のパラメータ","unseen":"未チェック"}}
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 を同時に確認し、実行状態と組み合わせて判断してください。設定に機能があるからといって、起動時にそれが採用されるわけではありません。特定のステータスファイルが見えない場合、それは単に権限や名前空間に起因する観測制限である可能性があります。