LinuxカーネルIPv4 TCP inet_opt/ireq_opt の解放後使用(CVSS 9.8)。
IPv4 ヘッダオプション付きの SYN は、そのオプションがリクエストソケットに保存される。
ハンドシェイクが完了すると、tcp_v4_syn_recv_sock() は同じバッファをコピーせずに
ポインタで子ソケットに渡す。別の CPU 上で再送された SYN は、子ソケットがすでに
消滅している間に tcp_v4_send_synack()/inet_csk_route_req() でそれを読み取る
(inet_sock_destruct() が素の kfree() で解放しており、子ソケットには
SOCK_RCU_FREE がない)。修正は 2 つの kfree_rcu() 呼び出しで、6.6.159 などに
取り込まれた。4.4 以降が脆弱。
ラボはゲストカーネルを起動するため、パッチ適用済みのホストカーネルが標的になることはない:
make image
make kernel-amp kernel-fixed-amp
make rootfs
make test-det-vuln # KASAN: slab-use-after-free in inet_csk_route_req
make test-det-fixed # same attack, clean
phase-det はクロス CPU の再現である:dup-SYN フラッダを CPU1 に固定(リクエスト
ソケットの作成とそのタイマー)、最終 ACK を CPU0 で(子ソケットの作成)、サーバの
accept+close を CPU3 で(子ソケットの破棄)。RPS は無効、攻撃者/標的の netns は
veth ペア経由、パケットは生の Ethernet フレームとして送出されるため、攻撃者自身の
カーネルがハンドシェイクを RST で破棄することはない。-amp カーネルは
inet_csk_route_req 内で ireq_opt を取得してからそれを参照解除するまでの間に
5ms の遅延を追加する(KCSAN 風の遅延注入で、これらの再現カーネルに限り再現性の
ために使用され、ソース内で明確にマークされている)。
poc/poc.c には timerace、race、migrate、mptcp の各バリアントもある。
evidence/REPRODUCED-UAF-first-splat.txt — 1 回の実行で 12 件の splat、最初のもの:
[ 9.076253] BUG: KASAN: slab-use-after-free in inet_csk_route_req+0x94/0x370
[ 9.076586] Read of size 1 at addr ffff888002ddaa41 by task poc/85
...
tcp_v4_send_synack+0x212/0x240
tcp_rtx_synack+0xd5/0x280
inet_rtx_syn_ack+0x38/0x60
tcp_check_req+0xb8e/0xde0
tcp_v4_rcv+0x1131/0x15e0
...
Allocated by task 79: tcp_v4_route_req+0x116/0x1b0 (options saved on the SYN)
Freed by task 80: inet_sock_destruct+0x2cd/0x380 (child close(), plain kfree)
evidence/VERIFIED-fixed-kernel-clean.log — 2 つの kfree_rcu() 呼び出しを適用した
カーネルに対する同じ攻撃:報告ゼロ。
まだパッチを適用できない場合は、prerouting で IPv4 オプションを持つ TCP パケットを
ドロップし(ip protocol tcp ip hdrlength > 5 drop)、migration バリアントに対しては
net.ipv4.tcp_migrate_req=0 を設定する。本当の修正はカーネルの更新である。