qemu-stable
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PULL 1/1] virtio-pci: fix use of a released vector


From: Peter Maydell
Subject: Re: [PULL 1/1] virtio-pci: fix use of a released vector
Date: Tue, 16 Apr 2024 11:01:36 +0100

On Mon, 15 Apr 2024 at 11:52, Michael S. Tsirkin <mst@redhat.com> wrote:
>
> From: Cindy Lu <lulu@redhat.com>
>
> During the booting process of the non-standard image, the behavior of the
> called function in qemu is as follows:
>
> 1. vhost_net_stop() was triggered by guest image. This will call the function
> virtio_pci_set_guest_notifiers() with assgin= false,
> virtio_pci_set_guest_notifiers() will release the irqfd for vector 0
>
> 2. virtio_reset() was triggered, this will set configure vector to 
> VIRTIO_NO_VECTOR
>
> 3.vhost_net_start() was called (at this time, the configure vector is
> still VIRTIO_NO_VECTOR) and then call virtio_pci_set_guest_notifiers() with
> assgin=true, so the irqfd for vector 0 is still not "init" during this process
>
> 4. The system continues to boot and sets the vector back to 0. After that
> msix_fire_vector_notifier() was triggered to unmask the vector 0 and  meet 
> the crash
>
> To fix the issue, we need to support changing the vector after 
> VIRTIO_CONFIG_S_DRIVER_OK is set.
>

Hi; Coverity points out what it thinks is a problem in this commit
(CID 1543938):

> diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
> index cb6940fc0e..cb159fd078 100644
> --- a/hw/virtio/virtio-pci.c
> +++ b/hw/virtio/virtio-pci.c
> @@ -1424,6 +1424,38 @@ static int virtio_pci_add_mem_cap(VirtIOPCIProxy 
> *proxy,
>      return offset;
>  }
>
> +static void virtio_pci_set_vector(VirtIODevice *vdev,
> +                                  VirtIOPCIProxy *proxy,
> +                                  int queue_no, uint16_t old_vector,
> +                                  uint16_t new_vector)
> +{
> +    bool kvm_irqfd = (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) &&
> +        msix_enabled(&proxy->pci_dev) && kvm_msi_via_irqfd_enabled();
> +
> +    if (new_vector == old_vector) {
> +        return;
> +    }
> +
> +    /*
> +     * If the device uses irqfd and the vector changes after DRIVER_OK is
> +     * set, we need to release the old vector and set up the new one.
> +     * Otherwise just need to set the new vector on the device.
> +     */
> +    if (kvm_irqfd && old_vector != VIRTIO_NO_VECTOR) {
> +        kvm_virtio_pci_vector_release_one(proxy, queue_no);
> +    }
> +    /* Set the new vector on the device. */
> +    if (queue_no == VIRTIO_CONFIG_IRQ_IDX) {
> +        vdev->config_vector = new_vector;
> +    } else {
> +        virtio_queue_set_vector(vdev, queue_no, new_vector);
> +    }

Here queue_no can be VIRTIO_CONFIG_IRQ_IDX, which is -1.

> +    /* If the new vector changed need to set it up. */
> +    if (kvm_irqfd && new_vector != VIRTIO_NO_VECTOR) {
> +        kvm_virtio_pci_vector_use_one(proxy, queue_no);

Here we pass that through to kvm_virtio_pci_vector_use_one().
In kvm_virtio_pci_vector_use_one()'s error-exit path ("undo")
it does
    vector = virtio_queue_vector(vdev, queue_no);
and in virtio_queue_vector() it does:

    return n < VIRTIO_QUEUE_MAX ? vdev->vq[n].vector :
        VIRTIO_NO_VECTOR;

where 'n' is an int, so if we can get here with queue_no being
VIRTIO_CONFIG_IRQ_IDX then we'll index off the front of the
vdev->vq[] array.

Maybe this is a "can't happen" case, but it does seem odd that
virtio_queue_vector() only bounds-checks the "too big" case
for its argument and not the "too small" case and/or it
doesn't have a special case for VIRTIO_CONFIG_IRQ_IDX.

> +    }
> +}
> +

thanks
-- PMM



reply via email to

[Prev in Thread] Current Thread [Next in Thread]