Skip to content

QEMU device emulation MMIO/PIO callback memory corruption (generic)

Bütün bir guest→host escape sınıfı: bir guest, emüle edilmiş bir device'ın MMIO/PIO register'larına attacker-controlled değerler yazar ve device'ın MemoryRegionOps read/write callback'i bunları (bir index, length veya offset olarak) bounds-checking yapmadan kullanarak bir host buffer'ının dışında okuma veya yazma yapar. CVE-2016-3710 (QEMU VGA) kanonik örnektir.

Mechanism

Note

Her emüle edilen device, guest o region'a dokunduğunda — memory-mapped I/O (MMIO) yoluyla ya da legacy I/O port space için programmed I/O (PIO in/out) yoluyla — tetiklenen MemoryRegionOps.read / .write callback'lerine sahip bir MemoryRegion kaydeder. Bu callback'ler host QEMU process'inde çalışır ve guest tarafından sağlanan addr/value'yu doğrudan alır. Isolation invariant şudur: bir device callback'i, guest tarafından yazılan her register değerini untrusted olarak ele almalı ve sonuçta oluşan tüm memory access'leri kendi allocate ettiği host buffer'larıyla sınırlamalıdır. Bug sınıfı, bir callback bir guest değerini array index, copy length veya base offset olarak kullanıp ardından bir host buffer'ına buffer sınırlarına karşı validate etmeden eriştiğinde ortaya çıkar. Tek bir guest PIO/MMIO yazması o zaman bir out-of-bounds read (host info leak) ya da write (host memory corruption) sürer. Primitive QEMU'nun host ayrıcalıklarıyla çalıştığı için, bu sınıf guest→host sınırını aşar ve birçok device'da DoS, host memory disclosure ve arbitrary host code execution ile sonuçlanmıştır.

Walkthrough

Public, patched örnek: CVE-2016-3710, QEMU VGA emulator OOB access'i (Wei Xiao / Qinghao Tang; Red Hat write-up'ı). Yalnızca kavramsal path:

  1. Guest (VGA register'larına dokunma ayrıcalığına sahip), VBE bank register'ını seçen bir PIO yazması yapar, örn. vbe_ioport_write_data() üzerinden VBE_DISPI_INDEX_BANK index'iyle. Handler, 16 MB'lık VGA RAM boyutuna karşı herhangi bir üst clamp olmadan s->bank_offset = val << 16 saklar.
  2. Guest ardından VGA memory'ye bir MMIO access yapar. vga_mem_writeb() / vga_mem_readb(), attacker-controlled bank_offset'i kullanarak hedefi hesaplar; bir byte address ayrıca 32-bit (dword) access'e yükseltilir ve hesaplanan pointer'ı 16 MB'lık host VGA buffer'ının ötesine iter.
  3. Out-of-bounds dword read/write, komşu host heap'e düşer — information leak, QEMU crash (DoS) veya grooming ile QEMU ayrıcalığında host code execution.
/* representative shape of the bug (guest controls bank_offset) */
static void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val) {
    addr += s->bank_offset;          /* unchecked, guest-influenced */
    ((uint32_t *)s->vram_ptr)[addr] = val;  /* OOB when addr exceeds vram size */
}

Fix, bank offset'i / access'i VGA RAM boyutuna karşı bounds-check eder, böylece callback artık buffer'ının ötesini index'leyemez. Aynı pattern (indexlemeden önce guest register değerlerini validate etmek) tüm sınıf için upstream fix'tir.

Observable effect on an unpatched build

Etkilenen bir build'de, hazırlanmış bank-register + MMIO dizisi vga_mem_writeb/readb içinde bir ASan heap-buffer-overflow raporu ya da bir QEMU SIGSEGV üretir. Red Hat advisory'si bunun "VGA emulator'ün enabled olduğu tüm QEMU/KVM ve Xen guest'lerini" etkilediğini belirtir.

Warning

Tarihsel, düzeltilmiş bug sınıfı (CVE-2016-3710 temsili; benzer bug'lar birçok device'da mevcut — RTL8139, PCNET, NVMe, CXL mailbox, vb.). Yalnızca açıklanmış yapı gösterilir; herhangi bir offset, heap layout veya end-to-end host-RCE chain verilmemiştir.

Detection

  • Bir device'ın MemoryRegionOps .read/.write callback'inde kök salan host-side ASan heap-buffer-overflow / OOB-read raporları ya da bir guest PIO/MMIO register yazmasının hemen ardından gelen QEMU SIGSEGV.
  • Device callback'lerini, bir host buffer'ına o buffer'ın boyutuna karşı bounds check olmadan index/length/offset olarak kullanılan guest değerleri için denetleyin.
  • Coverage-guided device fuzzing (QEMU --fuzz, qtest MMIO/PIO harness'leri, HYPERPILL tarzı hardware-assisted fuzzing) bu sınıfı deployment öncesinde sistematik olarak sürer.

Mitigation

  • QEMU'yu güncel tutun ve device başına CVE fix'lerini (örn. CVE-2016-3710) uygulayın; her fix, etkilenen callback'e eksik bounds check'i ekler.
  • Guest'in ihtiyaç duymadığı emüle device'ları disable edin / expose etmeyin (örn. bir paravirtual alternatifin var olduğu yerde legacy VGA/NIC modellerinden kaçının) ki MMIO/PIO callback attack surface'i daralsın.
  • QEMU'yu libvirt altında sVirt/SELinux ve seccomp ile unprivileged çalıştırın ki bir device callback'indeki bir OOB write, host yerine sandbox'lanmış QEMU process'iyle sınırlansın.

References