ASan はリングバッファー内の範囲外読み取りを見逃す:UBSan と手動ポイズニングで補う
libslirp の CVE-2026-9539(4.9.2 で修正)は、有効データの末尾を越えても読み取りが確保済みのリングバッファー内に収まるため、ファザーが到達しても ASan では検知できなかった。UBSan の整数オーバーフロー検出を足すか、バッファーの未使用領域を ASan のポイズニングで禁止にして検知する。
なぜ ASan で見つからないか
- ASan は「確保されていないメモリー」へのアクセスを検知する。リングバッファーのように大きく確保した領域の中で、論理的に無効なデータ部分を読んでも、確保済み領域なのでエラーにならない。
- 自前のメモリープール、アリーナ、固定長バッファーを使うコードは同じ盲点を持つ。
補う方法(Quarkslab の解説)
- UBSan で整数の異常を検知する: 読み取り量の計算でアンダーフローが起きていた。UBSan の整数オーバーフロー検出を有効にして再ビルドすると、ここで検知できる。
bash
clang -fsanitize=address,undefined,integer -fno-sanitize-recover=all ...(
-fsanitize=integerは符号なしのラップアラウンドも検知するため、正当なラップを多用するコードでは誤検知が出る。対象を絞って使う。) - 未使用領域を ASan でポイズニングする: バッファー全体をアクセス禁止として記録し、使用中の範囲だけを許可、使い終えた範囲は再び禁止にする。整数計算の副作用に頼らず、不正な読み取りそのものを検知できる。
c
#include <sanitizer/asan_interface.h> ASAN_POISON_MEMORY_REGION(buf, cap); // 確保直後に全体を禁止 ASAN_UNPOISON_MEMORY_REGION(buf + off, len); // 有効データを書いた範囲だけ許可 ASAN_POISON_MEMORY_REGION(buf + off, len); // 消費したら再び禁止 - 状態を持つプロトコルのファジング: LibAFL-QEMU を基盤に、TCP の状態変化ごとの差分スナップショットを保存し、そこから別のパケットを送って探索する構成が紹介された。スナップショットと QEMU 向け ASan の併用ができないため、見つけたパケット列を別プロセスで再実行して ASan 検査とカバレッジ記録を行う。
防御側の対応
- libslirp を 4.9.2 以降に更新する(QEMU などのユーザーモードネットワークで使われる)。悪用にはゲスト内の root か
CAP_NET_RAWが必要。