Skip to content

QEMU PVRDMA CREATE_MR mremap flaw (CVE-2021-3582)

PVRDMA_CMD_CREATE_MR gönderen kötü niyetli bir guest, QEMU'nun pvrdma_map_to_pdir()'ini başlangıçta allocate edilenden daha fazla page'i mremap() etmeye sürer; yeni mapping'i host buffer'ının ötesine yürütür ve host QEMU process'ini corrupt eder/crash'ler.

Mechanism

Note

PVRDMA (hw/rdma/vmw/pvrdma), QEMU'nun paravirtual RDMA device'ıdır. Bir memory region register etmek için guest bir PVRDMA_CMD_CREATE_MR command'i submit eder; host create_mr() path'i nihayetinde, guest tarafından sağlanan page directory / page table list'inden tek bir contiguous host mapping'i monte etmek için pvrdma_map_to_pdir()'i çağırır. Bunu, guest-controlled bir chunk count'u (nchunks) kullanarak, ardışık guest DMA chunk'larını iteration başına bir tane olacak şekilde birlikte mremap() ederek yapar.

Isolation invariant'ı şudur: device'ın birbirine dikiş attığı chunk sayısı asla length / TARGET_PAGE_SIZE'ı aşmamalı — yani destination mapping'in başlangıçta rezerve edildiği boyutu. Bug, loop'un guest'in nchunks'ına güvenmesi ve her yeni mapping'in önceden rezerve edilmiş region'ın içinde kalıp kalmadığını kontrol etmeden remap etmeye devam etmesidir. nchunks, region'ın tutabileceğinden büyük olduğunda, tekrarlanan mremap() working pointer'ı başlangıçta allocate edilmiş host memory sınırının ötesine uzatır. Tüm bunlar host ayrıcalıklarıyla host QEMU process'inde çalıştığı için, bir out-of-bounds host access'i (DoS ve prensipte host memory corruption'ı) doğrudan bir guest command'inden ulaşılır — bir guest→host sınır aşımı.

Walkthrough

Üst düzey, public Red Hat advisory'sinden ve hw/rdma/vmw/pvrdma_cmd.c'ye yapılan upstream fix'ten. Yalnızca kavramsal:

  1. Guest driver bir memory-region registration'ı inşa eder: buffer'ı tanımlayan bir page directory ve page table'ları yerleştirir ve belirtilen region length'i ile tutarsız bir chunk count set eder (nchunks > length / TARGET_PAGE_SIZE).
  2. Guest PVRDMA_CMD_CREATE_MR submit eder. Host'ta, command dispatcher create_mr()'a yönlendirir; bu da chunk'ları coalesce etmek için pvrdma_map_to_pdir()'i çağırır.
  3. pvrdma_map_to_pdir(), tek bir contiguous mapping'i büyütmek için mremap() çağırarak chunk'lar üzerinde loop yapar — ama yeni mapping'in length'ten rezerve edilen region içinde kalıp kalmadığını verify etmez.

    /* representative shape — host loops over guest-controlled chunk count */
    for (...; i < nchunks; i++) {           /* nchunks comes from the guest */
        host_virt = mremap(curr_page, TARGET_PAGE_SIZE,
                           TARGET_PAGE_SIZE, MREMAP_FIXED | MREMAP_MAYMOVE,
                           next_slot);       /* next_slot can run past the region */
    }
    
  4. Iteration count'u length'in rezerve ettiğini aştığında, mapping target'ı başlangıçta allocate edilmiş sınırın ötesine yürür — QEMU'yu crash'leyen (availability etkisi) ve kavramsal olarak komşu host state'ini corrupt edebilen bir out-of-bounds host operation'ı.

Upstream fix, loop'u bound eder; böylece device asla region length'inin izin verdiğinden fazlasını remap etmez ve nchunks'a güvenmek yerine malformed command'i reddeder.

Observable effect on an unpatched build

Vulnerable bir build'de crafted CREATE_MR, bir QEMU crash'i (SIGSEGV) ya da AddressSanitizer altında mremap()/page-coalescing path'inde pvrdma_map_to_pdir()'de köklenen bir out-of-bounds raporu üretir.

Warning

Tarihsel, düzeltilmiş bir bug (CVE-2021-3582, CVE-2021-3607 ve CVE-2021-3608'i de içeren 2021 PVRDMA cluster'ının parçası). Yalnızca disclose edilen yapı gösteriliyor — hiçbir offset, heap layout'u ya da uçtan uca host exploit'i yok.

Detection

  • Bir guest PVRDMA_CMD_CREATE_MR'ından kısa süre sonra backtrace'i pvrdma_map_to_pdir / create_mr içeren QEMU SIGSEGV veya ASan heap/OOB raporu.
  • Untrusted bir guest'ten gelen PVRDMA command trafiği ile korele bir QEMU domain crash'ini gösteren host log'ları / libvirt.
  • Chunk count'u declare edilen region length'i ile tutarsız olan memory-region registration'ları submit eden guest'ler için audit/telemetry.

Mitigation

  • pvrdma_map_to_pdir() remap loop'unu length / TARGET_PAGE_SIZE'a karşı bound eden upstream fix'i uygula (QEMU ≥ 6.1.0 serisi; distro'lar tarafından backport'landı).
  • PVRDMA device'ını untrusted guest'lere expose etme; PVRDMA nadiren gereklidir ve büyük bir guest→host attack surface'idir — mümkün olan yerde guest'in device model'inden çıkar.
  • QEMU'yu libvirt altında SELinux/sVirt ve seccomp ile unprivileged çalıştır; böylece bir OOB access host'a değil, sandbox'lanmış process'e sınırlı kalır.

References