Skip to content

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.

  1. 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 MemoryRegion içinde yaşar.

  2. QEMU o region için bir MemoryRegionCache initialize eder. Cache init'indeki off-by-one / size-handling kusuru nedeniyle, cache'lenen uzunluk table backing buffer'ını doğru şekilde bound etmez.

  3. 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.

    Conceptual shape (not a working exploit)
    guest MMIO write to MSI-X table window
      -> msix_table_mmio_write(addr, val)
           # addr-derived index trusted against a mis-sized cache
      -> store into cached host buffer at out-of-range offset
           # write lands just past the table's backing allocation
    
  4. 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, sonradan malloc(): corrupted / free(): invalid pointer abort'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 WRITE rapor 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 4bfb024bc76973d40a359476dc0291f46e435442 commit'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 on seccomp, 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.

References