[PATCH] hw/display/qxl: validate monitors_config heads[] in phys2virt

marcandre.lureau@redhat.com posted 1 patch 1 week, 3 days ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20260715072722.1643289-1-marcandre.lureau@redhat.com
hw/display/qxl.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
[PATCH] hw/display/qxl: validate monitors_config heads[] in phys2virt
Posted by marcandre.lureau@redhat.com 1 week, 3 days ago
From: Marc-André Lureau <marcandre.lureau@redhat.com>

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 <marcandre.lureau@redhat.com>
---
 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


Re: [PATCH] hw/display/qxl: validate monitors_config heads[] in phys2virt
Posted by Michael Tokarev 3 days, 7 hours ago
On 7/15/26 10:27, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> 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 <marcandre.lureau@redhat.com>

I'm picking this one up for the stable qemu series.
Please let me know if I shouldn't.

It would be nice if changes which should be picked up,
had Cc: qemu-stable@ in the first place, to avoid this
extra round-trip.  I'm trying to keep it as simple as
possible, only asking to reply if I should not pick it
up, but it is more work for everyone still.

Thanks,

/mjt

>   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;


Re: [PATCH] hw/display/qxl: validate monitors_config heads[] in phys2virt
Posted by Philippe Mathieu-Daudé 3 days, 7 hours ago
On 22/7/26 11:38, Michael Tokarev wrote:
> On 7/15/26 10:27, marcandre.lureau@redhat.com wrote:
>> From: Marc-André Lureau <marcandre.lureau@redhat.com>
>>
>> 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 <marcandre.lureau@redhat.com>
> 
> I'm picking this one up for the stable qemu series.
> Please let me know if I shouldn't.
> 
> It would be nice if changes which should be picked up,
> had Cc: qemu-stable@ in the first place, to avoid this
> extra round-trip.  I'm trying to keep it as simple as
> possible, only asking to reply if I should not pick it
> up, but it is more work for everyone still.

Indeed this patch should had a 'Cc: qemu-stable@' tag.

Re: [PATCH] hw/display/qxl: validate monitors_config heads[] in phys2virt
Posted by Marc-André Lureau 3 days, 7 hours ago
Hi

On Wed, Jul 22, 2026 at 2:01 PM Philippe Mathieu-Daudé
<philmd@oss.qualcomm.com> wrote:
>
> On 22/7/26 11:38, Michael Tokarev wrote:
> > On 7/15/26 10:27, marcandre.lureau@redhat.com wrote:
> >> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> >>
> >> 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 <marcandre.lureau@redhat.com>
> >
> > I'm picking this one up for the stable qemu series.
> > Please let me know if I shouldn't.
> >
> > It would be nice if changes which should be picked up,
> > had Cc: qemu-stable@ in the first place, to avoid this
> > extra round-trip.  I'm trying to keep it as simple as
> > possible, only asking to reply if I should not pick it
> > up, but it is more work for everyone still.
>
> Indeed this patch should had a 'Cc: qemu-stable@' tag.

It could. That said, properly testing fixes on older releases takes
additional time and effort, and I prefer not to add Cc: qemu-stable@
unless I've verified the fix against those versions myself. I
appreciate you taking care of the stable evaluation, but I prefer to
keep my focus on master. Imho, we should not rush backports before
they have received a little bit more testing, it could introduce
regressions - the opposite of what I'd expect from -stable...
Re: [PATCH] hw/display/qxl: validate monitors_config heads[] in phys2virt
Posted by Michael Tokarev 2 days, 5 hours ago
On 7/22/26 13:09, Marc-André Lureau wrote:
> On Wed, Jul 22, 2026 at 2:01 PM Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> wrote:
>>
>> On 22/7/26 11:38, Michael Tokarev wrote:
...
>>> It would be nice if changes which should be picked up,
>>> had Cc: qemu-stable@ in the first place, to avoid this
>>> extra round-trip.  I'm trying to keep it as simple as
>>> possible, only asking to reply if I should not pick it
>>> up, but it is more work for everyone still.
>>
>> Indeed this patch should had a 'Cc: qemu-stable@' tag.
> 
> It could. That said, properly testing fixes on older releases takes
> additional time and effort, and I prefer not to add Cc: qemu-stable@
> unless I've verified the fix against those versions myself. I
> appreciate you taking care of the stable evaluation, but I prefer to
> keep my focus on master. Imho, we should not rush backports before
> they have received a little bit more testing, it could introduce
> regressions - the opposite of what I'd expect from -stable...

I understand your concerns well (hopefully anyway).  However, I don't
really expect you to test things on older branches or to change your
focus, - it's not about that at all.

It is about just *marking* things which you, as the author of changes,
*think* might be good to fix/have in stable branches, so it gets some
attention later.

We can arrange "delayed stable queue" of sorts, we can wait for the
changes to prove themselves in the master branch, we can even try
to test the suggested changes in the stable branches - sometimes I
can do that too.  But without having such attention in the first
place, none of this can happen, ever.

Right now I have to ask for every change which looks like a candidate,
whenever it is a candidate or not.  This makes more work for you too,
by reading my emails and by cursing me making so much noise :)

Besides, with stable releases being not every second day but with some
delay, most stuff in there do have some minimal testing in the master
branch first, at the very least.  It is just before the stable series
freeze things might look as rushing for stable.  Also, a few years of
the stable series done this way already, kind of proves we're doing a
good job here.  There was one regression in migration code which was
a tricky case by its own (it was broken either way), and one or two
more regressions fixed by a quick follow-up update, and that's all.
With so many changes in there, I think it's a rather good result.
Yes there's always risk to introduce a regression.  Not doing any
fixing, on the other hand, ensures we stay with our bugs forever -
that would be the most stable stability :)

So, to make it explicit: I'm not asking your for more work -
especially not the extra testing of the changes in stable branches.
I only want to reduce your own work by not requiring to read my
questions when I feel something is a good candidate.  Tagging the
change as "for-stable" does not mean it must be applied, it is
more about marking it as a to-do item, or some sort - for you
or for someone else.  Just not to lose it.

Thanks,

/mjt

Re: [PATCH] hw/display/qxl: validate monitors_config heads[] in phys2virt
Posted by Philippe Mathieu-Daudé 4 days, 7 hours ago
On 15/7/26 09:27, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> 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 <marcandre.lureau@redhat.com>
> ---
>   hw/display/qxl.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)

Patch queued, thanks.

Re: [PATCH] hw/display/qxl: validate monitors_config heads[] in phys2virt
Posted by Marc-André Lureau 5 days, 6 hours ago
Hi

On Wed, Jul 15, 2026 at 11:28 AM <marcandre.lureau@redhat.com> wrote:
>
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
>
> 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 <marcandre.lureau@redhat.com>

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
>
>
Re: [PATCH] hw/display/qxl: validate monitors_config heads[] in phys2virt
Posted by Philippe Mathieu-Daudé 5 days, 5 hours ago
On 20/7/26 13:06, Marc-André Lureau wrote:
> Hi
> 
> On Wed, Jul 15, 2026 at 11:28 AM <marcandre.lureau@redhat.com> wrote:
>>
>> From: Marc-André Lureau <marcandre.lureau@redhat.com>
>>
>> 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 <marcandre.lureau@redhat.com>
> 
> 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(-)

Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>