Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CXLipse

CXLipse is a standalone reproduction package for a QEMU CXL Type-3 Set Feature out-of-bounds write that can be driven from a guest into host-side QEMU process memory corruption. In the verified local setup, the exploit replaces the QEMU process with /bin/sh and proves VM escape by comparing /bin/ls output from the escaped shell with /bin/ls output on the host.

The verified vulnerable QEMU target is commit de5d8bfd6105d3dd3ae668df9762df244a6d1506 (v11.0.0-1713-gde5d8bfd61 before local reproduction patches).

This repository is intended for authorized vulnerability reproduction, patch validation, and defensive research in a local lab.

What Is Included

  • poc/poc_cxl_vm_escape.c - guest-side PoC source.
  • poc/prepare_buildroot_rootfs.sh - builds the PoC and installs it into a Buildroot ext2 rootfs.
  • poc/run_qemu_cxl_buildroot.sh - launches the tested q35/KVM/CXL Type-3 target configuration.
  • poc/run_reproducer.sh - automates the guest run and verifies escape by exact host ls comparison.
  • tools/update_constants.py - rewrites exploit constants from a QEMU [CXL_DEBUG] layout line and execv@plt.
  • scripts/build_qemu_buildroot.sh - downloads and builds the pinned QEMU and Buildroot target used by the reproducer.
  • patches/qemu-cxl-layout-debug.patch - optional QEMU patch that prints the layout values needed by tools/update_constants.py.
  • docs/technical-report.md - root cause, impact, and reproduction details.
  • artifacts/minimal_poc_output.txt - sanitized output from a verified run.

Prerequisites

  • x86_64 Linux host with KVM available.
  • A vulnerable QEMU checkout and build. The verified local target was commit de5d8bfd6105d3dd3ae668df9762df244a6d1506.
  • Buildroot kernel and ext2 rootfs under the QEMU tree, or equivalent paths supplied through BZIMAGE and ROOTFS.
  • gcc, debugfs, expect, objdump, perl, and setarch.
  • Privileged guest access to the CXL PCI resource used by the PoC. The default is /sys/bus/pci/devices/0000:35:00.0/resource2.

Quick Start

cd /path/to/CXLipse
scripts/build_qemu_buildroot.sh
make reproduce

For a different QEMU checkout:

make prepare QEMU_SRC=/path/to/qemu
make reproduce QEMU_SRC=/path/to/qemu

The successful reproducer ends with:

VM_ESCAPE_CONFIRMED: escaped shell ls matched host ls

Exploit Workflow

Host lab
  |
  |  make prepare
  v
+-----------------------------+
| Buildroot ext2 rootfs       |
| /root/poc_cxl_vm_escape     |
| serial root shell enabled   |
+-------------+---------------+
              |
              |  make reproduce
              v
+-----------------------------+        MMIO mailbox writes
| QEMU q35/KVM guest          | -----------------------------+
| CXL Type-3 device exposed   |                              |
+-------------+---------------+                              |
              |                                              v
              | guest PoC opens resource2        +-----------------------------+
              | and sends CXL mailbox commands   | QEMU CXL Type-3 model      |
              |                                  | cmd_features_set_feature() |
              |                                  +-------------+---------------+
              |                                                |
              |  Set Feature #1: place fake dispatch objects   |
              |  Set Feature #2: corrupt dc.host_dc_as/regions |
              |                                                v
              |                                  +-----------------------------+
              |                                  | Out-of-bounds memcpy past   |
              |                                  | rank_sparing_wr_attrs       |
              |                                  +-------------+---------------+
              |                                                |
              |  Clear Poison triggers address_space_write()   |
              +------------------------------------------------+
                                                               |
                                                               v
                                                +-----------------------------+
                                                | attacker-shaped dispatch    |
                                                | calls execv("/bin/sh", ...) |
                                                +-------------+---------------+
                                                              |
                                                              v
                                                +-----------------------------+
                                                | escaped host shell          |
                                                | reproduce: compare host ls  |
                                                +-----------------------------+

