Skip to content

QEMU virtio-net error-path memory leak (CVE-2022-26353)

Daha önceki bir virtio-net use-after-free için yapılan fix, receive-queue element'lerini bir array'de cache'ledi ama receive bir error path'e girdiğinde onları detach etmeyi unuttu; bu da host DMA mapping'lerini ve VirtQueueElement allocation'larını leak etti — guest tarafından sürülen bir host memory exhaustion.

Mechanism

Sınır neden kırılıyor

QEMU'nun virtio-net receive path'i (hw/net/virtio-net.c içindeki virtio_net_receive_rcu) RX virtqueue'den bir ya da daha fazla descriptor pop eder, guest'in sağladığı buffer adreslerini host address space'ine map'ler ve gelen frame'i onlara kopyalar. CVE-2021-3748'in use-after-free'sini onarmak için, pop edilen VirtQueueElement nesneleri yerel bir elems[] array'inde cache'lendi ve yalnızca tüm frame yazıldıktan sonra unmap/free edildi. Regresyon: cleanup loop'u yalnızca success path'inde çalıştı. Receive erken abort ettiğinde — aşırı büyük bir frame, kötü bir header ya da yarı yolda bir mapping hatası — fonksiyon elems[]'i iterate etmeden return etti, böylece her cache'lenmiş element'in guest-to-host DMA mapping'i (address_space_map referansı) ve heap allocation'ı hiç release edilmedi. Bu bir missing-release-of-resource bug'ıdır (CWE-772): ihlal edilen invariant şudur: bir virtqueue'den pop edilen her nesne, error path'leri dahil her exit path'inde push ile geri verilmeli ya da açıkça detach edilmelidir. Error branch'ini tekrar tekrar zorlayan bir guest, QEMU process tükenene kadar host belleğini ve mapping table girdilerini leak eder — denial of service ve diğer device state'ini karmaşıklaştıran bayat mapping birikimi. Bu, exit-path simetrisi korunmazsa bir memory-safety bug'ını patch'lemenin nasıl bir başkasını sokabileceğinin ders kitabı örneğidir. Leak primitive'i için ../primitive/memory-leak-oracle.md'a ve bu patch'in kapatmaya çalıştığı bug için ../primitive/use-after-free.md'a bakın.

Walkthrough

Upstream commit ve Red Hat advisory'sinden kavramsal yeniden kurgu; yalnızca mantıksal adımlar.

  1. Kötü niyetli bir guest virtio-net RX virtqueue'sünü sürer ve buffer descriptor'ları kısmen bir non-direct-access region'a işaret eden bir frame ayarlar, böylece QEMU kopyalamadan önce elems[]'te birden çok VirtQueueElement cache'ler.
  2. Guest virtio_net_receive_rcu içinde erken bir hataya neden olur (örn. success-path cleanup'ından önce return eden bir header ya da length koşulu).
  3. Cache'lenmiş element'ler map'lenmiş ve allocate edilmiş bırakılır. Bunu binlerce kez tekrarlamak host DMA mapping'lerini ve belleği leak eder ve QEMU process'ini tüketir.
Root-cause ve fix fragment'i

Onarılmış error path, her cache'lenmiş element'i leak etmek yerine detach eder:

/* on error, release everything popped so far */
for (j = 0; j < i; j++) {
    virtqueue_detach_element(q->rx_vq, elems[j], lens[j]);
    g_free(elems[j]);
}

"This flaw was inadvertently introduced with the fix for CVE-2021-3748, which forgot to unmap the cached virtqueue elements on error, leading to memory leakage and other unexpected results." — NVD CVE-2022-26353

Detection

  • Host bellek büyümesi: QEMU process'inin, karşılık gelen bir guest workload'ı olmadan tek bir guest'ten gelen virtio-net RX aktivitesiyle korele şekilde sürekli tırmanan RSS'i birincil sinyaldir (cgroup memory.current, /proc/<pid>/status).
  • Mapping/table baskısı: Bir test build'inde bir leak detector (Valgrind/ASan) altında görünür şekilde aktif address-space mapping'lerinin ya da VirtQueueElement allocation'larının sayısındaki büyüme.
  • Telemetri: virtio-net receive error branch'ine tekrarlanan giriş ya da bir guest'in kasıtlı olarak hatalı biçimlendirilmiş RX descriptor'ları sunması anormaldir ve device-model tracing (receive path'inde trace-event) ile yüzeye çıkarılabilir.

Mitigation

  • Patch: QEMU 6.2 stable'da ve vendor errata'da (RHSA-2022:5263 ve eşdeğerleri) gönderilen upstream fix abe300d9 ("virtio-net: fix map leaking on error during receive")'ı uygulayın.
  • Resource cap'leri: QEMU'yu bir cgroup memory.max altında çalıştırın, böylece bir leak host'u değil yalnızca sorunlu VM'i DoS'lar; OOM-kill alerting ile eşleştirin.
  • Sandboxing: Tehlikeye girmiş bir QEMU'yu sınırlamak için -sandbox on (seccomp) ve svirt/AppArmor confinement kullanın; bunlar leak'i durdurmaz ama blast radius'unu sınırlar.
  • Defense in depth: Caching getiren herhangi bir memory-safety patch'ini exit-path review gerektiriyor olarak ele alın — pop edilen her virtqueue element'i tüm return'lerde release edilmelidir.

References