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
MemoryRegionOpsread/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:
- 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()üzerindenVBE_DISPI_INDEX_BANKindex'iyle. Handler, 16 MB'lık VGA RAM boyutuna karşı herhangi bir üst clamp olmadans->bank_offset = val << 16saklar. - Guest ardından VGA memory'ye bir MMIO access yapar.
vga_mem_writeb()/vga_mem_readb(), attacker-controlledbank_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. - 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/.writecallback'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,qtestMMIO/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.