hw/cxl/cxl-device-utils.c | 22 +++++++++++++++-------
From 66a0976944d7d415bc7ed125e7c55f52d686b52f Mon Sep 17 00:00:00 2001From: Haotian Jiang <sundayjiang@tencent.com>
Date: Thu, 9 Jul 2026 11:09:11 +0800
Subject: [PATCH] hw/cxl: reject mailbox commands with payload exceeding max
size
mailbox_reg_write() calls g_memdup2(pl, len_in) where len_in is
taken from the CXL_DEV_MAILBOX_CMD.LENGTH field, a 20-bit value
that can specify up to ~1 MB. The payload buffer pl points into
mbox_reg_state, which has only CXL_MAILBOX_MAX_PAYLOAD_SIZE (2048)
bytes of payload space. When len_in exceeds 2048, g_memdup2 reads
past the payload area into adjacent CXLDeviceState fields,
including host heap pointers in event_logs.
A guest can combine this with SET_LSA (variable-length, in=~0) to
write the over-read data into LSA backing memory, then read it back
with GET_LSA, leaking host heap addresses to the guest. This breaks
ASLR isolation between guest and host.
Reject commands with len_in > CXL_MAILBOX_MAX_PAYLOAD_SIZE by
returning CXL_MBOX_INVALID_PAYLOAD_LENGTH before calling g_memdup2.
Fixes: c9460561ed ("hw/cxl/mbox: Generalize the CCI command processing")
Reported-by: Haotian Jiang of Tencent Security (Yunding Lab) <sundayjiang@tencent.com>
Signed-off-by: Haotian Jiang <sundayjiang@tencent.com>
Cc: qemu-stable@nongnu.org
Link: https://gitlab.com/qemu-project/qemu/-/work_items/3967
---
hw/cxl/cxl-device-utils.c | 22 +++++++++++++++-------
1 file changed, 15 insertions(+), 7 deletions(-)
diff --git a/hw/cxl/cxl-device-utils.c b/hw/cxl/cxl-device-utils.c
index e150d74457..e4825f6ad6 100644
--- a/hw/cxl/cxl-device-utils.c
+++ b/hw/cxl/cxl-device-utils.c
@@ -202,14 +202,22 @@ static void mailbox_reg_write(void *opaque, hwaddr offset, uint64_t value,
bool bg_started = false;
int rc;
- pl_in_copy = g_memdup2(pl, len_in);
- if (len_in == 0 || pl_in_copy) {
- /* Avoid stale data - including from earlier cmds */
- memset(pl, 0, CXL_MAILBOX_MAX_PAYLOAD_SIZE);
- rc = cxl_process_cci_message(cci, cmd_set, cmd, len_in, pl_in_copy,
- &len_out, pl, &bg_started);
+ if (len_in > CXL_MAILBOX_MAX_PAYLOAD_SIZE) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "CXL mailbox: payload length %lu exceeds max %u\n",
+ (unsigned long)len_in, CXL_MAILBOX_MAX_PAYLOAD_SIZE);
+ rc = CXL_MBOX_INVALID_PAYLOAD_LENGTH;
} else {
- rc = CXL_MBOX_INTERNAL_ERROR;
+ pl_in_copy = g_memdup2(pl, len_in);
+ if (len_in == 0 || pl_in_copy) {
+ /* Avoid stale data - including from earlier cmds */
+ memset(pl, 0, CXL_MAILBOX_MAX_PAYLOAD_SIZE);
+ rc = cxl_process_cci_message(cci, cmd_set, cmd, len_in,
+ pl_in_copy, &len_out, pl,
+ &bg_started);
+ } else {
+ rc = CXL_MBOX_INTERNAL_ERROR;
+ }
}
/* Set bg and the return code */
--
2.34.1
© 2016 - 2026 Red Hat, Inc.