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
VirtQueueElementallocation'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.
- 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 çokVirtQueueElementcache'ler. - Guest
virtio_net_receive_rcuiçinde erken bir hataya neden olur (örn. success-path cleanup'ından önce return eden bir header ya da length koşulu). - 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
VirtQueueElementallocation'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.maxaltı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.