Skip to content

qianfei11/QEMU-CVES

Repository files navigation

QEMU-CVES — QEMU/KVM Vulnerability Reproduction Collection

A collection of QEMU/KVM vulnerability reproductions spanning information leaks, memory corruption, assertion failures, denial-of-service bugs, and full VM-escape chains.

Each subdirectory contains a self-contained reproduction environment: build scripts, a minimal Linux guest (Linux 5.4.40 + busybox), and a skeleton exploit.


CVE Index

Directory CVE QEMU Version Component Type
CVE-2015-3456 (VENOM)/ CVE-2015-3456 2.2.0-rc1 hw/block/fdc.c FIFO buffer overflow
CVE-2015-5165/ CVE-2015-5165 2.3.0 hw/net/rtl8139.c Information leak
CVE-2015-7504/ CVE-2015-7504 2.4.0 hw/net/pcnet.c Heap buffer overflow
CVE-2016-4952/ CVE-2016-4952 2.6.2 hw/scsi/vmw_pvscsi.c Host DoS (ring setup / infinite loop PoC)
CVE-2019-6788/ CVE-2019-6788 3.1.0 slirp/tcp_subr.c Heap buffer overflow
CVE-2019-14378/ CVE-2019-14378 4.0.0 slirp/ip_input.c Heap buffer overflow
CVE-2020-8608/ CVE-2020-8608 4.2.1 slirp/tcp_subr.c Heap buffer overflow
CVE-2020-14364/ CVE-2020-14364 4.2.1 hw/usb/core.c Out-of-bounds write
CVE-2020-25084/ CVE-2020-25084 4.2.1 hw/usb/hcd-xhci.c + hw/usb/core.c Assertion failure (xHCI)
Scavenger/ N/A (no CVE) 4.2.1 hw/block/nvme.c Uninitialized free (NVMe CMB)

Vulnerability Summaries

CVE-2015-3456 — VENOM (Floppy Disk Controller FIFO Overflow)

fdctrl_handle_drive_specification_command() in hw/block/fdc.c does not call fdctrl_reset_fifo() when a DRIVE_SPECIFICATION_COMMAND byte has bit-7 clear and data_len <= 7, leaving data_pos to advance past the 512-byte FIFO boundary on subsequent writes. Any adjacent heap data (e.g., a QEMUBH.cb function pointer) can be overwritten.

Patched in QEMU 2.3.0 (commit e6f4d0b) by adding the missing else branch that calls fdctrl_reset_fifo(). Confirmed working — clean QEMU v2.2.0-rc1 crashes with SIGSEGV at aio_bh_poll with rax = 0x4242424242424242.


CVE-2015-5165 — RTL8139 C+ Mode Information Leak

rtl8139_cplus_transmit_one() in hw/net/rtl8139.c insufficiently validates Ethernet/IP/TCP header lengths before performing checksum and TSO offload. A malformed IPv4 frame with IP Total Length < IHL can make the transmit path reuse uninitialised host heap bytes and leak them back to the guest through the emulated NIC loopback path.

This repository reproduction programs the RTL8139 directly from the guest, enables C+ transmit offload plus internal loopback, sends a malformed frame, and then recovers non-zero tail bytes / host-like pointers from guest-visible RX buffers. The bug is fixed by the XSA-140 patch series, which adds the missing short-packet and header-length checks before offload continues.


CVE-2015-7504 — PCNET Loopback CRC Heap Overflow

pcnet_transmit() in hw/net/pcnet.c appends a 4-byte CRC/FCS to the loopback transmit buffer. If the guest sends exactly 4096 bytes, the FCS write lands 4 bytes past the end of s->buffer, corrupting adjacent host device state (s->irq) and typically crashing the QEMU process.

This reproduction configures the emulated AMD PCnet card from guest userspace, places it into internal loopback mode, and sends an exact 4096-byte frame with an attacker-chosen final FCS so the overwrite is easy to recognise under GDB. The upstream fix reserves 4 bytes for the appended FCS (sizeof(s->buffer)-4).


CVE-2016-4952 — PVSCSI Ring-Setup Host DoS (Repository PoC)

