mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/
synced 2025-04-19 20:58:31 +09:00
PCI: Fix NULL dereference in SR-IOV VF creation error path
Clean up when virtfn setup fails to prevent NULL pointer dereference during device removal. The kernel oops below occurred due to incorrect error handling flow when pci_setup_device() fails. Add pci_iov_scan_device(), which handles virtfn allocation and setup and cleans up if pci_setup_device() fails, so pci_iov_add_virtfn() doesn't need to call pci_stop_and_remove_bus_device(). This prevents accessing partially initialized virtfn devices during removal. BUG: kernel NULL pointer dereference, address: 00000000000000d0 RIP: 0010:device_del+0x3d/0x3d0 Call Trace: pci_remove_bus_device+0x7c/0x100 pci_iov_add_virtfn+0xfa/0x200 sriov_enable+0x208/0x420 mlx5_core_sriov_configure+0x6a/0x160 [mlx5_core] sriov_numvfs_store+0xae/0x1a0 Link: https://lore.kernel.org/r/20250310084524.599225-1-shayd@nvidia.com Fixes: e3f30d563a38 ("PCI: Make pci_destroy_dev() concurrent safe") Signed-off-by: Shay Drory <shayd@nvidia.com> [bhelgaas: commit log, return ERR_PTR(-ENOMEM) directly] Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Cc: Keith Busch <kbusch@kernel.org>
This commit is contained in:
parent
cc7a371b0b
commit
04d50d953a
@ -285,23 +285,16 @@ const struct attribute_group sriov_vf_dev_attr_group = {
|
||||
.is_visible = sriov_vf_attrs_are_visible,
|
||||
};
|
||||
|
||||
int pci_iov_add_virtfn(struct pci_dev *dev, int id)
|
||||
static struct pci_dev *pci_iov_scan_device(struct pci_dev *dev, int id,
|
||||
struct pci_bus *bus)
|
||||
{
|
||||
int i;
|
||||
int rc = -ENOMEM;
|
||||
u64 size;
|
||||
struct pci_dev *virtfn;
|
||||
struct resource *res;
|
||||
struct pci_sriov *iov = dev->sriov;
|
||||
struct pci_bus *bus;
|
||||
|
||||
bus = virtfn_add_bus(dev->bus, pci_iov_virtfn_bus(dev, id));
|
||||
if (!bus)
|
||||
goto failed;
|
||||
struct pci_dev *virtfn;
|
||||
int rc;
|
||||
|
||||
virtfn = pci_alloc_dev(bus);
|
||||
if (!virtfn)
|
||||
goto failed0;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
virtfn->devfn = pci_iov_virtfn_devfn(dev, id);
|
||||
virtfn->vendor = dev->vendor;
|
||||
@ -314,8 +307,35 @@ int pci_iov_add_virtfn(struct pci_dev *dev, int id)
|
||||
pci_read_vf_config_common(virtfn);
|
||||
|
||||
rc = pci_setup_device(virtfn);
|
||||
if (rc)
|
||||
goto failed1;
|
||||
if (rc) {
|
||||
pci_dev_put(dev);
|
||||
pci_bus_put(virtfn->bus);
|
||||
kfree(virtfn);
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
return virtfn;
|
||||
}
|
||||
|
||||
int pci_iov_add_virtfn(struct pci_dev *dev, int id)
|
||||
{
|
||||
struct pci_bus *bus;
|
||||
struct pci_dev *virtfn;
|
||||
struct resource *res;
|
||||
int rc, i;
|
||||
u64 size;
|
||||
|
||||
bus = virtfn_add_bus(dev->bus, pci_iov_virtfn_bus(dev, id));
|
||||
if (!bus) {
|
||||
rc = -ENOMEM;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
virtfn = pci_iov_scan_device(dev, id, bus);
|
||||
if (IS_ERR(virtfn)) {
|
||||
rc = PTR_ERR(virtfn);
|
||||
goto failed0;
|
||||
}
|
||||
|
||||
virtfn->dev.parent = dev->dev.parent;
|
||||
virtfn->multifunction = 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user