From: Kevin Wolf Date: Fri, 5 Dec 2025 14:57:18 +0000 (+0100) Subject: pcie_sriov: Fix PCI_SRIOV_* accesses in pcie_sriov_pf_exit() X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f73e5ed9bc4cfacf041323a6b40a85e6b6459b75;p=thirdparty%2Fqemu.git pcie_sriov: Fix PCI_SRIOV_* accesses in pcie_sriov_pf_exit() PCI_SRIOV_* are offsets into the SR-IOV capability, not into the PCI config space. pcie_sriov_pf_exit() erroneously takes them as the latter, which makes it read PCI_HEADER_TYPE and PCI_BIST when it tries to read PCI_SRIOV_TOTAL_VF. In many cases we're lucky enough that the PCI config space will be 0 there, so we just skip the whole for loop, but this isn't guaranteed. For example, setting the multifunction bit on the PF and then doing a 'device_del' on it will get a larger number and cause a segfault. Fix this and access the real PCI_SRIOV_* fields in the capability. Cc: qemu-stable@nongnu.org Fixes: 19e55471d4e8 ('pcie_sriov: Allow user to create SR-IOV device') Signed-off-by: Kevin Wolf Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Message-Id: <20251205145718.55136-1-kwolf@redhat.com> --- diff --git a/hw/pci/pcie_sriov.c b/hw/pci/pcie_sriov.c index 34e0875d21..c41ac95bee 100644 --- a/hw/pci/pcie_sriov.c +++ b/hw/pci/pcie_sriov.c @@ -195,14 +195,17 @@ bool pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset, void pcie_sriov_pf_exit(PCIDevice *dev) { + uint8_t *cfg; + if (dev->exp.sriov_cap == 0) { return; } + cfg = dev->config + dev->exp.sriov_cap; if (dev->exp.sriov_pf.vf_user_created) { uint16_t ven_id = pci_get_word(dev->config + PCI_VENDOR_ID); - uint16_t total_vfs = pci_get_word(dev->config + PCI_SRIOV_TOTAL_VF); - uint16_t vf_dev_id = pci_get_word(dev->config + PCI_SRIOV_VF_DID); + uint16_t total_vfs = pci_get_word(cfg + PCI_SRIOV_TOTAL_VF); + uint16_t vf_dev_id = pci_get_word(cfg + PCI_SRIOV_VF_DID); unregister_vfs(dev); @@ -213,8 +216,6 @@ 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)); } }