Full Report
QEMU is a machine emulator and virtualizer that let's a host system run guest operating systems of any architecture. For this post, they decided to review Virtio Devices because they require an interface with the host operating system. virtio-snd device buffers are stored in a FIFO linked list after being popped from the virtqueue. In virtio_snd_handle_rx_xfer() there is a code for computing the proper size to use. This takes the size of a buffer and subtracts the size of a struct from it. However, this calculation can underflow by using a small buffer, giving us the first bug. In virtio_snd_pcm_in_cb() the usage of a buffer vs. the allocation is slightly off. First, the allocation size and the bounds check have an 8 byte difference, allowing for an 8 byte OOB write. The final bug was missing bounds check in the edge case of user provided values, creating another OOB write. This happened because the actual buffer allocation size was taken into account. The exploit focuses on the third bug because it contains the largest overflow. Each of these bugs is in the audio input path coming from the host side. So, the OOB write is effectively random. What can we even do with a write with uncontrolled data? Their initial idea was to overwrite a data structure with a size within QEMU but they couldn't find a suitable target. So, they targetted glibc, the heap allocator itself, to corrupt a tcache bin sized chunk size. This allowed them to free a chunk with an oversized entry into the tcache freelist. To perform a heap spray and get a better allocation primitive, they used the paravirtualized filesystem device virtio-9p. With each P9_TXATTRCREATE a host-side buffer is allocated with a name and value field, where the size is arbitrarily controlled. It can be written back to and read through later. An allocation on demand with a choosen size, fully controllable contents and the ability to free as needed. This is perfect for heap exploitation! To use the corruption, they fill up the bins and flush them continuously. Eventally, a write will occur on a 0x200 sized chunk on the size that will make it LARGER than the intended size. Once this is freed into the 0x210-0x2f0 bin it's overallocated. After reurning this chunk, a write to it will corrupt the size of the FOLLOWING chunk ahead of it with a user controlled value of 0x400. Now, the chunk has a complete overlap with the chunk ahead of it. This is a super useful state to be in. To get a heap leak, they use the tcache free list fd pointer. When it's the only entry in the list, safe linking is effectively useless because it's XORed with 0x00. They lost the final 12 bits. With this primitive, they write a pointer to the fd slot that is controlled and then read the memory. At this point, they can just reverse the XOR and read the slot. This effectively creates an encryption oracle to get the bits out. Pretty neat! Using the object V9fsFidState, they were able to produce an arbitrary read/write from the tcache poisioning primitive. By allocating an overlapped chunk with this object, there is a pointer that is directly controllable. This can be used for both reads and writes, which is effectively game over at this point. This bug sat in the codebase for over 2 years but was fixed the same week that OtterSec found it. Still, this is a great example of turning a small bug into something much larger with cascading improvements to exploitability. Great post!
Analysis Summary
# Vulnerability: QEMU virtio-snd Heap Overflow and Hypervisor Escape
## CVE Details
- **CVE ID**: Not explicitly named in the text (identified by OtterSec as a 0-day at the time of discovery).
- **CVSS Score**: Estimated 8.8 (High) / 9.0 (Critical) based on Guest-to-Host escape capabilities.
- **CWE**: CWE-122 (Heap-based Buffer Overflow), CWE-131 (Incorrect Calculation of Buffer Size), CWE-191 (Integer Underflow).
## Affected Systems
- **Products**: QEMU (machine emulator and virtualizer).
- **Versions**: Found in commit `ece408818d27f745ef1b05fb3cc99a1e7a5bf580` (Feb 2026). The code was present in the codebase for over 2 years prior to the fix.
- **Configurations**: Systems using the `virtio-snd` (virtio sound) device for audio input/capture.
## Vulnerability Description
Three distinct bugs were identified within the `virtio-snd` audio input path:
1. **Integer Underflow**: In `virtio_snd_handle_rx_xfer()`, the size for a buffer allocation is calculated by subtracting `sizeof(virtio_snd_pcm_status)` from the guest-provided iovec size. A small guest-provided buffer causes an underflow, leading to an undersized allocation.
2. **OOB Write (8-byte)**: In `virtio_snd_pcm_in_cb()`, a discrepancy between the allocation size and the bounds check logic allows for an 8-byte out-of-bounds (OOB) write.
3. **Uncontrolled OOB Write**: A missing bounds check in an edge case involving user-provided values allows a larger OOB write. Because the data written comes from the host-side audio input path, the content of the overflow is effectively "random" or uncontrolled by the attacker.
## Exploitation
- **Status**: PoC available. Successfully exploited to achieve guest-to-host escape (executing `gnome-calculator` on host).
- **Complexity**: High (Requires sophisticated heap grooming and glibc-specific exploitation techniques).
- **Attack Vector**: Adjacent (Guest OS to Host Hypervisor).
### Exploitation Strategy:
- **Heap Spray**: Used the `virtio-9p` (paravirtualized filesystem) device. By calling `P9_TXATTRCREATE`, an attacker can allocate host-side buffers of arbitrary size and content.
- **Primitive**: Targeted the `glibc` (v2.43) heap allocator. By using the uncontrolled write to corrupt a `tcache` bin chunk size, the attacker forced a chunk overlap.
- **Leak**: Exploited `tcache` safe linking behavior. By manipulating the free list so only one entry remained (XORed with 0x00), the attacker bypassed protection to leak heap addresses.
- **Control**: Overlapped a controlled chunk with a `V9fsFidState` object to gain arbitrary read/write, eventually overwriting `VirtQueue.handle_output` to redirect execution to `system()`.
## Impact
- **Confidentiality**: High (Full memory read access on host).
- **Integrity**: High (Arbitrary code execution on host).
- **Availability**: High (Total host system compromise).
## Remediation
### Patches
- The bug was fixed by the QEMU maintainers the same week it was reported by OtterSec (March 2026). Users should update to the latest QEMU stable release or pull the latest commits from the official repository.
### Workarounds
- Disable the `virtio-snd` device in QEMU configurations if audio input from the guest is not required.
- Limit guest permissions to prevent access to hardware device configurations.
## Detection
- **Indicators of Compromise**: Unexpected QEMU process crashes; unusual heap allocation patterns in host memory; execution of unauthorized subprocesses (e.g., `/bin/sh`) by the QEMU user.
- **Detection Methods**: Monitor for guest attempts to send malformed or undersized iovecs to the `virtio-snd` device.
## References
- OtterSec Blog: `https://osec[.]io/blog/2026-03-17-virtio-snd-qemu-hypervisor-escape/`
- Exploit Source: `https://github[.]com/otter-sec/qemu-escape`
- QEMU Project: `https://www[.]qemu[.]org/`