* [PATCH] pcie_sriov: fix wrong write width and off-by-one in pf_reset
@ 2026-09-17 5:38 lirongqing
2026-09-17 17:17 ` Michael S. Tsirkin
0 siblings, 1 reply; 3+ messages in thread
From: lirongqing @ 2026-09-17 5:38 UTC (permalink / raw)
To: Michael S . Tsirkin, qemu-devel; +Cc: Li RongQing
From: Li RongQing <lirongqing@baidu.com>
pcie_sriov_pf_reset() restores the VF BAR type registers using
pci_set_quad() with a 4-byte stride. Since each VF BAR register is
4 bytes wide, the 8-byte write also covers the following BAR
register. Although subsequent iterations overwrite most of the
unintended writes, the access is incorrect and the final iteration
can write beyond the VF BAR registers.
SR-IOV defines six VF BAR registers and does not provide a VF ROM BAR.
However, several SR-IOV code paths use PCI_NUM_REGIONS, which includes
the ROM slot and therefore has a value of seven.
In particular, the final iteration in pcie_sriov_pf_reset() currently
writes a quadword at the offset of the seventh region. This starts at
the byte immediately following the six VF BAR registers and can
overwrite subsequent fields in the SR-IOV capability.
Use pci_set_long() to match the 4-byte VF BAR register width, and use
PCI_SRIOV_NUM_BARS when iterating over SR-IOV VF BARs. This also makes
the BAR count consistent with the assertion in
pcie_sriov_pf_init_vf_bar().
Fixes: 7c0fa8dff811b5 ("pcie: Add support for Single Root I/O Virtualization (SR/IOV)")
Fixes: c8bc4db403e176 ("pcie_sriov: Reset SR-IOV extended capability")
Signed-off-by: Li RongQing <lirongqing@baidu.com>
---
hw/pci/pcie_sriov.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/hw/pci/pcie_sriov.c b/hw/pci/pcie_sriov.c
index c41ac95..6122a26 100644
--- a/hw/pci/pcie_sriov.c
+++ b/hw/pci/pcie_sriov.c
@@ -229,7 +229,7 @@ void pcie_sriov_pf_init_vf_bar(PCIDevice *dev, int region_num,
assert(sriov_cap > 0);
assert(region_num >= 0);
- assert(region_num < PCI_NUM_REGIONS);
+ assert(region_num < PCI_SRIOV_NUM_BARS);
assert(region_num != PCI_ROM_SLOT);
wmask = ~(size - 1);
@@ -308,7 +308,7 @@ int16_t pcie_sriov_pf_init_from_user_created_vfs(PCIDevice *dev,
return -1;
}
- for (size_t j = 0; j < PCI_NUM_REGIONS; j++) {
+ for (size_t j = 0; j < PCI_SRIOV_NUM_BARS; j++) {
if (vfs[i]->io_regions[j].size != vfs[0]->io_regions[j].size ||
vfs[i]->io_regions[j].type != vfs[0]->io_regions[j].type) {
error_setg(errp, "inconsistent SR-IOV BARs");
@@ -344,7 +344,7 @@ int16_t pcie_sriov_pf_init_from_user_created_vfs(PCIDevice *dev,
dev->exp.sriov_pf.vf = vfs;
dev->exp.sriov_pf.vf_user_created = true;
- for (i = 0; i < PCI_NUM_REGIONS; i++) {
+ for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
PCIIORegion *region = &vfs[0]->io_regions[i];
if (region->size) {
@@ -463,8 +463,8 @@ void pcie_sriov_pf_reset(PCIDevice *dev)
*/
pci_set_word(dev->config + sriov_cap + PCI_SRIOV_SYS_PGSIZE, 0x1);
- for (uint16_t i = 0; i < PCI_NUM_REGIONS; i++) {
- pci_set_quad(dev->config + sriov_cap + PCI_SRIOV_BAR + i * 4,
+ for (uint16_t i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
+ pci_set_long(dev->config + sriov_cap + PCI_SRIOV_BAR + i * 4,
dev->exp.sriov_pf.vf_bar_type[i]);
}
}
--
2.9.4
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH] pcie_sriov: fix wrong write width and off-by-one in pf_reset
2026-09-17 5:38 [PATCH] pcie_sriov: fix wrong write width and off-by-one in pf_reset lirongqing
@ 2026-09-17 17:17 ` Michael S. Tsirkin
2026-09-18 1:33 ` 答复: [????] " Li,Rongqing
0 siblings, 1 reply; 3+ messages in thread
From: Michael S. Tsirkin @ 2026-09-17 17:17 UTC (permalink / raw)
To: lirongqing; +Cc: qemu-devel
On Thu, Sep 17, 2026 at 01:38:18PM +0800, lirongqing wrote:
> From: Li RongQing <lirongqing@baidu.com>
>
> pcie_sriov_pf_reset() restores the VF BAR type registers using
> pci_set_quad() with a 4-byte stride. Since each VF BAR register is
> 4 bytes wide, the 8-byte write also covers the following BAR
> register. Although subsequent iterations overwrite most of the
> unintended writes, the access is incorrect and the final iteration
> can write beyond the VF BAR registers.
>
> SR-IOV defines six VF BAR registers and does not provide a VF ROM BAR.
> However, several SR-IOV code paths use PCI_NUM_REGIONS, which includes
> the ROM slot and therefore has a value of seven.
>
> In particular, the final iteration in pcie_sriov_pf_reset() currently
> writes a quadword at the offset of the seventh region. This starts at
> the byte immediately following the six VF BAR registers and can
> overwrite subsequent fields in the SR-IOV capability.
>
> Use pci_set_long() to match the 4-byte VF BAR register width, and use
> PCI_SRIOV_NUM_BARS when iterating over SR-IOV VF BARs. This also makes
> the BAR count consistent with the assertion in
> pcie_sriov_pf_init_vf_bar().
>
> Fixes: 7c0fa8dff811b5 ("pcie: Add support for Single Root I/O Virtualization (SR/IOV)")
i do not see the bug in that version.
do u mean 19e55471d4e8 maybe?
> Fixes: c8bc4db403e176 ("pcie_sriov: Reset SR-IOV extended capability")
> Signed-off-by: Li RongQing <lirongqing@baidu.com>
> ---
> hw/pci/pcie_sriov.c | 10 +++++-----
> 1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/hw/pci/pcie_sriov.c b/hw/pci/pcie_sriov.c
> index c41ac95..6122a26 100644
> --- a/hw/pci/pcie_sriov.c
> +++ b/hw/pci/pcie_sriov.c
> @@ -229,7 +229,7 @@ void pcie_sriov_pf_init_vf_bar(PCIDevice *dev, int region_num,
>
> assert(sriov_cap > 0);
> assert(region_num >= 0);
> - assert(region_num < PCI_NUM_REGIONS);
> + assert(region_num < PCI_SRIOV_NUM_BARS);
> assert(region_num != PCI_ROM_SLOT);
>
> wmask = ~(size - 1);
> @@ -308,7 +308,7 @@ int16_t pcie_sriov_pf_init_from_user_created_vfs(PCIDevice *dev,
> return -1;
> }
>
> - for (size_t j = 0; j < PCI_NUM_REGIONS; j++) {
> + for (size_t j = 0; j < PCI_SRIOV_NUM_BARS; j++) {
> if (vfs[i]->io_regions[j].size != vfs[0]->io_regions[j].size ||
> vfs[i]->io_regions[j].type != vfs[0]->io_regions[j].type) {
> error_setg(errp, "inconsistent SR-IOV BARs");
> @@ -344,7 +344,7 @@ int16_t pcie_sriov_pf_init_from_user_created_vfs(PCIDevice *dev,
> dev->exp.sriov_pf.vf = vfs;
> dev->exp.sriov_pf.vf_user_created = true;
>
> - for (i = 0; i < PCI_NUM_REGIONS; i++) {
> + for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
> PCIIORegion *region = &vfs[0]->io_regions[i];
>
> if (region->size) {
> @@ -463,8 +463,8 @@ void pcie_sriov_pf_reset(PCIDevice *dev)
> */
> pci_set_word(dev->config + sriov_cap + PCI_SRIOV_SYS_PGSIZE, 0x1);
>
> - for (uint16_t i = 0; i < PCI_NUM_REGIONS; i++) {
> - pci_set_quad(dev->config + sriov_cap + PCI_SRIOV_BAR + i * 4,
> + for (uint16_t i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
> + pci_set_long(dev->config + sriov_cap + PCI_SRIOV_BAR + i * 4,
> dev->exp.sriov_pf.vf_bar_type[i]);
> }
> }
> --
> 2.9.4
^ permalink raw reply [flat|nested] 3+ messages in thread* 答复: [????] Re: [PATCH] pcie_sriov: fix wrong write width and off-by-one in pf_reset
2026-09-17 17:17 ` Michael S. Tsirkin
@ 2026-09-18 1:33 ` Li,Rongqing
0 siblings, 0 replies; 3+ messages in thread
From: Li,Rongqing @ 2026-09-18 1:33 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: qemu-devel@nongnu.org
> On Thu, Sep 17, 2026 at 01:38:18PM +0800, lirongqing wrote:
> > From: Li RongQing <lirongqing@baidu.com>
> >
> > pcie_sriov_pf_reset() restores the VF BAR type registers using
> > pci_set_quad() with a 4-byte stride. Since each VF BAR register is
> > 4 bytes wide, the 8-byte write also covers the following BAR register.
> > Although subsequent iterations overwrite most of the unintended
> > writes, the access is incorrect and the final iteration can write
> > beyond the VF BAR registers.
> >
> > SR-IOV defines six VF BAR registers and does not provide a VF ROM BAR.
> > However, several SR-IOV code paths use PCI_NUM_REGIONS, which includes
> > the ROM slot and therefore has a value of seven.
> >
> > In particular, the final iteration in pcie_sriov_pf_reset() currently
> > writes a quadword at the offset of the seventh region. This starts at
> > the byte immediately following the six VF BAR registers and can
> > overwrite subsequent fields in the SR-IOV capability.
> >
> > Use pci_set_long() to match the 4-byte VF BAR register width, and use
> > PCI_SRIOV_NUM_BARS when iterating over SR-IOV VF BARs. This also makes
> > the BAR count consistent with the assertion in
> > pcie_sriov_pf_init_vf_bar().
> >
> > Fixes: 7c0fa8dff811b5 ("pcie: Add support for Single Root I/O
> > Virtualization (SR/IOV)")
>
> i do not see the bug in that version.
> do u mean 19e55471d4e8 maybe?
>
You are right. Thanks for catching that! The issue was indeed introduced by commit 19e55471d4e8, not the initial SR/IOV support commit.
thanks
[Li,Rongqing]
> > Fixes: c8bc4db403e176 ("pcie_sriov: Reset SR-IOV extended capability")
> > Signed-off-by: Li RongQing <lirongqing@baidu.com>
> > ---
> > hw/pci/pcie_sriov.c | 10 +++++-----
> > 1 file changed, 5 insertions(+), 5 deletions(-)
> >
> > diff --git a/hw/pci/pcie_sriov.c b/hw/pci/pcie_sriov.c index
> > c41ac95..6122a26 100644
> > --- a/hw/pci/pcie_sriov.c
> > +++ b/hw/pci/pcie_sriov.c
> > @@ -229,7 +229,7 @@ void pcie_sriov_pf_init_vf_bar(PCIDevice *dev, int
> > region_num,
> >
> > assert(sriov_cap > 0);
> > assert(region_num >= 0);
> > - assert(region_num < PCI_NUM_REGIONS);
> > + assert(region_num < PCI_SRIOV_NUM_BARS);
> > assert(region_num != PCI_ROM_SLOT);
> >
> > wmask = ~(size - 1);
> > @@ -308,7 +308,7 @@ int16_t
> pcie_sriov_pf_init_from_user_created_vfs(PCIDevice *dev,
> > return -1;
> > }
> >
> > - for (size_t j = 0; j < PCI_NUM_REGIONS; j++) {
> > + for (size_t j = 0; j < PCI_SRIOV_NUM_BARS; j++) {
> > if (vfs[i]->io_regions[j].size != vfs[0]->io_regions[j].size ||
> > vfs[i]->io_regions[j].type != vfs[0]->io_regions[j].type) {
> > error_setg(errp, "inconsistent SR-IOV BARs"); @@
> > -344,7 +344,7 @@ int16_t
> pcie_sriov_pf_init_from_user_created_vfs(PCIDevice *dev,
> > dev->exp.sriov_pf.vf = vfs;
> > dev->exp.sriov_pf.vf_user_created = true;
> >
> > - for (i = 0; i < PCI_NUM_REGIONS; i++) {
> > + for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
> > PCIIORegion *region = &vfs[0]->io_regions[i];
> >
> > if (region->size) {
> > @@ -463,8 +463,8 @@ void pcie_sriov_pf_reset(PCIDevice *dev)
> > */
> > pci_set_word(dev->config + sriov_cap + PCI_SRIOV_SYS_PGSIZE,
> > 0x1);
> >
> > - for (uint16_t i = 0; i < PCI_NUM_REGIONS; i++) {
> > - pci_set_quad(dev->config + sriov_cap + PCI_SRIOV_BAR + i * 4,
> > + for (uint16_t i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
> > + pci_set_long(dev->config + sriov_cap + PCI_SRIOV_BAR + i * 4,
> > dev->exp.sriov_pf.vf_bar_type[i]);
> > }
> > }
> > --
> > 2.9.4
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-09-18 1:34 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-17 5:38 [PATCH] pcie_sriov: fix wrong write width and off-by-one in pf_reset lirongqing
2026-09-17 17:17 ` Michael S. Tsirkin
2026-09-18 1:33 ` 答复: [????] " Li,Rongqing
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.