flawopen.com/Teardowns/cve-2024-1086-linux-netfilter-nftables-uaf
CVE-2024-1086:Linux nf_tablesの解放後使用
CVE-2024-1086は、無効なDROPパラメーターを受け入れるLinux nf_tablesの解放後使用です。ディストリビューションの修正済みカーネルを適用してください。
担当者が「受け入れる」か「破棄する」だけを選ぶ申請書を想像してください。別欄には破棄時のエラーコードを記入し、ゼロまたは有効な負のエラー値だけを許可します。脆弱な検証処理は、正の「受け入れる」値がその欄に入るのを許していました。その結果、後続のネットワーク処理で判定の解釈が食い違いました。修正では、正確に定義された判定値だけを受け入れます。
主要な概念と専門用語
nf_tables- nftablesがパケットフィルタリングなどのネットワークルールを設定するために使うLinuxカーネルのサブシステム。
Netfilter verdict- カーネルがパケットルールを評価した結果。例は
NF_ACCEPTとNF_DROPです。DROPにはエラー値を付けられますが、hookはゼロまたは有効な負のerrnoを想定します。 解放後使用(CWE-416)- オブジェクトの寿命が終わった後にコードがそのメモリーへアクセスする欠陥です。NVDは本件をローカルのカーネル権限昇格として記録しています。
User namespace- プロセスのIDと権限を対応付けるLinux namespaceです。非特権ユーザーが作成できるかはカーネルとディストリビューションの方針によります。作成可能であることだけでホスト脱出が保証されるわけではありません。
フレームワーク対応
- このガイドで説明する弱点の CWE 参照: CWE-416
- CISA KEV — 追加日 2024-05-30 — CVE-2024-1086
根本原因の分析 (Root Cause)
net/netfilter/nf_tables_api.c の nft_verdict_init() は、以前は判定値をマスクし、NF_DROP や NF_QUEUE のパラメーターを許可していました。Netfilter hook は NF_DROP の上位ビットにゼロまたは有効な負の errno が入ることを想定します。upstreamの修正によると、NF_ACCEPT のような正の値が解放後使用を引き起こす可能性がありました。パッチはこの寛容な経路を削除し、定義済みの判定値だけを許可します。それ以外は -EINVAL を返します。NVDは影響をローカル権限昇格としています。到達可能性はカーネル、利用可能な権限、ディストリビューションの方針によって異なり、すべてのコンテナーが同じ条件とは限りません。
ステップ・バイ・ステップの攻撃フロー
ローカルでルールを管理できること
報告された攻撃はローカルから行われます。プロセスがnf_tablesの判定検証に到達できる必要があります。必要な権限や非特権user namespaceの可否はホスト設定によって異なります。
無効な判定パラメーターが検証に到達
修正前の nft_verdict_init() は NF_VERDICT_MASK を適用した後、一部のパラメーター付き値を許可していました。パラメーター部分に正の NF_ACCEPT が含まれる場合も該当します。
hook処理で解放後使用が発生
Netfilter hookは NF_DROP のパラメーターをゼロまたは有効な負のerrnoとして解釈します。upstreamの報告は、許可された正の値がパケット処理中に解放後使用を引き起こし得ると説明しています。一般化できる攻撃プリミティブや、必ずコンテナーから脱出できることを示すものではありません。
ディストリビューションの修正済みカーネルを適用
upstreamの変更は未対応の判定パラメーターを拒否します。パッケージのバージョンやバックポートは異なるため、ディストリビューションが提供する修正版をインストールして起動してください。
ソースコード比較:脆弱 vs 堅牢化
脆弱なコードは判定値をマスクして後続処理へ進むため、正の NF_ACCEPT などが NF_DROP のエラー欄に入る可能性がありました。修正は正確な定数だけを許可し、それ以外には -EINVAL を返します。これはupstreamパッチの要点を示す抜粋で、単体でコンパイル可能な関数ではありません。
ソース抜粋: net/netfilter/nf_tables_api.c
/* f342de4e2f33 適用前の net/netfilter/nf_tables_api.c にある nft_verdict_init() の抜粋。
* マスク値の経路ではパラメーター付き verdict が許可されていた。 */
switch (data->verdict.code) {
default:
switch (data->verdict.code & NF_VERDICT_MASK) {
case NF_ACCEPT:
case NF_DROP:
case NF_QUEUE:
break;
default:
return -EINVAL;
}
fallthrough;
case NFT_CONTINUE:
case NFT_BREAK:
case NFT_RETURN:
/* 既存の他の verdict 処理はこの後に続く。 */
break;
}
/* f342de4e2f33 による変更後の net/netfilter/nf_tables_api.c にある
* nft_verdict_init() の抜粋。 */
switch (data->verdict.code) {
case NF_ACCEPT:
case NF_DROP:
case NF_QUEUE:
break;
case NFT_CONTINUE:
case NFT_BREAK:
case NFT_RETURN:
/* 既存の他の verdict 処理はこの後に続く。 */
break;
default:
return -EINVAL;
}
エンジニアリング&システム堅牢化チェックリスト
- ✓ディストリビューションが推奨する修正済みカーネルをインストールして起動し、再起動後に稼働中のカーネルを確認してください。バックポートによりバージョン番号は異なります。
- ✓単一のupstreamバージョン比較ではなく、利用中のカーネル種別とパッケージに対応するディストリビューションのセキュリティ情報を確認してください。
- ✓更新を延期する場合は、非特権user namespaceの作成を制限するベンダー文書の対策を検討してください。この設定が対象ディストリビューションに存在することを確認し、コンテナーやデスクトップアプリへの影響をテストしてください。
- ✓カーネルの判定検証をレビューする際は、パケットhookに入る前に未対応のパラメータービットを拒否し、許可する定数と無効な正の値をテストしてください。