Layout Constants

The host-code-execution proof intentionally uses concrete QEMU process addresses. If you rebuild QEMU or change the launch configuration, update the constants in poc/poc_cxl_vm_escape.c.

  1. Apply the debug patch to the QEMU tree:
cd /path/to/qemu
git apply /path/to/CXLipse/patches/qemu-cxl-layout-debug.patch
  1. Rebuild QEMU and boot once with poc/run_qemu_cxl_buildroot.sh. The QEMU stderr log should contain a line like:
[CXL_DEBUG] ct3d=0x... rank_sparing_wr_attrs=0x... host_dc_as=0x... regions[1]=0x...
  1. Update the PoC constants from that log:
cd /path/to/CXLipse
tools/update_constants.py artifacts/qemu_stderr.log \
  --source poc/poc_cxl_vm_escape.c \
  --qemu-bin /path/to/qemu/build/qemu-system-x86_64

The helper also computes execv@plt from the QEMU binary, assuming the default setarch -R PIE base 0x555555554000.

Building QEMU And Buildroot

The bootstrap script downloads and builds a local target under work/:

cd /path/to/CXLipse
scripts/build_qemu_buildroot.sh

By default it:

  • clones QEMU from https://gitlab.com/qemu-project/qemu.git;
  • checks out de5d8bfd6105d3dd3ae668df9762df244a6d1506;
  • applies patches/qemu-cxl-layout-debug.patch;
  • configures QEMU with --enable-asan --target-list=x86_64-softmmu;
  • downloads Buildroot 2024.02.3;
  • builds qemu_x86_64_defconfig with an ext2 rootfs and automatic serial root shell for reproducibility;
  • installs /root/poc_cxl_vm_escape into the rootfs.

Useful overrides:

WORKDIR=/tmp/cxlipse-build JOBS=16 scripts/build_qemu_buildroot.sh
scripts/build_qemu_buildroot.sh --skip-layout-patch
scripts/build_qemu_buildroot.sh --qemu-dir /path/to/qemu --skip-qemu

After the build, if the layout constants differ, run one reproducer attempt to capture artifacts/qemu_stderr.log, update constants with tools/update_constants.py, then rerun make prepare reproduce.

Reproducer Behavior

make prepare modifies the Buildroot rootfs used for testing:

  • installs /root/poc_cxl_vm_escape;
  • optionally enables an automatic serial root shell so the expect-based reproducer can run unattended.

This rootfs change is only test harness setup. It is not part of the QEMU CXL memory-corruption bug.

make reproduce starts QEMU, runs the guest PoC, drives the escaped host shell, and compares:

/bin/ls -1A --color=never

from the escaped shell against the same command run by the host-side reproducer. The VM escape is considered proven only if those outputs match exactly.

Root Cause Summary

cmd_features_set_feature() derives the copy size from the guest-controlled mailbox payload length:

bytes_to_copy = len_in - sizeof(CXLSetFeatureInHeader);

Some feature paths, such as patrol scrub and ECS, validate hdr->offset + bytes_to_copy against the destination structure size before copying. Several PPR and memory sparing paths do not. The rank sparing path is the one used by this PoC:

memcpy((uint8_t *)&ct3d->rank_sparing_wr_attrs + hdr->offset,
       mem_sparing_write_attrs, bytes_to_copy);

Both hdr->offset and bytes_to_copy are guest-controlled, so the guest can write beyond rank_sparing_wr_attrs into adjacent CXLType3Dev dynamic-capacity state. The PoC corrupts dc.host_dc_as and dc.regions[], then triggers address_space_write() through attacker-shaped QEMU memory dispatch structures.

Expected Fix Direction

Apply the same bounds-check pattern used by patrol scrub and ECS to every PPR and memory sparing Set Feature path before each memcpy(). Each check should use the exact destination field size.

About

A QEMU VM escape reproduction.

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages