QEMU NVMe out-of-bounds arbitrary memory read (unvalidated guest offset)¶
QEMU'nun NVMe
nvme_changed_nslist()Get-Log-Page handler'ında bir out-of-bounds read (CVE-2021-3947): guest-controlled bir log-page offset'i buffer'a karşı validate edilmiyor ve komşu host memory'sini guest'e geri sızdırıyor.
Mechanism¶
Note
NVMe Get Log Page, guest'in controller log'larını bir guest buffer'ına
okumasına izin verir ve log içine guest tarafından sağlanan bir offset
(off) ile bir length destekler. QEMU'nun Changed-Namespace-List handler'ı
hw/nvme/ctrl.c içindeki nvme_changed_nslist(), sabit boyutlu bir log
buffer'ından o offset'te kopyalar. Isolation invariant'ı, off'un log
buffer'ı içinde kalması ve böylece device'ın yalnızca kendi log byte'larını
döndürmesidir. Bug: off (ve kısmen guest-controlled length)
off, buffer size'ına karşı validate edilmeden index/copy için
kullanılır — buffer'dan büyük bir off underflow/over-index yapar, dolayısıyla
device hedeflenen buffer'ın ötesini okur ve komşu QEMU-process memory'sini
guest'e döndürür.
Bu, host→guest sınırını bir information-disclosure primitive olarak aşar: NVMe access'i olan kötü niyetli bir guest, asla görmemesi gereken host process memory'sini (heap içeriği, ASLR'yi yenmek için kullanılabilir pointer'lar) okur; bu, tipik bir escape chain'in leak yarısıdır. Yayınlanmış PoC'lerde NVMe reentrancy UAF'i (CVE-2021-3929) ile doğal olarak eşleşir.
Walkthrough¶
Public, halihazırda patch'lenmiş materyal: Red Hat Bugzilla 2021869 ve upstream fix
commit'i e2c57529c9306e4 (~QEMU 6.2'de düzeltildi). Yalnızca kavramsal
reproduction path'i:
- Guest, Changed Namespace List için bir Get Log Page admin command'i
gönderir; kendi kontrolündeki bir log-page offset
off'unu (ve length'i) seçer. nvme_changed_nslist(), copy'yi sabit log buffer'ı içinde konumlandırmak içinoff'u kullanır amaoff/length'i buffer sınırlarına karşı kontrol etmez.offbuffer'ın ötesine ayarlandığında (örn. > 4096), copy byte'larını log buffer'ına komşu host memory'sinden kaynaklar.- Bu out-of-bounds byte'lar command'in DMA result'unda döndürülür → guest sızdırılmış host memory'sini okur.
Warning
Tarihsel, patch'lenmiş bir issue. Yalnızca kavramsal; hiçbir offset ya da weaponize edilmiş leak chain'i yok.
Representative fix shape (illustrative)
Beklenen gözlem: bir guest'in büyük bir offset ile bir Changed-Namespace log
page'inden non-zero/garbage byte'lar okuması; ASan altında nvme_changed_nslist'te
bir heap-buffer-overflow READ.
Detection¶
- Host tarafı: ASan/instrumented build'ler
nvme_changed_nslist'te bir heap OOB read rapor eder. - Behavioral: bir guest'in log size'ının ötesindeki offset'lerle Get-Log-Page
göndermesi anormaldir; out-of-range
offiçeren NVMe admin command'lerini logla/audit et. - Guest'te yüzeye çıkan sızdırılmış içerik (non-log byte'lar) gözlemlenebilir sinyaldir.
Mitigation¶
- CVE-2021-3947 için QEMU fix'ini uygula (commit
e2c57529c9306e4): kopyalamadan önce guest tarafından sağlanan log offset/length'ini buffer'a karşı validate et. - NVMe emulation'ını patch'li tut ve ihtiyaç duymayan guest'ler için emule edilen NVMe device'ını devre dışı bırakarak attack surface'i daralt.
- Defense-in-depth: bir info-leak'in ulaşabileceği host memory'sini sınırlamak için QEMU'yu deprivilege/sandbox et (seccomp, sVirt).
References¶
- Red Hat Bugzilla 2021869 (CVE-2021-3947, QEMU NVMe out-of-bounds memory read): https://bugzilla.redhat.com/show_bug.cgi?id=2021869
- QiuhaoLi, "Recursive MMIO VM Escape PoC" (CVE-2021-3929/3947): https://github.com/QiuhaoLi/CVE-2021-3929-3947