hw/pci/pcie_sriov.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
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>
---
hw/pci/pcie_sriov.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/hw/pci/pcie_sriov.c b/hw/pci/pcie_sriov.c
index 8a4bf0d6f7..cf1b5b5c05 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));
}
}
--
2.51.0
On Wed, Sep 24, 2025 at 11:51:53AM -0400, Stefan Hajnoczi wrote: > 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> > --- > hw/pci/pcie_sriov.c | 6 +++++- > 1 file changed, 5 insertions(+), 1 deletion(-) CCing qemu-stable > > diff --git a/hw/pci/pcie_sriov.c b/hw/pci/pcie_sriov.c > index 8a4bf0d6f7..cf1b5b5c05 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)); > } > } > -- > 2.51.0 >
On 24.09.2025 20:51, Stefan Hajnoczi wrote: > On Wed, Sep 24, 2025 at 11:51:53AM -0400, Stefan Hajnoczi wrote: >> 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> >> --- >> hw/pci/pcie_sriov.c | 6 +++++- >> 1 file changed, 5 insertions(+), 1 deletion(-) > > CCing qemu-stable Ping? Can we apply this to the master branch, so I can pick it up for the stable series? Thanks, /mjt
© 2016 - 2025 Red Hat, Inc.