# How to Exploit the CXL GET_LOG Handler Vulnerability in QEMU: A Full Chain Guide

> Exploit the CXL GET_LOG handler vulnerability in QEMU with this full chain guide. Learn to leak host pointers and achieve arbitrary code execution in the QEMU host process.

- Repository: [bikini/exploitarium](https://github.com/bikini/exploitarium)
- Tags: how-to-guide
- Published: 2026-09-07

---

**You can exploit the CXL GET_LOG handler vulnerability in QEMU by leveraging an out-of-bounds read in the Type-3 mailbox command handler to leak host pointers, then using an unchecked SET_FEATURE rank-sparing write to forge memory-management objects that ultimately trigger arbitrary code execution in the QEMU host process.**

The CXL Type-3 mailbox implementation in QEMU contains critical validation flaws that allow guest-to-host escape. According to the `bikini/exploitarium` repository, these vulnerabilities reside in the mailbox command handlers where boundary checks are improperly implemented, enabling an attacker to first disclose sensitive memory addresses and subsequently achieve arbitrary write capabilities leading to full system compromise.

## Understanding the GET_LOG Validation Flaw

The root cause lies in how the GET_LOG handler validates its arguments. As documented in the repository's analysis of [`qemu-cxl-type3-mailbox-escape-poc/README.md`](https://github.com/bikini/exploitarium/blob/main/qemu-cxl-type3-mailbox-escape-poc/README.md) at lines 141-149, the handler verifies that `offset + length` fits within the internal log buffer size (`sizeof(cci->cel_log)`). However, it then uses `offset` directly as an array index without ensuring `offset` itself is within the buffer bounds.

This discrepancy creates an **out-of-bounds read** primitive. By providing a large `offset` value that passes the aggregate range check but indexes beyond the buffer boundary, a guest can leak arbitrary host memory contents, including QEMU's PIE base and the `CXLType3Dev` object address.

### The Unchecked SET_FEATURE Write Primitive

Complementing the read vulnerability, the SET_FEATURE rank-sparing handler lacks proper bounds checking on its write operations. As noted in [`README.md`](https://github.com/bikini/exploitarium/blob/main/README.md) at lines 151-156, this handler copies guest-controlled data into the `rank_sparing_wr_attrs` structure without validating the destination bounds. This provides an **arbitrary write** primitive into host memory relative to the `CXLType3Dev` object.

## The Five-Stage Exploit Chain

The proof-of-concept implemented in [`stage2.c`](https://github.com/bikini/exploitarium/blob/main/stage2.c) executes a complete chain that transforms these primitives into full code execution:

1. **Leak Host Pointers via GET_LOG**: Issue the GET_LOG command with a crafted offset to read beyond the `cel_log` buffer, extracting a QEMU text pointer and the `CXLType3Dev` object address from host heap memory.

2. **Calculate Base Addresses**: Derive the QEMU PIE base from the leaked text pointer, then calculate the exact host address of the `CXLType3Dev` structure using offsets determined from the leaked data.

3. **Forge Memory-Management Objects**: Use the SET_FEATURE rank-sparing command to write a carefully constructed payload past the end of `rank_sparing_wr_attrs`. This forges a complete chain of QEMU objects including `FlatView`, `AddressSpaceDispatch`, `MemoryRegionSection`, `MemoryRegion`, and `MemoryRegionOps` structures.

4. **Trigger the Callback**: Invoke the MEDIA_OPERATIONS mailbox command, which walks the forged address space and eventually calls the controlled `MemoryRegionOps.write` callback.

5. **Achieve Code Execution**: The callback redirects execution to attacker-controlled code, typically invoking `system("/bin/sh")` to escape the guest and execute commands in the host environment.

## Implementation Details from stage2.c

The 32-bit guest payload in [`stage2.c`](https://github.com/bikini/exploitarium/blob/main/stage2.c) demonstrates the exploitation sequence. First, it issues the out-of-bounds GET_LOG command as shown at lines 24-36 and 250-254:

```c
/* Issue GET_LOG to leak host pointers */
u32 off = GET_LOG_OOB_BASE_OFFSET + (rel >> 2);
mailbox_cmd(CMD_GET_LOG, 24);   // Sends GET_LOG request

/* Extract leaked data from the out-of-bounds scratch area */
qemu_base = handler - CMD_LOGS_GET_LOG_OFF;               // PIE base
ct3d_host  = qemu_base + GET_LOG_OOB_MEM_BASE_FROM_CT3D; // CXLType3Dev address

```

After calculating the base addresses at lines 392-402, the exploit crafts the payload and writes it via SET_FEATURE:

```c
/* Forge the dynamic-capacity objects using SET_FEATURE */
memcpy((uint8_t *)&ct3d->rank_sparing_wr_attrs + hdr->offset,
       crafted_payload, payload_len);

/* Trigger the forged write callback */
mailbox_cmd(CMD_MEDIA_OPERATIONS, ...);

```

Key files in the `bikini/exploitarium` repository support this exploitation:

- [`stage2.c`](https://github.com/bikini/exploitarium/blob/main/stage2.c): Contains the 32-bit protected-mode payload that drives PCI config space access and issues the mailbox commands.
- `boot.asm`: Provides the 16-bit bootloader that initializes the system and loads the main stage.
- [`run.sh`](https://github.com/bikini/exploitarium/blob/main/run.sh): Automates QEMU launch with the correct CXL Type-3 configuration and validates successful exploitation.
- [`README.md`](https://github.com/bikini/exploitarium/blob/main/README.md): Documents the vulnerability analysis and exploit flow with specific line references to the QEMU source behavior.

## Building and Running the Exploit

To execute the proof-of-concept locally, build the guest stage and BIOS image, then launch QEMU with CXL Type-3 support enabled:

```bash

# Build the 32-bit stage and BIOS image

sh build.sh

# Launch QEMU with CXL Type-3 enabled (replace with your qemu binary)

sh run.sh /usr/bin/qemu-system-x86_64

# Verify successful exploitation

cat /tmp/qemu_cxl_escape_marker

```

The [`run.sh`](https://github.com/bikini/exploitarium/blob/main/run.sh) script handles the QEMU configuration and validates successful exploitation by checking for the marker file. Successful execution logs include entries showing the leaked handler address (`handler=0x…`), calculated QEMU base (`qemu_base=0x…`), and system function location (`system=0x…`), confirming each stage of the chain completed successfully.

## Summary

- The **GET_LOG handler** in QEMU's CXL Type-3 mailbox validates `offset + length` against buffer size but uses `offset` directly as an array index, enabling out-of-bounds reads of host memory.
- The **SET_FEATURE rank-sparing handler** performs unchecked writes to `rank_sparing_wr_attrs`, allowing arbitrary data injection into host memory relative to the `CXLType3Dev` object.
- The exploit chain implemented in `bikini/exploitarium` combines these primitives to forge QEMU memory-management structures and trigger arbitrary code execution through the MEDIA_OPERATIONS command handler.
- Any guest capable of issuing CXL mailbox commands can exploit this vulnerability, making it critical for environments with CXL Type-3 support enabled.

## Frequently Asked Questions

### What QEMU versions are affected by the CXL GET_LOG vulnerability?

The vulnerability affects QEMU implementations with CXL Type-3 mailbox support where the GET_LOG and SET_FEATURE handlers lack proper bounds validation. You should check your specific QEMU version against the latest security advisories, but the underlying issue stems from improper offset validation in the mailbox command processing code referenced in the `bikini/exploitarium` analysis at lines 141-156.

### Can this exploit work with a 16-bit guest or does it require a full operating system?

The exploit does not require a full operating system. According to the source analysis, **any guest capable of issuing CXL mailbox commands** can trigger the vulnerability, including a simple 16-bit bootloader. The provided PoC uses a minimal bootloader (`boot.asm`) that loads a 32-bit stage ([`stage2.c`](https://github.com/bikini/exploitarium/blob/main/stage2.c)), demonstrating that complex guest environments are unnecessary for successful exploitation.

### What specific host memory structures are leaked by the GET_LOG command?

The out-of-bounds GET_LOG read leaks QEMU text pointers (allowing calculation of the PIE base) and the heap address of the `CXLType3Dev` object. These pointers are located in memory adjacent to the `cel_log` buffer and are extracted by the guest in [`stage2.c`](https://github.com/bikini/exploitarium/blob/main/stage2.c) using carefully calculated offsets based on the buffer overflow position.

### How does the SET_FEATURE command achieve arbitrary code execution?

The SET_FEATURE rank-sparing handler writes guest-controlled data beyond the bounds of `rank_sparing_wr_attrs` without validation. By overwriting adjacent memory, an attacker can construct fake `MemoryRegion` and `MemoryRegionOps` structures. When the MEDIA_OPERATIONS command subsequently traverses these forged objects, it invokes a controlled function pointer, redirecting execution to attacker-specified code such as `system("/bin/sh")`.