This repository's implemented PoC exercises the PVSCSI ring-setup path in hw/scsi/vmw_pvscsi.c: sending PVSCSI_CMD_SETUP_RINGS with reqRingNumPages=0 makes pvscsi_ring_init_data() call pvscsi_log2(0xffffffff), after which the host-side loop never terminates.

Attack vector: MMIO (PCI BAR0) via the PVSCSI adapter. The PoC is treated as a host DoS verification under GDB, not as a guest-to-host code-execution exploit.


CVE-2019-6788 — SLiRP FTP/IRC tcp_emu() Heap Overflow

tcp_emu() in slirp/tcp_subr.c handles FTP PORT and IRC DCC traffic by parsing with sscanf then writing a rewritten string back into the same mbuf with snprintf, without checking that the result fits within the mbuf boundary. A guest can trigger the overflow by connecting to SLiRP's FTP emulation (port 21) or IRC (port 6667) and sending a crafted PORT or DCC command.

Related: CVE-2019-6778 (same family, SLiRP tcp_emu FTP PORT).


CVE-2019-14378 — SLiRP ip_reass() Heap Overflow

ip_reass() in slirp/ip_input.c reassembles fragmented IP datagrams. The allocated mbuf may be smaller than the total reassembled size when certain fragment offset combinations are presented, causing the subsequent memcpy of fragment data to overflow the mbuf.

Attack vector: raw IP socket inside the VM sending crafted fragmented UDP datagrams to the SLiRP gateway (10.0.2.2). Patched by adding a next > IP_MAXPACKET check before m_inc().


CVE-2020-8608 — SLiRP IRC DCC tcp_emu() Heap Overflow

Closely related to CVE-2019-6788. tcp_emu()'s IRC DCC SEND handler in slirp/tcp_subr.c rewrites the DCC packet's embedded IP address to the SLiRP external address. When the rewritten address is longer than the original, the snprintf call overflows the backing mbuf.

Attack vector: guest connects to 10.0.2.2:6667 and sends a DCC SEND with a 256-byte filename and a short internal IP that SLiRP expands to a longer external address.


CVE-2020-14364 — USB EHCI do_token_setup() Out-of-Bounds Write

do_token_setup() in hw/usb/core.c stores setup_len (derived from the guest-controlled SETUP packet) into s->setup_len before checking whether it exceeds sizeof(s->data_buf) (4096 bytes). Subsequent DATA stage packets copy up to s->setup_len bytes into data_buf, providing a controlled out-of-bounds write.

Call chain: ehci_work_bhehci_advance_stateehci_executeusb_handle_packetdo_token_setup. Requires --enable-spice at configure time (enables the EHCI controller). Patched by moving the s->setup_len assignment after the bounds check.


CVE-2020-25084 (xHCI) — xhci_fire_ctl_transfer Assertion Failure

xhci_fire_ctl_transfer() in hw/usb/hcd-xhci.c sends a control transfer with a DATA TRB whose direction field (TRB_TR_DIR) is set to OUT while the request is an IN transfer (GET_DESCRIPTOR, bmRequestType=0x80). The direction mismatch causes xhci_xfer_create_sgl() to call xhci_die() and destroy the SGL (nsg→0). xhci_setup_packet() ignores the error; usb_packet_map() returns 0 with iov.size=0; usb_handle_packet()usb_packet_copy() fires assert(p->actual_length + bytes <= iov->size).

Call chain: xhci_doorbell_writexhci_kick_epxhci_kick_epctxxhci_fire_ctl_transferusb_handle_packetusb_packet_copySIGABRT. Affects QEMU 4.2.1 and 5.0.0; the QEMU 4.2.1 binary from CVE-2020-14364/ can be reused.


Scavenger — NVMe CMB Uninitialized Stack Free → VM Escape (No CVE)

(Black Hat Asia 2021 — not CVE-2020-25084)

nvme_dma_read_prp() in hw/block/nvme.c declares a QEMUSGList on the stack without zero-initialising it, then passes it to nvme_map_prp(). On the error path, nvme_map_prp() jumps to unmap: and calls qemu_sglist_destroy() on the uninitialised stack struct, freeing stack garbage as heap pointers.

Full exploit chain (see Scavenger/README.md): heap spray → virtio-gpu UAF primitive → chunk reclaim → physmap leak → QEMU base derivation → timer hijack → system() on host.

