Key Files for QEMU CXL Type-3 Mailbox Exploitation in Exploitarium

The Exploitarium repository's QEMU CXL PoC relies on seven critical files—stage2.c, boot.asm, stage2.ld, build.sh, run.sh, poc.img, and README.md—to demonstrate a full-chain escape from a CXL Type-3 guest to arbitrary code execution on the QEMU host.

The bikini/exploitarium repository hosts a Proof-of-Concept that weaponizes a vulnerability in QEMU's CXL Type-3 device mailbox implementation. Understanding the QEMU CXL exploit requires analyzing how minimal bootloader assembly, freestanding C code, and shell scripts coordinate to hijack the hypervisor process. This guide breaks down each file's role in the exploit chain, from the initial 16-bit bootstrap to the final callback hijacking primitives.

Core Exploit Implementation Files

The exploit chain centers on three files that execute inside the guest environment: a bootstrap assembly loader, a linker script for binary layout, and the main payload driver.

boot.asm: 16-Bit BIOS Bootstrapper

The file qemu-cxl-type3-mailbox-escape-poc/boot.asm contains a minimal 16-bit BIOS loader that initializes the CPU and transitions to protected mode. It reads the secondary stage binary from the floppy image (poc.img) into memory and jumps to the entry point defined in stage2.c. This assembly stub establishes the execution environment required for the 32-bit C code to interact with PCI configuration space and the CXL mailbox registers.

stage2.c: Protected-Mode Exploit Orchestrator

Located at qemu-cxl-type3-mailbox-escape-poc/stage2.c, this freestanding 32-bit C binary contains the complete exploit logic. The _start function (at line 80) initializes serial output and triggers the multi-stage attack flow. Key functions include:

  • setup_pci() (line 67): Configures PCI BARs and enables the CXL Type-3 device mapping.
  • mailbox_cmd(u32 opcode, u32 len) (line 39): Writes command opcodes to the mailbox interface and polls for completion.
  • leak_rel(u32 rel) (line 48): Issues malformed GET_LOG mailbox commands to read out-of-bounds from the CXLType3Dev structure, leaking the QEMU PIE base and heap addresses.
  • forge_payload() (line 93): Constructs fake FlatView, AddressSpaceDispatch, MemoryRegionSection, MemoryRegion, and MemoryRegionOps structures in the mailbox payload buffer.
  • fake_write_call() (line 58): Transmits the forged structures and triggers a MEDIA_OPERATIONS command to invoke the hijacked MemoryRegionOps.write callback.

stage2.ld: Flat Binary Linker Script

The qemu-cxl-type3-mailbox-escape-poc/stage2.ld linker script specifies the memory layout for the protected-mode stage. It creates a flat binary output compatible with the bootloader's expectations, ensuring the _start symbol resides at the correct physical address for the 16-bit to 32-bit transition.

Build and Execution Automation

Three additional files handle the compilation pipeline and QEMU orchestration, ensuring reproducible exploitation environments.

build.sh: Guest Image Compilation Pipeline

The qemu-cxl-type3-mailbox-escape-poc/build.sh script automates the construction of poc.img. It assembles boot.asm using a 16-bit assembler, compiles stage2.c with freestanding 32-bit compiler flags, and packages both components into a bootable floppy image. This script ensures the bootloader and exploit stage are correctly aligned for the BIOS loading mechanism.

run.sh: QEMU CXL Device Launcher

The qemu-cxl-type3-mailbox-escape-poc/run.sh script configures and launches QEMU with the necessary QEMU CXL Type-3 device parameters. It attaches the poc.img as a floppy drive, enables the CXL volatile memory region, and validates successful exploitation by checking for the host marker file /tmp/qemu_cxl_escape_marker after the guest triggers the system() call.

poc.img: Pre-Built Bootable Payload

The qemu-cxl-type3-mailbox-escape-poc/poc.img file is the binary artifact generated by build.sh. It contains the concatenated bootloader and stage2 payload, ready for direct execution by QEMU's BIOS without requiring external storage emulation beyond the floppy interface.

Technical Exploit Mechanisms in stage2.c

Understanding the file contents requires examining how stage2.c manipulates the CXL mailbox interface to achieve host memory corruption.

Mailbox Command Interface

