QEMU PVRDMA page-table OOB read DoS (CVE-2023-1544)¶
Crafted bir PVRDMA guest driver'ı, bir page table'ın tutabileceğinden daha fazla ring page-table entry'si rapor eder; QEMU'nun
pvrdma_ring_next_elem_read()'i bunun üzerine ring descriptor'larını out of bounds okur ve host process'ini crash'ler (DoS).
Mechanism¶
Note
PVRDMA, completion-queue (CQ) ve async-event channel'larını guest'e
descriptor ring'leri olarak expose eder. Guest, backing page table'ları
allocate ve initialize eder ve device'a her ring'i kaç page-table entry'sinin
(page'in) oluşturduğunu söyler. Host tarafında,
pvrdma_ring_next_elem_read() bir sonraki ring element'ini fetch etmek için bu
page'leri walk eder.
Isolation invariant'ı şudur: guest'in rapor ettiği page-table entry count'u, tek bir page table'ın address'leyebileceğini aşmamalı — device, ring'i index'lemeden önce entry sayısının one-page-table size'ına sığdığını verify etmek zorundadır. Bug, device'ın guest tarafından sağlanan count'a güvenmesidir. Çok sayıda page table allocate ve initialize edip legitimate bound'un ötesinde bir entry count rapor ederek, kötü niyetli ya da buggy bir guest, host ring walk'unun mapped page-table memory'sinin ötesini index'lemesini sağlar ve host QEMU process'inde bir out-of-bounds read üretir. Read host ayrıcalıklarıyla ve attacker-influenced address'lerde execute olduğu için guest→host sınırını aşar; disclose edilen etki bir host crash / denial of service'tir.
Walkthrough¶
Üst düzey, public Red Hat advisory'sinden ve upstream hardening commit'inden ("hw/pvrdma: Protect against buggy or malicious guest driver"). Yalnızca kavramsal:
- Guest driver, CQ / async-event descriptor ring'ini backing etmesi amaçlanan aşırı sayıda page table allocate ve initialize eder.
- Guest, ring'i, unpatched device'ın validate etmediği bir değer olan rapor edilen page-table entry sayısı bir page table'ın kapasitesini aşacak şekilde programlar.
-
Host ring aktivitesini servis eder;
pvrdma_ring_next_elem_read(), guest tarafından sağlanan count'u kullanarak bir sonraki element'i okumak için page-table-backed ring boyunca ilerler. -
Count page-table bound'unun ötesindeyken, read mapped region'ın dışına düşer — QEMU'yu crash'leyen (availability etkisi) ve komşu host memory içeriğini disclose edebilecek bir out-of-bounds host read'i.
Upstream fix, explicit check'ler ekler; böylece device, ring'i walk etmek için kullanmadan önce bir page table'ın tutabileceğini aşan page-table entry count'larını reddeder.
Observable effect on an unpatched build
Vulnerable bir build'de crafted ring configuration'ı bir QEMU crash'i ya da
AddressSanitizer altında pvrdma_ring_next_elem_read()'de köklenen bir
out-of-bounds-read raporu verir.
Warning
Tarihsel, düzeltilmiş bir bug (CVE-2023-1544; QEMU 7.2.x / 8.x serisinde düzeltildi). Yalnızca disclose edilen yapı gösteriliyor — hiçbir offset, heap layout'u ya da weaponize edilmiş trigger yok.
Detection¶
- Untrusted bir guest'ten gelen PVRDMA ring/CQ aktivitesinden sonra backtrace'i
pvrdma_ring_next_elem_readiçeren QEMU SIGSEGV veya ASan OOB-read raporu. - PVRDMA trafiği ile korele tekrarlayan QEMU domain crash'lerini gösteren host/libvirt log'ları; bir ring için olağandışı çok sayıda page table initialize eden anormal guest'ler.
- Rapor edilen ring page-table-entry count'u tek bir page table'ın kapasitesiyle tutarsız olan guest'ler için telemetry.
Mitigation¶
- Ring'i walk etmeden önce page-table entry count'unu page-table size'ına karşı validate eden upstream fix'i uygula (QEMU ≥ 7.2.7 / 8.2.0; distro'lar tarafından backport'landı).
- PVRDMA device'ını untrusted guest'lere expose etme — RDMA'nın gerekli olmadığı yerlerde device model'inden çıkararak guest→host surface'ini daralt.
- QEMU'yu libvirt altında SELinux/sVirt ve seccomp ile unprivileged çalıştır; böylece bir OOB read sandbox'lanmış process'e sınırlı kalır.