[PATCH v2 2/2] PCI/IOV: Skip VF Resizable BAR restore on read error

From: Marco Nenciarini

Date: Fri Apr 17 2026 - 09:25:55 EST


sriov_restore_vf_rebar_state() uses the VF Resizable BAR Control
register to decide how many VF BARs to restore (nbars) and which
VF BAR each iteration addresses (bar_idx). bar_idx indexes into
dev->sriov->barsz[], which has only PCI_SRIOV_NUM_BARS (6) entries.

When the device does not respond, config reads return the all-ones
pattern. Both fields are 3 bits wide, so nbars and bar_idx both
evaluate to 7. The barsz[] access then goes out of bounds. UBSAN
reports this as:

UBSAN: array-index-out-of-bounds in drivers/pci/iov.c:948:51
index 7 is out of range for type 'resource_size_t [6]'

Observed on an NVIDIA RTX PRO 1000 GPU (GB207GLM) that fell off the
PCIe bus during a failed GC6 power state exit. The subsequent
pci_restore_state() invoked sriov_restore_vf_rebar_state() while
config reads returned 0xffffffff, triggering the splat.

Bail out if any VF Resizable BAR Control read returns the error
pattern. No further VF BARs are touched, which is safe because a
config read that returns the error pattern indicates the device is
unreachable and restoration is pointless. This mirrors the guard
in pci_restore_rebar_state().

Fixes: 5a8f77e24a30 ("PCI/IOV: Restore VF resizable BAR state after reset")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Marco Nenciarini <mnencia@xxxxxxxx>
---
Cc: Michał Winiarski <michal.winiarski@xxxxxxxxx>
Cc: Ilpo Järvinen <ilpo.jarvinen@xxxxxxxxxxxxxxx>
Cc: Rafael J. Wysocki <rafael@xxxxxxxxxx>
Cc: Eric Chanudet <echanude@xxxxxxxxxx>
Cc: Alex Williamson <alex@xxxxxxxxxxx>
Cc: Lukas Wunner <lukas@xxxxxxxxx>

drivers/pci/iov.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index 91ac4e37ecb9c..08df9bace13d1 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -938,12 +938,18 @@ static void sriov_restore_vf_rebar_state(struct pci_dev *dev)
return;

pci_read_config_dword(dev, pos + PCI_VF_REBAR_CTRL, &ctrl);
+ if (PCI_POSSIBLE_ERROR(ctrl))
+ return;
+
nbars = FIELD_GET(PCI_VF_REBAR_CTRL_NBAR_MASK, ctrl);

for (i = 0; i < nbars; i++, pos += 8) {
int bar_idx, size;

pci_read_config_dword(dev, pos + PCI_VF_REBAR_CTRL, &ctrl);
+ if (PCI_POSSIBLE_ERROR(ctrl))
+ return;
+
bar_idx = FIELD_GET(PCI_VF_REBAR_CTRL_BAR_IDX, ctrl);
size = pci_rebar_bytes_to_size(dev->sriov->barsz[bar_idx]);
ctrl &= ~PCI_VF_REBAR_CTRL_BAR_SIZE;
--
2.47.3