]> git.ipfire.org Git - thirdparty/qemu.git/commitdiff
pcie_sriov: make pcie_sriov_pf_exit() safe on non-SR-IOV devices
authorStefan Hajnoczi <stefanha@redhat.com>
Wed, 24 Sep 2025 15:51:53 +0000 (11:51 -0400)
committerMichael Tokarev <mjt@tls.msk.ru>
Wed, 15 Oct 2025 20:27:03 +0000 (23:27 +0300)
Commit 3f9cfaa92c96 ("virtio-pci: Implement SR-IOV PF") added an
unconditional call from virtio_pci_exit() to pcie_sriov_pf_exit().

pcie_sriov_pf_exit() reads from the SR-IOV Capability in Configuration
Space:

  uint8_t *cfg = dev->config + dev->exp.sriov_cap;
  ...
  unparent_vfs(dev, pci_get_word(cfg + PCI_SRIOV_TOTAL_VF));
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This results in undefined behavior when dev->exp.sriov_cap is 0 because
this is not an SR-IOV device. For example, unparent_vfs() segfaults when
total_vfs happens to be non-zero.

Fix this by returning early from pcie_sriov_pf_exit() when
dev->exp.sriov_cap is 0 because this is not an SR-IOV device.

Cc: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
Cc: Michael S. Tsirkin <mst@redhat.com>
Reported-by: Qing Wang <qinwang@redhat.com>
Buglink: https://issues.redhat.com/browse/RHEL-116443
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
Fixes: cab1398a60eb ("pcie_sriov: Reuse SR-IOV VF device instances")
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20250924155153.579495-1-stefanha@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
(cherry picked from commit bab681f752048c3bc22d561b1d314c7ec16419c9)
(Mjt: backport to before v10.0.0-819-g19e55471d4e8
 "pcie_sriov: Allow user to create SR-IOV device")
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
hw/pci/pcie_sriov.c

index dd4fbaea4611a699e56281e93066a7a372c20405..6281bd61d9528e7f9bd4e9799c5a63b52d9a2321 100644 (file)
@@ -112,6 +112,9 @@ bool pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset,
 void pcie_sriov_pf_exit(PCIDevice *dev)
 {
     uint8_t *cfg = dev->config + dev->exp.sriov_cap;
+    if (dev->exp.sriov_cap == 0) {
+        return;
+    }
 
     unparent_vfs(dev, pci_get_word(cfg + PCI_SRIOV_TOTAL_VF));
 }