VAPIC writable ROM alias can escape the option-ROM window and expose locked SMRAM
Automated-tool disclosure: AI-assisted source analysis helped identify this issue. I manually reviewed the affected source, validated the trigger and resulting mapping, and practically demonstrated that it can supply a capability in a guest-to-host escape chain. The attached reproducer is human-reviewed source code and does not exercise the full escape chain.
Classification note: I am not sure whether this standalone issue qualifies as a security issue under QEMU's published guidelines. It crosses the guest-kernel-to-SMM isolation boundary, and Q35 with a virtualization accelerator is a supported configuration, but the guidelines also treat some virtual-device misbehavior requiring guest kernel or root privileges as a hardening bug. I have therefore prepared this as a confidential report so the QEMU security team can make that determination. The confidential marking is not intended to assert that the standalone bug qualifies for security handling.
Host environment
- Operating system: Debian GNU/Linux 12 (bookworm)
- OS/kernel version: Linux 6.1.0-51-amd64, Debian 6.1.177-1 (2026-07-16)
- Architecture: x86_64
- QEMU flavor: qemu-system-x86_64
- QEMU version: 11.0.92 (v11.1.0-rc2-9-gb428fe0362), commit b428fe03
- QEMU command line:
/home/artem/qemuctf/patched-stack/qemu/bin/qemu-system-x86_64 \ -name debian-12-qemu \ -machine q35,accel=kvm:tcg \ -cpu max \ -smp 4 \ -m 8G \ -drive file=/home/artem/vm/debian-12-qemu/disk.qcow2,if=virtio,format=qcow2 \ -drive file=/home/artem/vm/debian-12-qemu/seed.iso,if=virtio,format=raw,readonly=on \ -nic user,model=virtio-net-pci,mac=52:54:00:12:34:56,hostfwd=tcp:127.0.0.1:2222-:22 \ -object rng-random,filename=/dev/urandom,id=rng0 \ -device virtio-rng-pci,rng=rng0 \ -display none \ -serial file:/home/artem/vm/debian-12-qemu/console.log \ -monitor unix:/home/artem/vm/debian-12-qemu/monitor.sock,server=on,wait=off
Emulated/Virtualized environment
- Operating system: Debian GNU/Linux 12 (bookworm)
- OS/kernel version: Linux 6.1.0-51-cloud-amd64, Debian 6.1.177-1 (2026-07-16)
- Architecture: x86_64
Description of problem
The 16-bit VAPIC setup hypercall lets a privileged guest choose both the base and size of a
priority-1000 writable RAM alias. QEMU does not verify that the resulting interval belongs to the
VAPIC option ROM. On Q35, a guest can therefore place the alias over 0xa0000..0xbffff, bypassing
the chipset's locked-SMRAM view and modifying memory that will execute in System Management Mode.
Current qemu.git master, commit fa19879df1658f96ac07365fca8835b7decd6995, remains affected by
source inspection and runtime validation. The relevant code is:
For a 16-bit write to I/O port 0x7e, vapic_write() derives rom_paddr from guest-controlled
CS:EIP and adds the guest-supplied port value. vapic_map_rom_writable() then:
- aligns this guest-selected value to a 512-byte ROM block;
- calls
memory_region_find(mr, 0, 1), selecting the full guest-RAM backing rather than validating the region at the requested address; - reads the alias length from the guest-controlled byte
ram[rom_paddr + 2]; and - creates a
kvmvapic-romalias at overlap priority 1000 without checking that its rounded base and end remain inside the option-ROM window.
In the attached reproducer, the setup write executes at GPA 0x9fe10, selecting block 0x9fe00,
and guest RAM byte 0x9fe02 is 0xff. The raw length is therefore 0xff * 512 = 0x1fe00 bytes.
QEMU's page rounding changes this into [0x9f000, 0xc0000). The priority-1000 alias overrides the
normal Q35 mappings for locked SMRAM at [0xa0000, 0xc0000).
The resume condition is practical and does not inherently require the attacker to control QEMU's
management interface. Privileged guest code can install the suspend hook in advance. When the
guest next enters S3, the hook arms the malicious firmware waking vector, which remains in place
while the VM is suspended. The attacker can then wait for an ordinary resume initiated by a user,
operator, or configured virtual wake source; the wake stub executes before the guest OS completes
its normal resume. The system_wakeup HMP command in the reproducer is only a deterministic way to
produce that ordinary wake event.
Security relevance and scope uncertainty
I am not asserting that this bug independently crosses a security boundary that QEMU promises to protect. I have prepared it for confidential triage because I am unsure whether it qualifies as a security issue under QEMU's guidelines. The QEMU security process says that not every part of QEMU provides a security boundary and invites reports when the reporter thinks there may be a vulnerability or is unsure how a vulnerability affects QEMU. In particular, I do not know whether guest-kernel-to-SMM isolation on an accelerated Q35 machine is within the supported security boundary.
Regardless of that security classification, this is incorrect device behavior: a hypercall whose documented purpose is to make the VAPIC option ROM writable can instead replace unrelated Q35 memory mappings. QEMU neither rejects the malformed setup nor constrains its resulting range to the option-ROM window.
The immediate primitive crosses the guest kernel/SMM isolation boundary: a guest administrator
can inject arbitrary code into locked SMRAM and have it execute in SMM. The Q35 D_LCK protection
no longer prevents non-SMM guest software from modifying the SMM backing memory.
The project's published security model explicitly treats the guest as untrusted and lists Q35 with a virtualization accelerator as a supported guest-isolation configuration. On the other hand, its "degraded guest behaviour" guidance says that virtual-device misbehavior requiring guest kernel or root privileges will generally be treated as a hardening bug, and it does not explicitly identify guest-kernel-to-SMM isolation as a supported security boundary. I therefore defer classification to the QEMU security team.
I nevertheless used this primitive with other, separately reported vulnerabilities to obtain a complete guest-to-host escape and practically demonstrated that chain from a Debian 12 guest. Those other issues are independent and intentionally omitted here. I defer the standalone severity and CVE decision to the QEMU security team.
Suggested fix
QEMU should bind the writable alias to the VAPIC option ROM that QEMU actually loaded, rather than
trusting an address and length reconstructed from guest state. At minimum, before creating the
alias, it should reject any raw or page-rounded interval whose base or end lies outside the PC
option-ROM window (0xc0000..0xdffff), perform overflow-safe end checks, and verify the expected
VAPIC ROM identity. The strongest fix would retain the exact address and size assigned when
kvmvapic.bin is loaded and require the setup hypercall to match that range.
The validation must occur before deleting an existing alias or calling
memory_region_init_alias(). A regression test should attempt setup writes from below 0xc0000
and with a size byte that would cross 0xe0000, then confirm that no alias is created.
Steps to reproduce
- Start an x86 Q35/KVM guest with ACPI S3 and an HMP monitor. The complete command line used for practical validation is included above.
- Copy the attached
qemu-vapic-smram-reproducer.tar.gzinto the guest, extract it, and install the build prerequisites. On Debian:tar -xzf qemu-vapic-smram-reproducer.tar.gz cd qemu-vapic-smram-reproducer sudo apt-get install build-essential linux-headers-$(uname -r) make sudo insmod vapic_s3_repro.ko - In the guest, run
sudo systemctl suspend. In the HMP monitor, runsystem_wakeupto resume it. - In HMP, run
info mtreeand inspect the system-memory region tree. A vulnerable build shows priority-1000kvmvapic-romcovering0x000000000009f000..0x00000000000bffff, overlappingsmram-regionat0x00000000000a0000..0x00000000000bffff. - In the guest, confirm the messages with
sudo dmesg | tail -n 20, then unload the module withsudo rmmod vapic_s3_repro. Reset or stop the test VM to remove the QEMU-side alias.
The observable mapping is sufficient to demonstrate the bug. The reproducer deliberately does not write an SMM payload or invoke any other vulnerability.
Additional information
- Runtime validation was performed on upstream-derived commit
b428fe036233cbd15d37e3c027ab6ca4d3661a80and repeated on current masterfa19879df1658f96ac07365fca8835b7decd6995(QEMU 11.1.50). - The exact attached archive builds against the listed Debian kernel's installed headers without compiler warnings. The resulting module loaded under that matching kernel for runtime testing.
- The attached archive contains only the kernel-module C source, a Makefile, and detailed run instructions.
- I found no public QEMU issue or CVE matching this VAPIC alias-range flaw. A confidential report may of course already exist.
- Reporter: "Artem Dinaburg" artem@trailofbits.com