@samitouri / QOSamiQemu / commits / dff528657f

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>

Denis V. Lunev committed Jul 17, 2026 at 14:22 UTC dff528657fc114119ece1478ad845b0292a87683
1 file changed +25 -7
hw/vfio/pci.c
+25 -7
@@ -323,10 +323,16 @@ static void vfio_irqchip_change(Notifier *notify, void *data)
323 static bool vfio_intx_enable(VFIOPCIDevice *vdev, Error **errp)
324 {
325 PCIDevice *pdev = PCI_DEVICE(vdev);
326 - uint8_t pin = vfio_pci_read_config(pdev, PCI_INTERRUPT_PIN, 1);
326 + uint32_t val = vfio_pci_read_config(pdev, PCI_INTERRUPT_PIN, 1);
327 + uint8_t pin;
328 Error *err = NULL;
329 int32_t fd;
330
331 + if (val == (uint32_t)-1) {
332 + error_setg(errp, "failed to read PCI_INTERRUPT_PIN");
333 + return false;
334 + }
335 + pin = val;
336
337 if (!pin) {
338 return true;
@@ -2766,6 +2772,7 @@ bool vfio_pci_add_capabilities(VFIOPCIDevice *vdev, Error **errp)
2772 void vfio_pci_pre_reset(VFIOPCIDevice *vdev)
2773 {
2774 PCIDevice *pdev = PCI_DEVICE(vdev);
2775 + uint32_t val;
2776 uint16_t cmd;
2777
2778 vfio_disable_interrupts(vdev);
@@ -2774,23 +2781,34 @@ void vfio_pci_pre_reset(VFIOPCIDevice *vdev)
2781 * Stop any ongoing DMA by disconnecting I/O, MMIO, and bus master.
2782 * Also put INTx Disable in known state.
2783 */
2777 - cmd = vfio_pci_read_config(pdev, PCI_COMMAND, 2);
2778 - cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
2779 - PCI_COMMAND_INTX_DISABLE);
2780 - vfio_pci_write_config(pdev, PCI_COMMAND, cmd, 2);
2784 + val = vfio_pci_read_config(pdev, PCI_COMMAND, 2);
2785 + if (val != (uint32_t)-1) {
2786 + cmd = val;
2787 + cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
2788 + PCI_COMMAND_INTX_DISABLE);
2789 + vfio_pci_write_config(pdev, PCI_COMMAND, cmd, 2);
2790 + }
2791
2792 /* Make sure the device is in D0 */
2793 if (pdev->pm_cap) {
2794 uint16_t pmcsr;
2795 uint8_t state;
2796
2787 - pmcsr = vfio_pci_read_config(pdev, pdev->pm_cap + PCI_PM_CTRL, 2);
2797 + val = vfio_pci_read_config(pdev, pdev->pm_cap + PCI_PM_CTRL, 2);
2798 + if (val == (uint32_t)-1) {
2799 + return;
2800 + }
2801 + pmcsr = val;
2802 state = pmcsr & PCI_PM_CTRL_STATE_MASK;
2803 if (state) {
2804 pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
2805 vfio_pci_write_config(pdev, pdev->pm_cap + PCI_PM_CTRL, pmcsr, 2);
2806 /* vfio handles the necessary delay here */
2793 - pmcsr = vfio_pci_read_config(pdev, pdev->pm_cap + PCI_PM_CTRL, 2);
2807 + val = vfio_pci_read_config(pdev, pdev->pm_cap + PCI_PM_CTRL, 2);
2808 + if (val == (uint32_t)-1) {
2809 + return;
2810 + }
2811 + pmcsr = val;
2812 state = pmcsr & PCI_PM_CTRL_STATE_MASK;
2813 if (state) {
2814 error_report("vfio: Unable to power on device, stuck in D%d",