Skip to content

QEMU virtio DMA reentrancy double-free (mem_reentrancy_guard bypass)

CVE-2024-3446: virtio-gpu, virtio-serial-bus ve virtio-crypto, kendi bottom-half işlemeleri sırasında guest tarafından programlanmış bir DMA write üzerinden yeniden girilebiliyordu; mem_reentrancy_guard bottom-half (BH) path'ini kapsamadığı için host nesnelerini iki kez free ediyordu.

Mechanism

Note

QEMU bir guest physical address'i host process'ine address_space_map() ile map'ler. Descriptor düz RAM yerine device MMIO'ya işaret ettiğinde, o map (ya da sonraki bir erişim) hedef device'ın kendi read/write callback'ine yeniden girer. Bir device'ın işlem ortasında kendi içine recursive olarak yeniden girmesini önlemek için QEMU, her MemoryRegion başına mem_reentrancy_guard.engaged_in_io flag'ini ekledi (e1000e ve nvme DMA-reentrancy UAF'leri tarafından istismar edilen aynı invariant). İzolasyon invariant'ı şudur: bir device bir request'i işlerken, guest tarafından tetiklenen bir DMA o device'ın handler'ının çakışan state üzerinde yeniden çalışmasına neden olmamalıdır. CVE-2024-3446 o guard'daki bir boşluktur. virtio-gpu, virtio-serial-bus ve virtio-crypto, işi device'ın I/O path'inin kullandığı guard nesnesine değil, bus/transport'a bağlı düz qemu_bh_new_guarded() ile oluşturulan bir QEMUBH'a (bottom half) erteliyordu. Bir guest, bir buffer/VirtQueueElement zaten in-flight iken device'ın BH'ına yeniden giren bir DMA ayarlayabilirdi, böylece aynı host nesnesi iki kez free edilirdi — tamamen kötü niyetli bir guest'ten erişilebilir bir heap double-free, guest→host sınırını geçiyor.

Walkthrough

Public, patch'lenmiş materyal, upstream fix serisi "hw/virtio: Protect from more DMA re-entrancy bugs"'tan (Philippe Mathieu-Daudé, QEMU 9.0 için). Yalnızca kavramsal path:

  1. Guest, buffer adresi bir device MMIO region'a (RAM değil) çözümlenen bir virtqueue descriptor programlar, böylece QEMU'nun DMA erişimi bir device handler'a yeniden girer.
  2. Hedeflenen virtio device'ı (gpu / serial-bus / crypto) bir request üzerinde in-flight'tır ve işlemesini bir QEMUBH'a schedule etmiştir. O BH yalnızca transport seviyesinde guard edildiği için, nested re-entry handler'ı paylaşılan state üzerinde yeniden çalıştırır.
  3. Handler, dış (hâlâ unwind edilmemiş) çağrının da free ettiği bir host nesnesini (örn. bir request/VirtQueueElement ile ilişkili bir allocation) free eder — QEMU host heap'inde bir double free.

Temsili fix şekli (alıntılanan seriden): bottom half'in bus guard yerine device'ın reentrancy guard'ını paylaşması için DeviceState * alan yeni bir helper virtio_bh_new_guarded() tanıtıldı ve üç device qemu_bh_new_guarded()'tan ona geçirildi:

hw/virtio: Introduce virtio_bh_new_guarded() helper
hw/display/virtio-gpu:     Protect from DMA re-entrancy bugs
hw/char/virtio-serial-bus: Protect from DMA re-entrancy bugs
hw/virtio/virtio-crypto:   Protect from DMA re-entrancy bugs
Patch'lenmemiş bir build'de gözlemlenebilir etki

AddressSanitizer / glibc malloc hardening altında, crash, guest MMIO-destekli descriptor'ı gönderdikten sonra etkilenen virtio device'ının BH callback'i içinde bir double free or corruption / ASan attempting double-free abort olarak yüzeye çıkar. İyi niyetli bir guest'te driver'lar descriptor'ları hiçbir zaman device MMIO'ya yönlendirmez, dolayısıyla bu path asla çalıştırılmaz.

Warning

Tarihsel, düzeltilmiş bug class'ı (CVE-2024-3446, QEMU 9.0'da patch'lendi ve distro'lar tarafından backport edildi). Silahlandırılmış offset'ler, heap-grooming reçetesi ya da uçtan uca RCE chain'i verilmemiştir — yalnızca double-free'nin açıklanmış yapısı.

Detection

  • Host tarafı crash imzaları: bir virtio device bottom-half'inde (virtio-gpu / virtio-serial-bus / virtio-crypto) handler'ından kaynaklanan glibc double free or corruption, ya da ASan double-free raporları.
  • İşi device-scoped virtio_bh_new_guarded() yerine guard edilmemiş qemu_bh_new_guarded() üzerinden schedule eden virtio device'larını denetleyin.
  • Reentrancy/DMA fuzzing'i (descriptor'lar device MMIO'ya yönlendirilmiş) bu class'ı deployment öncesi yeniden üretir; aynı harness ilgili e1000e / nvme reentrancy bug'larını da bulur.

Mitigation

  • QEMU 9.0+'a ya da CVE-2024-3446 backport'unu (virtio_bh_new_guarded() device-scoped guard'ı) taşıyan bir distro build'ine güncelleyin.
  • QEMU process'indeki bir double-free'nin host kontrolüne dönüşmek yerine sınırlanması için QEMU'yu libvirt altında SELinux/sVirt sandboxing ile unprivileged çalıştırın.
  • Bir device gereksiz olduğunda onu guest'e açmayın (virtio attack surface'ini azaltın).

References