QEMU PVRDMA REG_DSRHIGH uninit pointer (CVE-2021-3608)¶
Guest'in
PVRDMA_REG_DSRHIGHregister'ına yaptığı bir write, QEMU'yu düzgün şekilde initialize edilmemiş birring->pagesarray'i ilepvrdma_ring_init()'ten geçirir; böylece daha sonrardma_pci_dma_unmap()'e uninitialized bir pointer geçirilir — undefined behavior ve bir host crash'i.
Mechanism¶
Note
PVRDMA, Device Shared Region (DSR) aracılığıyla bootstrap olur: guest, DSR
address'ini low ve high yarılarını PVRDMA_REG_DSRLOW / PVRDMA_REG_DSRHIGH
register'larına yazarak yayınlar; bu da host'un DSR'yi load etmesini ve
ring'lerini pvrdma_ring_init() aracılığıyla initialize etmesini tetikler.
Isolation invariant'ı şudur: bir pointer ancak başarıyla initialize
edildikten sonra dereference ya da unmap edilmesi güvenlidir. Bug,
REG_DSRHIGH / DSR-load path'inde ring->pages array'inin düzgün şekilde
initialize edilmemiş bırakılabilmesidir; error/cleanup path'inde o
uninitialized pointer ardından rdma_pci_dma_unmap()'e verilir. Bir
uninitialized pointer
üzerinde işlem yapmak undefined behavior'dır — en azından bir QEMU crash'i
(DoS) ve guest'in etkileyebileceği bir değeri unmap/free etmek, düz bir NULL
deref'ten daha tehlikeli bir primitive'dir. Doğrudan bir guest register
write'ından ulaşıldığı ve host ayrıcalıklarıyla execute olduğu için guest→host
sınırını aşar.
Walkthrough¶
Üst düzey, public Red Hat advisory'sinden ve hw/rdma/vmw/pvrdma_dev_ring.c'deki
upstream fix'ten. Yalnızca kavramsal:
- Guest, DSR high address'ini
PVRDMA_REG_DSRHIGHMMIO register'ı aracılığıyla yazar ve host'u DSR'yi load edip ring'leri initialize etmeye yönlendirir. - Host'ta
pvrdma_ring_init()ring'i kurar ama unpatched path'tering->pages'i düzgün şekilde initialize edilmemiş bırakabilir (örn. bir mapping adımı yarı yolda fail ettiğinde). -
Sonraki cleanup
ring->pages'i walk eder ve onun entry'leri üzerinde — uninitialized slot dahil —rdma_pci_dma_unmap()'i çağırır. -
Unmap routine'ine geçirilen uninitialized pointer undefined behavior üretir: bir QEMU crash'i (availability etkisi) ya da attacker-influenced bir değer üzerinde operasyonlar.
Upstream fix, ring->pages'i initialize eder (ve failure/cleanup path'ini sıkar);
böylece DMA-unmap routine'ine asla uninitialized bir pointer geçirilmez.
Observable effect on an unpatched build
Vulnerable bir build'de crafted DSR setup'ı bir QEMU crash'i ya da
AddressSanitizer / MemorySanitizer altında pvrdma_ring_init →
rdma_pci_dma_unmap path'inde bir use-of-uninitialized-value veya
invalid-free raporu verir.
Warning
Tarihsel, düzeltilmiş bir bug (CVE-2021-3608,
CVE-2021-3582 ve CVE-2021-3607 —
init_dev_ring()'te integer-overflow kaynaklı unchecked malloc, ayrı bir DoS —
ile birlikte 2021 PVRDMA cluster'ının parçası). Yalnızca disclose edilen yapı
gösteriliyor — hiçbir offset ya da weaponize edilmiş trigger yok.
Detection¶
- Bir guest
PVRDMA_REG_DSRHIGHwrite'ından hemen sonra, backtrace'ipvrdma_ring_initverdma_pci_dma_unmapiçeren QEMU SIGSEGV / invalid-free veya MSan/ASan uninitialized-value raporları. - Untrusted bir guest'ten gelen PVRDMA DSR initialization'ı ile korele QEMU domain crash'lerini gösteren host/libvirt log'ları.
- DSR (re)initialization'ını tekrar tekrar tetikleyen, özellikle error path'lerini vurmak için tasarlanmış kısmen geçerli mapping'lerle yapan guest'ler için audit.
Mitigation¶
ring->pages'i initialize eden upstream fix'i uygula (QEMU ≥ 6.1.0; distro'lar tarafından backport'landı); böylecerdma_pci_dma_unmap()'e hiçbir uninitialized pointer ulaşmaz.- PVRDMA device'ını untrusted guest'lere expose etme — RDMA'nın gerekli olmadığı yerlerde device model'inden çıkar.
- QEMU'yu libvirt altında SELinux/sVirt ve seccomp ile unprivileged çalıştır; hardening ile compile et (örn. CI'da trap-on-uninitialized tooling) ki bu class erken yakalansın.
References¶
- Red Hat Bugzilla — CVE-2021-3608: pvrdma uninitialized memory unmap in pvrdma_ring_init()
- NVD — CVE-2021-3608
- Ubuntu security — CVE-2021-3608
- Red Hat Bugzilla — CVE-2021-3607: pvrdma unchecked malloc size due to integer overflow in init_dev_ring()
- NVD — CVE-2021-3607
- Related: PVRDMA CREATE_MR mremap flaw, access of uninitialized pointer primitive, null-pointer dereference primitive