Hi
On Wed, Jul 15, 2026 at 11:28 AM <[email protected]> wrote:
>
> From: Marc-André Lureau <[email protected]>
>
> The qxl_phys2virt() call for guest_monitors_config only validates
> sizeof(QXLMonitorsConfig), which covers the fixed header (count and
> max_allowed) since commit 8efec0ef8bbc ("hw/display/qxl: Pass requested
> buffer size to qxl_phys2virt()"), but not the flexible array member
> heads[]. When count == 1, heads[0] is accessed without its memory being
> validated, allowing a guest to cause an out-of-bounds read.
>
> Include sizeof(QXLHead) in the size passed to qxl_phys2virt() so that
> the first head entry is validated within the guest memory slot, preventing
> guest-visible memory reading.
>
> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4027
> Reported-by: Tristan @TristanInSec
> Signed-off-by: Marc-Andre Lureau <[email protected]>
we are receiving multiple reports of this issue, can someone review?
(why the code only cares about count == 1 here? to limit the area to
render. in case of multi-monitor, it's the client job to handle the
monitor-config areas - tbh I suspect QEMU -display doesn't handle that
well, but I didn't check)
> ---
> hw/display/qxl.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/hw/display/qxl.c b/hw/display/qxl.c
> index 74258afa582..3df796175c2 100644
> --- a/hw/display/qxl.c
> +++ b/hw/display/qxl.c
> @@ -270,7 +270,7 @@ static void qxl_spice_monitors_config_async(PCIQXLDevice
> *qxl, int replay)
> }
>
> cfg = qxl_phys2virt(qxl, qxl->guest_monitors_config, MEMSLOT_GROUP_GUEST,
> - sizeof(QXLMonitorsConfig));
> + sizeof(QXLMonitorsConfig) + sizeof(QXLHead));
> if (cfg != NULL && cfg->count == 1) {
> qxl->guest_primary.resized = 1;
> qxl->guest_head0_width = cfg->heads[0].width;
> --
> 2.55.0
>
>