If a passthrough device's config space is unreadable at realize
time (wedged link, surprise removal, powered-off GPU, etc.), the
read of PCI_INTERRUPT_PIN comes back as 0xff. That value is
non-zero, so it passes the "!pin" early-return check, and
vfio_intx_enable() turns it into an out-of-range intx.pin (254).
That value survives into pci_irq_deassert() -> pci_set_irq() ->
pci_irq_handler(), which asserts 0 <= irq_num < PCI_NUM_PINS and
aborts, killing the whole qemu-kvm process with SIGABRT instead
of just failing the device.

Reject pin values outside the legal PCI_INTERRUPT_PIN range so
this now surfaces as an ordinary device realize failure.

Signed-off-by: Denis V. Lunev <[email protected]>
CC: Alex Williamson <[email protected]>
CC: "Cedric Le Goater" <[email protected]>
---
 hw/vfio/pci.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index c204706e63..612ee4a0db 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -812,6 +812,12 @@ static void vfio_msix_enable(VFIOPCIDevice *vdev)
     PCIDevice *pdev = PCI_DEVICE(vdev);
     int ret;
 
+    /* pin reads back as 0xff if the device is unresponsive */
+    if (pin > PCI_NUM_PINS) {
+        error_setg(errp, "Invalid PCI interrupt pin %d", pin);
+        return -EINVAL;
+    }
+
     vfio_disable_interrupts(vdev);
 
     vdev->msi_vectors = g_new0(VFIOMSIVector, vdev->msix->entries);
-- 
2.53.0


Reply via email to