QEMU MSI-X memory-region cache OOB write (CVE-2020-27821)¶
QEMU'nun memory-region cache initialization'ındaki bir kusur, bir MSI-X table MMIO write'ının out-of-bounds bir offset'e ulaşmasına izin veriyor; cache'lenen region'a komşu host memory'sini corrupt ederek QEMU process'ini crash'liyor.
Mechanism¶
Isolation invariant: cache'lenmiş bir MMIO mapping, hizmet ettiği erişimin tamamını kapsamalı
QEMU, bir MemoryRegion'a yapılan tekrarlı access'leri bir MemoryRegionCache (address_space_cache_init() aracılığıyla) inşa ederek hızlandırır; bu, bir guest address aralığının bir host buffer'ına önceden hesaplanmış bir translation'ıdır. Örtük invariant, dispatch edilen her access'in cache'in initialize edildiği aralığın içine düşmesi ve cache uzunluğunun region size'ından dürüstçe hesaplanmasıdır.
Vulnerable path'te MSI-X table region'ının cache'i, table'ı sadakatle bound etmeyen bir uzunlukla initialize edilmişti; dolayısıyla MSI-X table'a guest tarafından sürülen bir MMIO write (hw/pci/msix.c içindeki msix_table_mmio_write()), hedeflenen table backing store'unun ötesinde bir offset'e resolve olabiliyordu. Write index'i guest-controlled bir MMIO address'inden türediği ve cache onu clamp edemediği için, store cache'lenen region'a komşu host heap memory'sine düşer. Bu, guest→host sınırını aşar çünkü corrupt eden write guest RAM'inde değil, host QEMU process address space'inde execute olur. Class, klasik bir out-of-bounds write — bkz. ../primitive/out-of-bounds-write.md.
Walkthrough¶
Bu, disclose edilmiş, patch'lenmiş bir materyaldir (CVE-2020-27821, QEMU 5.2.0'da 4bfb024bc76973d40a359476dc0291f46e435442 commit'i ile düzeltildi). Kusur, MSI-X table path'i memory-region cache'i benimsediğinde QEMU 3.0'da eklendi. Aşağıdaki path kavramsaldır, public advisory ve commit'ten alınmıştır.
-
Guest, MSI-X capability'si QEMU tarafından emule edilen bir PCI device'a sahiptir. MSI-X table, bir host buffer'ı ile backing edilen ayrı bir
MemoryRegioniçinde yaşar. -
QEMU o region için bir
MemoryRegionCacheinitialize eder. Cache init'indeki off-by-one / size-handling kusuru nedeniyle, cache'lenen uzunluk table backing buffer'ını doğru şekilde bound etmez. -
Guest, address'i MSI-X table window'unun sonuna yakın bir entry'yi hedefleyen bir MMIO write gönderir.
msix_table_mmio_write()handler'ı, hedefi guest tarafından sağlanan offset'ten hesaplar. -
Store, cache'lenmiş buffer'ın dışına yazar. Pratikte bu, komşu host heap metadata'sını ya da komşu allocation'ları corrupt eder ve QEMU process'i fault'a girer (DoS). Advisory etkiyi guest-triggered bir host crash olarak kapsamlandırır.
Tarihsel / patch'lenmiş
Yalnızca yetkili defensive research ve regression testing içindir. Fragment boundary-violation şeklini gösterir, weaponize edilmiş uçtan uca bir host code-execution chain'ini değil. Patch'lenmemiş QEMU'ya karşı untrusted guest'ler çalıştırma.
Detection¶
- Crash signature:
msix_table_mmio_write/address_space_*cache*üzerinden geçen bir backtrace'e sahip QEMU SIGSEGV/SIGABRT, kanonik fingerprint'tir. glibc altında, out-of-bounds bir heap store çoğu zaman write'ın kendisinde değil, sonradanmalloc(): corrupted/free(): invalid pointerabort'ları olarak yüzeye çıkar. - ASAN build'leri: bir ASAN/sanitizer QEMU build'i, MSI-X table MMIO write path'inde köklenen bir
heap-buffer-overflow WRITErapor eder — fuzzing/regression harness'ları için en doğrudan kanıt. - Telemetry: bir guest'in bir device'ın MSI-X table window'unun kuyruğuna (özellikle işlevsel bir neden olmadan) yoğun MMIO write'lar yapması anormaldir ve device model'inden ya da qtest tracing'inden gözlemlenebilir.
- Fuzzing: MSI-X BAR offset'lerini gezen structured PCI/MMIO device fuzzing (qtest + libFuzzer) bu class'ı hızlıca reproduce eder. Bkz. ../hypervisor/hypercall-fuzzing.md.
Mitigation¶
- Patch: memory-region cache length/bounds handling'ini düzelten
4bfb024bc76973d40a359476dc0291f46e435442commit'ini taşıyan QEMU 5.2.0 veya sonrasına (ya da bir distro backport'una) güncelle. - Defense in depth: emule edilen device'ın MSI-X table'ının kesinlikle gerekli olmadığı yerlerde paravirtualized virtio device'ları tercih et; machine type'taki emulated device surface'ini minimize et.
- Confinement: QEMU'yu sandbox'lanmış olarak (
-sandbox onseccomp, ayrılmış unprivileged uid, SELinux/sVirt) çalıştır; böylece corrupt/abort olmuş bir device model, VM'in kendi process'inin ötesine pivot edemez. - Build hardening: QEMU'yu distro'nun sağladığı toolchain hardening'i (
_FORTIFY_SOURCE, stack protector, full RELRO, ASLR/PIE) ile dağıt; böylece adjacent-write corruption'ı steer edilmek yerine abort olmaya daha yatkın olur. - Operational: host QEMU process'ini crash'leyen tek bir guest'i, bir stability blip'i değil, bir security event olarak ele al.