I also faced such issue

Acked-by: Yonggang Luo <[email protected]>

I Can this be in qemu 11.1?

On Sat, Jul 25, 2026 at 6:14 AM Michael S. Tsirkin <[email protected]> wrote:
>
> virtio-mmio reports VIRTQUEUE_MAX_SIZE (1024) as QUEUE_NUM_MAX for every
> queue, regardless of the size the device passes to virtio_add_queue().
>
> This works by accident because QEMU mostly does not care about the ring
> size - the guest is the one allocating memory here.  But this changes
> with in-order vqs where qemu is the one allocating resources.
> Now, specifying a larger vq than allocated causes an OOB memory access.
>
> To fix:
> - for new machine types, report the actual max queue size to guest
> - for old machine types, use a compat property to allocate 1k sized
>   queues
>
> Fixes: 525d82e323 ("virtio: fix queue size validation against allocated
maximum")
> Fixes: CVE-2026-50626
> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3882
> Cc: Peter Maydell <[email protected]>
> Signed-off-by: Michael S. Tsirkin <[email protected]>
> ---
>  include/hw/virtio/virtio-bus.h  |  1 +
>  include/hw/virtio/virtio-mmio.h |  1 +
>  hw/core/machine.c               |  1 +
>  hw/virtio/virtio-mmio.c         |  7 +++----
>  hw/virtio/virtio.c              | 11 +++++++++++
>  5 files changed, 17 insertions(+), 4 deletions(-)
>
> diff --git a/include/hw/virtio/virtio-bus.h
b/include/hw/virtio/virtio-bus.h
> index 1a2d396156..f80fd71424 100644
> --- a/include/hw/virtio/virtio-bus.h
> +++ b/include/hw/virtio/virtio-bus.h
> @@ -30,6 +30,7 @@
>  #include "qom/object.h"
>
>  #define TYPE_VIRTIO_BUS "virtio-bus"
> +#define VIRTIO_QUEUE_SIZE_OVERRIDE "x-override-queue-size"
>  typedef struct VirtioBusClass VirtioBusClass;
>  typedef struct VirtioBusState VirtioBusState;
>  DECLARE_OBJ_CHECKERS(VirtioBusState, VirtioBusClass,
> diff --git a/include/hw/virtio/virtio-mmio.h
b/include/hw/virtio/virtio-mmio.h
> index 1644d09810..0a9069868c 100644
> --- a/include/hw/virtio/virtio-mmio.h
> +++ b/include/hw/virtio/virtio-mmio.h
> @@ -69,6 +69,7 @@ struct VirtIOMMIOProxy {
>      /* Fields only used for non-legacy (v2) devices */
>      uint32_t guest_features[2];
>      VirtIOMMIOQueue vqs[VIRTIO_QUEUE_MAX];
> +    uint16_t override_queue_size;
>  };
>
>  #endif
> diff --git a/hw/core/machine.c b/hw/core/machine.c
> index 805148678d..73b4d82b4a 100644
> --- a/hw/core/machine.c
> +++ b/hw/core/machine.c
> @@ -41,6 +41,7 @@
>  #include "hw/arm/smmuv3.h"
>
>  GlobalProperty hw_compat_11_0[] = {
> +    { "virtio-mmio", VIRTIO_QUEUE_SIZE_OVERRIDE, "1024" },
>      { "chardev-vc", "encoding", "cp437" },
>      { "tpm-crb", "cap-chunk", "off" },
>      { "tpm-crb", "x-allow-chunk-migration", "off" },
> diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c
> index 58c6d46aab..55ceaeef5f 100644
> --- a/hw/virtio/virtio-mmio.c
> +++ b/hw/virtio/virtio-mmio.c
> @@ -172,10 +172,7 @@ static uint64_t virtio_mmio_read(void *opaque,
hwaddr offset, unsigned size)
>                  >> (32 * proxy->host_features_sel);
>          }
>      case VIRTIO_MMIO_QUEUE_NUM_MAX:
> -        if (!virtio_queue_get_num(vdev, vdev->queue_sel)) {
> -            return 0;
> -        }
> -        return VIRTQUEUE_MAX_SIZE;
> +        return virtio_queue_get_max_num(vdev, vdev->queue_sel);
>      case VIRTIO_MMIO_QUEUE_PFN:
>          if (!proxy->legacy) {
>              qemu_log_mask(LOG_GUEST_ERROR,
> @@ -738,6 +735,8 @@ static const Property virtio_mmio_properties[] = {
>      DEFINE_PROP_BOOL("force-legacy", VirtIOMMIOProxy, legacy, true),
>      DEFINE_PROP_BIT("ioeventfd", VirtIOMMIOProxy, flags,
>                      VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD_BIT, true),
> +    DEFINE_PROP_UINT16(VIRTIO_QUEUE_SIZE_OVERRIDE, VirtIOMMIOProxy,
> +                       override_queue_size, 0),
>  };
>
>  static void virtio_mmio_realizefn(DeviceState *d, Error **errp)
> diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
> index 340bac2607..35f2a50ddb 100644
> --- a/hw/virtio/virtio.c
> +++ b/hw/virtio/virtio.c
> @@ -2590,6 +2590,17 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev,
int queue_size,
>      if (i == VIRTIO_QUEUE_MAX || queue_size > VIRTQUEUE_MAX_SIZE)
>          abort();
>
> +    BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
> +    if (qbus && qbus->parent &&
> +        object_property_find(OBJECT(qbus->parent),
VIRTIO_QUEUE_SIZE_OVERRIDE)) {
> +        int override = object_property_get_int(OBJECT(qbus->parent),
> +
VIRTIO_QUEUE_SIZE_OVERRIDE,
> +                                               &error_abort);
> +        if (override) {
> +            queue_size = override;
> +        }
> +    }
> +
>      vdev->vq[i].vring.num = queue_size;
>      vdev->vq[i].vring.num_default = queue_size;
>      vdev->vq[i].vring.align = VIRTIO_PCI_VRING_ALIGN;
> --
> MST
>
>


-- 
         此致
礼
罗勇刚
Yours
    sincerely,
Yonggang Luo

Reply via email to