[PATCH] hw/pci-host/pnv_phb4: fix guest-triggerable abort on 8-byte config access
Nikhil Kumar Singh <[email protected]> Wed, 5 Aug 2026 14:35:30 +0530
| Newsgroups | gmane.comp.emulators.qemu,gmane.comp.emulators.qemu.stable |
|---|---|
| Message-ID | <[email protected]> |
A guest-triggerable assertion crash (DoS) exists in pnv_phb4_config_write()
and pnv_phb4_config_read(). When a guest performs an 8-byte access to
PHB_CONFIG_DATA (offset 0x130), QEMU aborts because the switch(size)
statement in the config accessors only handles 1, 2, and 4-byte accesses,
hitting g_assert_not_reached() in the default case.
Since guest input is untrusted, an invalid access size should not crash
the host. Fix this by adding a size > 4 guard in pnv_phb4_reg_write() and
pnv_phb4_reg_read() before the config accessor calls, and by replacing
the g_assert_not_reached() in pnv_phb4_config_write() and
pnv_phb4_config_read() with phb_error() to cover any other callers.
Invalid reads now return ~0ull, maintaining PCI conventions.
Fixes: 4f9924c4d4cf ("ppc/pnv: Add models for POWER9 PHB4 PCIe Host bridge")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3591
Signed-off-by: Nikhil Kumar Singh <[email protected]>
---
hw/pci-host/pnv_phb4.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 705a5bcf07..02ca2f978c 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -84,7 +84,9 @@ static void pnv_phb4_config_write(PnvPHB4 *phb, unsigned off,
val = bswap32(val);
break;
default:
- g_assert_not_reached();
+ phb_error(phb, "invalid config write size %u at offset 0x%x\n",
+ size, off);
+ return;
}
pci_host_config_write_common(pdev, cfg_addr, limit, val, size);
}
@@ -119,7 +121,9 @@ static uint64_t pnv_phb4_config_read(PnvPHB4 *phb, unsigned off,
case 4:
return bswap32(val);
default:
- g_assert_not_reached();
+ phb_error(phb, "invalid config read size %u at offset 0x%x\n",
+ size, off);
+ return ~0ull;
}
}
@@ -507,6 +511,11 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
/* Special case outbound configuration data */
if ((off & 0xfffc) == PHB_CONFIG_DATA) {
+ if (size > 4) {
+ phb_error(phb, "invalid config write size %u at 0x%"PRIx64"\n",
+ size, off);
+ return;
+ }
pnv_phb4_config_write(phb, off & 0x3, size, val);
return;
}
@@ -644,6 +653,11 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
uint64_t val;
if ((off & 0xfffc) == PHB_CONFIG_DATA) {
+ if (size > 4) {
+ phb_error(phb, "invalid config read size %u at 0x%"PRIx64"\n",
+ size, off);
+ return ~0ull;
+ }
return pnv_phb4_config_read(phb, off & 0x3, size);
}
--
2.54.0