The mailbox_cmd() function provides the primitive for all CXL device interactions. It accepts an opcode and payload length, writes them to the mailbox command register, and spins until the control register indicates completion. This function drives the GET_LOG leaks and the final MEDIA_OPERATIONS trigger:

static void mailbox_cmd(u32 opcode, u32 len) {
    mmio_write64(MBOX_CMD, opcode | (len << 16), 0);
    w32(MBOX_CTRL, 1);
    while (r32(MBOX_CTRL) & 1)
        pause_cpu();
}

Host Address Space Leakage via GET_LOG

The leak_rel() function exploits an out-of-bounds read in the GET_LOG command handler. By calculating offsets relative to the CXLType3Dev structure base, it leaks 64-bit pointers from host memory:

static U64 leak_rel(u32 rel) {
    u32 off = GET_LOG_OOB_BASE_OFFSET + (rel >> 2);
    payload_write(0, cel_uuid, 16);
    w32(MBOX_PAYLOAD + 16, off);
    w32(MBOX_PAYLOAD + 20, 8);
    mailbox_cmd(CMD_GET_LOG, 24);
    return (U64){ r32(MBOX_PAYLOAD), r32(MBOX_PAYLOAD + 4) };
}

This leak exposes the QEMU binary base address and the address of internal device structures, enabling the calculation of fake object locations for the next stage.

Structure Forgery and Callback Hijacking

Using the leaked addresses, forge_payload() builds a chain of fake QEMU internal objects inside the mailbox payload buffer. It populates a fake MemoryRegionOps structure with a controlled function pointer in the .write field, typically targeting system() from the host libc. The fake_write_call() function then issues a MEDIA_OPERATIONS command that causes QEMU to interpret the forged structures as valid memory region descriptors, invoking the attacker-controlled callback with a crafted command string:

static void forge_payload(U64 rank_host, U64 fn, U64 opaque,
                          U64 mr_addr, const char *arg) {
    /* ... compute fake object addresses ... */
    put64(fake, FAKE_OPS_OFF + 8, fn);        // Set .write = system()
    /* ... copy command string into fake payload ... */
}

Summary

  • boot.asm: 16-bit bootstrap loader that transitions CPU to protected mode and loads the stage2 payload.
  • stage2.c: Core exploit logic implementing PCI setup, mailbox command primitives, host pointer leakage, and forged object injection.
  • stage2.ld: Linker script ensuring correct flat binary layout for the protected-mode stage.
  • build.sh: Automation script compiling assembly and C sources into the bootable poc.img.
  • run.sh: QEMU launcher configuring the CXL Type-3 device and verifying host compromise.
  • poc.img: Pre-built binary image containing the complete guest-side exploit chain.
  • README.md: Documentation covering usage instructions and architectural overview of the vulnerability.

Frequently Asked Questions

What is the purpose of stage2.c in the QEMU CXL exploit?

The stage2.c file contains the freestanding 32-bit payload that executes after the bootloader. It configures the PCI subsystem for CXL device access, leaks host memory pointers via malformed mailbox commands, forges fake QEMU internal structures, and triggers arbitrary code execution in the host process through a hijacked callback.

How does boot.asm interact with the CXL Type-3 exploit payload?

The boot.asm file initializes the CPU from real mode to protected mode and loads the stage2 binary from the floppy image into RAM. It serves as the entry vector that bridges QEMU's BIOS execution environment to the custom exploit code that manipulates the CXL mailbox registers.

Which script handles the QEMU CXL device configuration?

The run.sh script configures the QEMU CXL Type-3 device parameters when launching the virtual machine. It specifies the volatile memory backend, attaches the exploit image, and validates successful exploitation by checking for the presence of /tmp/qemu_cxl_escape_marker on the host filesystem after the guest triggers the vulnerability.

What QEMU internal structures does the exploit forge to achieve code execution?

According to the source in stage2.c, the exploit constructs fake versions of FlatView, AddressSpaceDispatch, MemoryRegionSection, MemoryRegion, and MemoryRegionOps. The forged MemoryRegionOps structure contains a controlled function pointer in its .write field, which QEMU invokes when processing a MEDIA_OPERATIONS mailbox command, redirecting execution to system() with attacker-controlled arguments.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →