Commit dff528657f for qemu.org

commit dff528657fc114119ece1478ad845b0292a87683
Author: Denis V. Lunev <den@openvz.org>
Date:   Fri Jul 17 14:22:29 2026 +0200

    vfio/pci: don't narrow a failed config read to a plausible value

    vfio_pci_read_config() signals a failed host-side read by returning
    (uint32_t)-1, regardless of the requested length. vfio_intx_enable()
    and vfio_pci_pre_reset() both narrowed that return value straight
    into a uint8_t/uint16_t local before checking anything, which
    truncates -1 into 0xff or 0xffff - values a real 1- or 2-byte
    register read can legitimately produce. From that point on, a
    failed read and real all-ones content are indistinguishable.

    Keep the full uint32_t result and check it against (uint32_t)-1
    before narrowing. In vfio_pci_pre_reset(), skip the corresponding
    write-back on a failed read instead of writing back constructed
    garbage to the device.

    Resolves: Coverity CID 1663684
    Resolves: Coverity CID 1663688
    Signed-off-by: Denis V. Lunev <den@openvz.org>
    CC: Alex Williamson <alex@shazbot.org>
    CC: Cédric Le Goater <clg@redhat.com>
    Link: https://lore.kernel.org/qemu-devel/20260717122232.468955-2-den@openvz.org
    [ clg: Added Coverity IDs ]
    Reviewed-by: Cédric Le Goater <clg@redhat.com>
    Signed-off-by: Cédric Le Goater <clg@redhat.com>

diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index dcfc92aae1..b8c937d4be 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -323,10 +323,16 @@ static void vfio_irqchip_change(Notifier *notify, void *data)
 static bool vfio_intx_enable(VFIOPCIDevice *vdev, Error **errp)
 {
     PCIDevice *pdev = PCI_DEVICE(vdev);
-    uint8_t pin = vfio_pci_read_config(pdev, PCI_INTERRUPT_PIN, 1);
+    uint32_t val = vfio_pci_read_config(pdev, PCI_INTERRUPT_PIN, 1);
+    uint8_t pin;
     Error *err = NULL;
     int32_t fd;

+    if (val == (uint32_t)-1) {
+        error_setg(errp, "failed to read PCI_INTERRUPT_PIN");
+        return false;
+    }
+    pin = val;

     if (!pin) {
         return true;
@@ -2766,6 +2772,7 @@ bool vfio_pci_add_capabilities(VFIOPCIDevice *vdev, Error **errp)
 void vfio_pci_pre_reset(VFIOPCIDevice *vdev)
 {
     PCIDevice *pdev = PCI_DEVICE(vdev);
+    uint32_t val;
     uint16_t cmd;

     vfio_disable_interrupts(vdev);
@@ -2774,23 +2781,34 @@ void vfio_pci_pre_reset(VFIOPCIDevice *vdev)
      * Stop any ongoing DMA by disconnecting I/O, MMIO, and bus master.
      * Also put INTx Disable in known state.
      */
-    cmd = vfio_pci_read_config(pdev, PCI_COMMAND, 2);
-    cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
-             PCI_COMMAND_INTX_DISABLE);
-    vfio_pci_write_config(pdev, PCI_COMMAND, cmd, 2);
+    val = vfio_pci_read_config(pdev, PCI_COMMAND, 2);
+    if (val != (uint32_t)-1) {
+        cmd = val;
+        cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+                 PCI_COMMAND_INTX_DISABLE);
+        vfio_pci_write_config(pdev, PCI_COMMAND, cmd, 2);
+    }

     /* Make sure the device is in D0 */
     if (pdev->pm_cap) {
         uint16_t pmcsr;
         uint8_t state;

-        pmcsr = vfio_pci_read_config(pdev, pdev->pm_cap + PCI_PM_CTRL, 2);
+        val = vfio_pci_read_config(pdev, pdev->pm_cap + PCI_PM_CTRL, 2);
+        if (val == (uint32_t)-1) {
+            return;
+        }
+        pmcsr = val;
         state = pmcsr & PCI_PM_CTRL_STATE_MASK;
         if (state) {
             pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
             vfio_pci_write_config(pdev, pdev->pm_cap + PCI_PM_CTRL, pmcsr, 2);
             /* vfio handles the necessary delay here */
-            pmcsr = vfio_pci_read_config(pdev, pdev->pm_cap + PCI_PM_CTRL, 2);
+            val = vfio_pci_read_config(pdev, pdev->pm_cap + PCI_PM_CTRL, 2);
+            if (val == (uint32_t)-1) {
+                return;
+            }
+            pmcsr = val;
             state = pmcsr & PCI_PM_CTRL_STATE_MASK;
             if (state) {
                 error_report("vfio: Unable to power on device, stuck in D%d",