Skip to content

QEMU virtio-snd heap buffer overflow (virtio_snd_pcm_in_cb)

CVE-2024-7730: QEMU'nun virtio-snd PCM input callback'indeki eksik bir maximum-size bounds check, receive iovec'inde audio data için yer olmadığında bir guest'in host tarafı bir heap buffer overflow'u zorlamasına izin veriyor.

Mechanism

Note

Bir virtio device guest tarafından virtqueue'lar üzerinden sürülür: guest scatter/gather descriptor'ları (bir iovec) gönderir ve host device model'i onları doldurur. PCM input (capture) path'i için host, iovec'in toplam kapasitesini katı bir tavan olarak ele almalı ve onun ötesine asla yazmamalıdır. QEMU'nun virtio_snd_pcm_in_cb()'i bunun yerine buffer başına buffer->size field'ını çalışan bir şimdiye-kadar-toplam akümülatör'ü olarak kullandı (transmit path'inin kaçındığı pattern) ve audio'yu hiçbir zaman iovec'in gerçek boyutuyla karşılaştırmadan döngüyle yazdı. Guest, toplam uzunluğu sizeof(virtio_snd_pcm_status)'a (8 byte'lık status footer'ı) eşit bir in_sg iovec yayımladığında, audio data için kullanılabilir alan sıfırdır — yine de callback audio'yu AUD_read ile buffer'a okumaya devam eder ve host allocation'ının ötesine yazar. Toplam uzunluk sizeof(virtio_snd_pcm_status)'tan küçük olduğunda ise iov_size(...) - sizeof(virtio_snd_pcm_status) çıkarması bir integer underflow yapar, dolayısıyla sorun yalnızca eşitlik değil bu underflow case'ini de kapsar. İzolasyon sınırı geçilir çünkü guest'in sağladığı descriptor geometrisi doğrudan host (QEMU process) heap write'larını yönlendirir.

Walkthrough

Kavramsal, halihazırda patch'lenmiş path (public materyal: GitLab issue #2427, fix commit 98e77e3d ve osec.io writeup'ı).

  1. Geometri: guest, in_sg/in_num'u toplam boyutu == sizeof(virtio_snd_pcm_status) (8 byte) olan bir iovec tanımlayan bir RX virtqueue element'i enqueue eder ve sıfır data kapasitesi bırakır.
  2. Allocation: host data region'ını iov_size(in_sg, in_num) - sizeof(virtio_snd_pcm_status)'tan boyutlandırır. iovec tam olarak 8 byte olduğunda bu 0 byte'tır; guest iovec'i sizeof(virtio_snd_pcm_status) (8 byte)'dan küçük yaptığında ise iov_size(...) - sizeof(virtio_snd_pcm_status) çıkarması bir integer underflow yapar; unsigned arithmetic'te sonuç çok büyük bir değere wrap'lenir ve hesaplanan "kalan kapasite" gerçek alandan kopar — yani sorun yalnızca eşitlik (==) değil, iov_size(...) < sizeof(virtio_snd_pcm_status) underflow case'ini de kapsar.
  3. Overflow: virtio_snd_pcm_in_cb() capture loop'unu çalıştırır ve gelen audio'yu gerçek (sıfır) kapasiteyi hesaba katmayan bir limitle AUD_read üzerinden yazar, audio byte'larını küçük boyutlu chunk'ın ötesine taşırır.
  4. Corruption: komşu glibc heap metadata'sı bozulur. osec.io araştırması 0x200 boyutunda bir komşu (bir virtio-9p xattr değeri) groom eder ve daha fazla heap exploitation'ı bootstrap etmek için onun size field'ını bozar.

Fix, herhangi bir write öncesinde eksik tavanı ekler:

max_size = iov_size(buffer->elem->in_sg, buffer->elem->in_num);
for (;;) {
    if (buffer->size >= max_size) {
        return_rx_buffer(stream, buffer);
        break;
    }
    /* ... AUD_read into the remaining space ... */
}

Warning

Overflow içeriği audio stream'idir — saldırgan tarafından etkilenir ama tam olarak keyfi değildir — bu yüzden bu, kontrole ulaşmak için hassas heap grooming ile eşleştirilmesi gereken bir uncontrolled overflow'dur. CVE-2026-3195 aynı callback'in eksik bir fix regresyonudur; herhangi bir backport'un gerçekten her write'ı bound ettiğini doğrulayın.

Detection

  • Host/sandbox: QEMU'yu ASan/-fsanitize=address altında çalıştırın; hw/audio/virtio-snd.c içindeki OOB write hemen bir heap-buffer-overflow olarak işaretlenir (fuzzing issue #2427'yi tam olarak böyle yüzeye çıkardı).
  • virtio-snd için toplam uzunluğu status footer boyutuna eşit (data room yok) RX descriptor'ları yayımlayan bir guest, bir device-model monitor'ün loglayabileceği anormal, şüpheli bir pattern'dir.
  • virtio-snd capture aktivitesiyle korele QEMU crash'leri/abort'larını izleyin.

Mitigation

  • Patch: fix commit 98e77e3d (QEMU ≥ 9.1.0)'i ve CVE-2026-3195 takibini uygulayın; input callback'in her write'ı iov_size(in_sg, in_num) ile bound ettiğinden emin olun.
  • Attack surface reduction: Gerekli olmadıkça virtio-snd'yi untrusted guest'lere açmayın; audio capture'a ihtiyaç duymayan VM config'lerinden device'ı kaldırın.
  • Defense in depth: Host tarafı bir overflow'un minimum blast radius'una sahip olması için QEMU'yu sandboxed (seccomp, -sandbox on), düşük ayrıcalıklı confined bir process olarak (SELinux/AppArmor svirt) çalıştırın.

References