HMP expression evaluator signed integer overflow reaches xp physical-memory address
Host environment
- Operating system: Ubuntu 24.04.5 LTS (Noble Numbat)
- OS/kernel version:
Linux bea1e-HP-ZHAN66-14-G1a-AI 6.17.0-40-generic #40~24.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue Jun 23 16:48:12 UTC 2 x86_64 x86_64 x86_64 GNU/Linux - Architecture: x86_64
- QEMU flavor:
qemu-system-x86_64 - QEMU version:
QEMU emulator version 11.1.50 (v11.1.0-1360-g209b2afafa) - QEMU command line:
./build/qemu-system-x86_64 -M none -nographic -S -qmp unix:/tmp/qemu-poc-m02.sock,server=on,wait=off -no-shutdown
Emulated/Virtualized environment
- Operating system: N/A (
-M none; no guest was started) - OS/kernel version: N/A
- Architecture: N/A
Description of problem
AI-assisted static auditing was used to discover this issue. I manually
reviewed the reported code path, built the latest upstream qemu.git master
from source, and reproduced the behavior directly against that build. The
exact tested revision is 209b2afaface001c7d4d981e38f186afe7b24a50.
The HMP expression evaluator in monitor/hmp.c performs signed int64_t
arithmetic without detecting overflow. On the tested master revision,
multiplication in expr_prod() uses val *= val2 at monitor/hmp.c:574,
while addition and subtraction in expr_sum() use val += val2 and
val -= val2 at monitor/hmp.c:635-637.
The expression result is accepted for an HMP l argument and stored with
qdict_put_int() at monitor/hmp.c:1033. For the xp command,
hmp_physical_memory_dump() obtains that value as an hwaddr, and
memory_dump() passes it to address_space_read() at
monitor/hmp-cmds.c:645.
For example, the mathematical result of 2*4611686018427387904 is
9223372036854775808 (INT64_MAX + 1). On the tested build, HMP silently
produces 0x8000000000000000 and accepts the wrapped value as the address
supplied to xp:
p 2*4611686018427387904
0x8000000000000000
xp /1x 2*4611686018427387904
8000000000000000: Cannot access memoryExpected behavior is for the parser to reject an arithmetic expression whose
result is outside the int64_t range, rather than execute signed-overflow
undefined behavior and pass the resulting value to a command handler.
Security scope: reaching this code requires access to HMP, directly or through
QMP human-monitor-command. QEMU documents the monitor as a privileged control
interface, and an authorized monitor client can already request arbitrary
addresses with xp. The reproducer confirms the arithmetic bug and its
propagation into the physical-memory read path, but it does not establish an
additional authorization bypass, disclosure of mapped memory, host crash, or
guest-to-host escape. I am filing confidentially so maintainers can determine
whether this behavior has a meaningful misuse case within QEMU's security
boundary.
Steps to reproduce
-
Fetch and build upstream QEMU master. The exact tested commit was
209b2afaface001c7d4d981e38f186afe7b24a50:git clone https://gitlab.com/qemu-project/qemu.git cd qemu git checkout 209b2afaface001c7d4d981e38f186afe7b24a50 ./configure --target-list=x86_64-softmmu --disable-werror --enable-debug --disable-docs ninja -C build qemu-system-x86_64 -
Save the attached
poc.py, then run it against the resulting binary:python3 poc.py ./build/qemu-system-x86_64 -
Observe that
p 2*4611686018427387904returns0x8000000000000000, and thatxp /1x 2*4611686018427387904reports the same wrapped value as its physical address before returningCannot access memoryunder-M none.
Additional information
Exact upstream revision and commit date:
209b2afaface001c7d4d981e38f186afe7b24a50
2026-09-10T22:02:18-10:00
Merge tag 'pull-parallels-2026-09-11' of https://gitlab.com/dlunev/qemu into stagingRelevant current-master code path:
HMP command string
-> monitor_parse_arguments()
-> get_expr()
-> expr_prod() / expr_sum()
-> qdict_put_int(qdict, key, val)
-> hmp_physical_memory_dump()
-> memory_dump()
-> address_space_read()The minimal reproducer uses -M none, so no MemoryRegion is mapped at the
wrapped address and address_space_read() returns an error. No QEMU crash was
observed. The result should not be described as confirmed information
disclosure without a separate mapped-region reproducer showing an access that
the same monitor client could not request directly.
A robust fix should use checked arithmetic for multiplication, addition, and
subtraction and report an HMP expression error on overflow. The same audit
should cover unary negation of INT64_MIN, division/remainder of INT64_MIN
by -1, and M-suffix scaling, which are related signed-arithmetic edge cases
but are not all exercised by the attached reproducer.
Attached source-code test case: poc.py. It was created for this report and is
included as auditable Python source; it was not obtained from a third party.