On Tue, Apr 16, 2024 at 6:01 PM Peter Maydell <peter.mayd...@linaro.org> wrote:
>
> On Mon, 15 Apr 2024 at 11:52, Michael S. Tsirkin <m...@redhat.com> wrote:
> >
> > From: Cindy Lu <l...@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.
>
> > +    }
> > +}
> > +
>
hi peter
I think we can simply remove the part
    vector = virtio_queue_vector(vdev, queue_no);
the vector is get from virtio_pci_get_notifier() and don't need to get it again
I will send the fix soon
thanks
cindy
> thanks
> -- PMM
>


Reply via email to