From: Stefan Hajnoczi Date: Wed, 24 Sep 2025 15:51:53 +0000 (-0400) Subject: pcie_sriov: make pcie_sriov_pf_exit() safe on non-SR-IOV devices X-Git-Tag: v10.2.0-rc1~76^2~27 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=bab681f752048c3bc22d561b1d314c7ec16419c9;p=thirdparty%2Fqemu.git pcie_sriov: make pcie_sriov_pf_exit() safe on non-SR-IOV devices 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 Cc: Michael S. Tsirkin Reported-by: Qing Wang Buglink: https://issues.redhat.com/browse/RHEL-116443 Signed-off-by: Stefan Hajnoczi Reviewed-by: Akihiko Odaki Fixes: cab1398a60eb ("pcie_sriov: Reuse SR-IOV VF device instances") Reviewed-by: Michael S. Tsirkin Message-ID: <20250924155153.579495-1-stefanha@redhat.com> Signed-off-by: Michael S. Tsirkin --- diff --git a/hw/pci/pcie_sriov.c b/hw/pci/pcie_sriov.c index 29474d749a..c4f88f0975 100644 --- a/hw/pci/pcie_sriov.c +++ b/hw/pci/pcie_sriov.c @@ -195,7 +195,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; + } if (dev->exp.sriov_pf.vf_user_created) { uint16_t ven_id = pci_get_word(dev->config + PCI_VENDOR_ID); @@ -211,6 +213,8 @@ void pcie_sriov_pf_exit(PCIDevice *dev) pci_config_set_device_id(dev->exp.sriov_pf.vf[i]->config, vf_dev_id); } } else { + uint8_t *cfg = dev->config + dev->exp.sriov_cap; + unparent_vfs(dev, pci_get_word(cfg + PCI_SRIOV_TOTAL_VF)); } }