Distinction from CVE-2020-25084: Scavenger targets hw/block/nvme.c (NVMe CMB) and achieves full VM escape. CVE-2020-25084 targets hw/usb/hcd-xhci.c (xHCI USB) and causes only a DoS (SIGABRT). No CVE has been assigned to Scavenger.


Common Workflow

Most directories follow a layout like:

CVE-XXXX-YYYY/
├── build.sh          # downloads + builds QEMU & Linux kernel (shared source at ../linux-5.4.40)
├── exploit.sh        # one-click verification (build check + GDB/timeout harness)
├── launch.sh         # boots the VM interactively
├── attach.sh         # boots the VM under GDB and auto-runs /exp via rdinit=/a.sh
├── kernel.config     # optional scenario-specific kernel config fragment
├── .gitignore
├── README.md
└── rootfs/
    ├── exp.c         # exploit source (guest-side C)
    ├── init          # initramfs init script
    ├── a.sh          # non-interactive exploit runner (rdinit target)
    ├── pack.sh       # repacks rootfs.cpio from rootfs/
    ├── etc/          # passwd, group, hostname, …
    ├── root/         # welcome banner
    └── bin/          # busybox symlinks (built by build.sh)

Generated artefacts (gitignored):

CVE-XXXX-YYYY/
├── qemu-system-x86_64  # vulnerable QEMU binary (copied by build.sh)
├── pc-bios/            # QEMU ROM files (copied by build.sh)
├── bzImage             # guest kernel (compiled from ../linux-5.4.40)
├── rootfs.cpio         # initramfs archive (packed by rootfs/pack.sh)
└── linux-build/        # out-of-tree kernel build directory

Shared infrastructure at repo root:

linux-5.4.40/           # shared kernel source tree (used by all CVEs)
default.config          # common kernel config options (base for all builds)

One-click reproduction

cd CVE-XXXX-YYYY/
./exploit.sh

exploit.sh checks whether qemu-system-x86_64 is present (running build.sh automatically if not), prints the expected success/crash/hang indicator, then launches the documented verification harness. For CVE-2019-14378, which causes a hang rather than a crash, a 90-second timeout is applied and exit code 124 confirms the bug.

Build

cd CVE-XXXX-YYYY/
chmod +x build.sh launch.sh attach.sh rootfs/pack.sh rootfs/a.sh
./build.sh

build.sh builds the vulnerable QEMU tag (either in /tmp/ or in a local source tree, depending on the directory) and copies qemu-system-x86_64 plus pc-bios/ into the scenario directory. It builds the Linux guest kernel from the shared source tree at ../linux-5.4.40, applying ../default.config first and then the directory's own ./kernel.config fragment (where present), and writes the out-of-tree build to ./linux-build/.

Interactive VM

./launch.sh      # opens a shell inside the VM; run /exp to trigger the bug

Automated verification (non-interactive)

./attach.sh      # launches GDB; the VM boots with rdinit=/a.sh, which runs /exp
                 # automatically; GDB stops on the documented crash/hang point

Infrastructure Notes

  • Guest kernel: Linux 5.4.40, shared source at linux-5.4.40/ in the repo root. Common options are in default.config; each CVE adds a ./kernel.config fragment on top (e.g. CONFIG_E1000=y for SLiRP CVEs, CONFIG_DEVMEM=y for MMIO CVEs). CVE-2015-3456 (VENOM) uses only the default config.
  • Busybox: each directory uses a static busybox binary in rootfs/bin/. If the binary is missing, build.sh copies it from the host system (/usr/bin/busybox or /bin/busybox). Install with sudo apt-get install busybox-static if needed.
  • QEMU 2.x quirks: requires Python 2 (--python=python2) and building with make IASL= subdir-x86_64-softmmu to avoid incompatibility with modern iasl.
  • Library path: launch.sh and attach.sh set LD_LIBRARY_PATH to $(conda info --base)/lib, providing libtinfow.so.6 and other runtime libraries from the active conda environment. libslirp.so.0 is used directly from the system (ldconfig). CVE-2020-8608 keeps two special locally-built libslirp variants (libslirp.so.0.1.0 debug-patched and libslirp-asan.so.0.1.0 ASAN-instrumented) that are not available from any package.

References

About

Recurrence of QEMU CVEs.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors