* [PULL 01/13] vfio/igd: Clear saved BDSM in legacy VBIOS ROM at load time
2026-07-21 17:05 [PULL 00/13] vfio queue Cédric Le Goater
@ 2026-07-21 17:05 ` Cédric Le Goater
2026-07-21 17:05 ` [PULL 02/13] vfio/region: Clarify dma-buf failure messages Cédric Le Goater
` (12 subsequent siblings)
13 siblings, 0 replies; 17+ messages in thread
From: Cédric Le Goater @ 2026-07-21 17:05 UTC (permalink / raw)
To: qemu-devel
Cc: Tomita Moeko, K S Maan, qemu-stable, Alex Williamson,
Cédric Le Goater
From: Tomita Moeko <tomitamoeko@gmail.com>
IGD does not come with a ROM BAR [1], the ROM BAR read by default from
kernel is actually the host VBIOS shadow RAM region that contains host
modifications on boot. With AI-assisted reverse engineering on VBIOS
binaries, it is observed that VBIOS saves BDSM register value on first
access and uses saved value if present.
When the image is executed in guest, since there is already a saved HPA
in VBIOS, it keeps using that value instead of the GPA programmed by
SeaBIOS in BDSM register in PCI config space, causing VBIOS to program
GTT entries with wrong address, resulting in garbled output in BIOS
POST and the error below detected by i915 driver.
i915 0000:00:02.0: [drm] *ERROR* Initial plane programming using invalid range, dma_addr=0x00000000db200000 ((null) [0x00000000baf00000-0x00000000beefffff])
The previous solution, c4c45e943e51 ("vfio/pci: Intel graphics legacy
mode assignment"), adjusts GTT entry addresses to (addr - host BDSM +
guest BDSM) to workaround that. But it is removed in 5aed8b0f0be2
("vfio/igd: Remove GTT write quirk in IO BAR 4") due to inconsistent
values in MMIO BAR0 and IO BAR4.
Since it was a value latched into the VBIOS that breaks virtualization
(QEMU does not map the GTT at the same address in the VM), a ROM quirk
clearing the saved value in VBIOS image is introduced. It searches the
BDSM accessor routine by matching a 19-byte signature anchored on the
unique `mov $0x105e,%ax` instruction, then locates the offset of saved
BDSM and clears it. This makes the routine fall through to the PCI
config read on the first call inside the guest.
[1] 3.5.15, 4th Generation Intel Core Processor Family Datasheet Vol. 2
https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/4th-gen-core-family-desktop-vol-2-datasheet.pdf
Fixes: 5aed8b0f0be2 ("vfio/igd: Remove GTT write quirk in IO BAR 4")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3093
Reported-by: K S Maan <kirandeepmaan45@gmail.com>
Cc: qemu-stable@nongnu.org
Signed-off-by: Tomita Moeko <tomitamoeko@gmail.com>
Reviewed-by: Alex Williamson <alex@shazbot.org>
Link: https://lore.kernel.org/qemu-devel/20260708103100.23127-1-tomitamoeko@gmail.com
Signed-off-by: Cédric Le Goater <clg@redhat.com>
---
hw/vfio/pci.h | 3 ++
hw/vfio/igd-stubs.c | 5 ++
hw/vfio/igd.c | 115 +++++++++++++++++++++++++++++++++++++++++++
hw/vfio/pci-quirks.c | 5 ++
hw/vfio/pci.c | 2 +
hw/vfio/trace-events | 1 +
6 files changed, 131 insertions(+)
diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h
index fe52e9df6e67707c9899d418b0261afeedf4aab2..c9ab9498708ec0343e206c7f343085b0be8a7a1e 100644
--- a/hw/vfio/pci.h
+++ b/hw/vfio/pci.h
@@ -252,10 +252,13 @@ void vfio_bar_quirk_exit(VFIOPCIDevice *vdev, int nr);
void vfio_bar_quirk_finalize(VFIOPCIDevice *vdev, int nr);
void vfio_setup_resetfn_quirk(VFIOPCIDevice *vdev);
bool vfio_add_virt_caps(VFIOPCIDevice *vdev, Error **errp);
+void vfio_rom_quirk_setup(VFIOPCIDevice *vdev);
void vfio_quirk_reset(VFIOPCIDevice *vdev);
VFIOQuirk *vfio_quirk_alloc(int nr_mem);
+
void vfio_probe_igd_bar0_quirk(VFIOPCIDevice *vdev, int nr);
bool vfio_probe_igd_config_quirk(VFIOPCIDevice *vdev, Error **errp);
+void vfio_igd_legacy_rom_quirk(VFIOPCIDevice *vdev);
extern const PropertyInfo qdev_prop_nv_gpudirect_clique;
diff --git a/hw/vfio/igd-stubs.c b/hw/vfio/igd-stubs.c
index f7687d909125c2233e76f7e6d03aa90f38c3b89f..5f60b24c8b46d94f0de2573aeb6b6c80690476cb 100644
--- a/hw/vfio/igd-stubs.c
+++ b/hw/vfio/igd-stubs.c
@@ -18,3 +18,8 @@ bool vfio_probe_igd_config_quirk(VFIOPCIDevice *vdev, Error **errp)
{
return true;
}
+
+void vfio_igd_legacy_rom_quirk(VFIOPCIDevice *vdev)
+{
+ return;
+}
diff --git a/hw/vfio/igd.c b/hw/vfio/igd.c
index e091f21b6a3aea0013e0b3094d2ca13588200c98..413a49aae9163c6500bc50f29e5454f698addaa4 100644
--- a/hw/vfio/igd.c
+++ b/hw/vfio/igd.c
@@ -724,3 +724,118 @@ bool vfio_probe_igd_config_quirk(VFIOPCIDevice *vdev, Error **errp)
return vfio_pci_igd_config_quirk(vdev, errp);
}
+
+/*
+ * IGD ROM BAR read from kernel is actually the host VBIOS shadow RAM region,
+ * which contains host modifications. In Gen 6-9 VBIOS, the routine below is
+ * used to get BDSM value when programming the initial GTT.
+ * xx xx xx xx v: .long ? # saved value
+ * 66 53 push %ebx
+ * 66 2e 83 3e xx xx 00 cmpl $0x0,%cs:v # is saved value empty?
+ * 74 07 je 1f # if zero, go compute
+ * 66 2e a1 xx xx mov %cs:v,%eax # else return saved value
+ * eb 0f jmp 2f
+ * b8 5e 10 1: mov $0x105e,%ax # dev 00:02.0, offset 5E
+ * e8 xx xx call pci_read_cfg_word
+ * 66 c1 e0 10 shl $0x10,%eax # left shift 16 bits
+ * 66 2e a3 xx xx mov %eax,%cs:v # save the result
+ * 66 5b 2: pop %ebx
+ * c3 ret
+ * When running the VBIOS in guest, saved value still reflects the host stolen
+ * memory base address, which is not correct in guest. So we need to patch the
+ * VBIOS to clear the saved value.
+ *
+ * The unique 19-byte starts at `cmpl $0,%cs:v` and ends at `mov $0x105e,%ax`
+ * anchors the match to the routine. Both `cs:` displacements must reference
+ * the same offset.
+ */
+static int igd_vbios_find_saved_bdsm(const uint8_t *rom, size_t rom_size,
+ uint16_t *bdsm_offset)
+{
+ static const uint8_t start[] = { 0x66, 0x2e, 0x83, 0x3e };
+ static const uint8_t middle[] = { 0x00, 0x74, 0x07, 0x66, 0x2e, 0xa1 };
+ static const uint8_t end[] = { 0xeb, 0x0f, 0xb8, 0x5e, 0x10 };
+ uint16_t val;
+ size_t i;
+ bool found = false;
+
+ if (rom_size < 19) {
+ return -ENOENT;
+ }
+
+ for (i = 0; i + 19 <= rom_size; i++) {
+ if (memcmp(rom + i, start, sizeof(start)) != 0 ||
+ memcmp(rom + i + 6, middle, sizeof(middle)) != 0 ||
+ memcmp(rom + i + 14, end, sizeof(end)) != 0) {
+ continue;
+ }
+
+ /* same saved value address? */
+ if (rom[i + 4] != rom[i + 12] || rom[i + 5] != rom[i + 13]) {
+ continue;
+ }
+
+ if (found) {
+ return -EEXIST;
+ }
+
+ val = rom[i + 4] | ((uint16_t)rom[i + 5] << 8);
+ if (val + sizeof(uint32_t) <= rom_size) {
+ *bdsm_offset = val;
+ found = true;
+ }
+ }
+
+ if (!found) {
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+void vfio_igd_legacy_rom_quirk(VFIOPCIDevice *vdev)
+{
+ uint8_t *rom = vdev->rom;
+ int gen;
+ uint16_t pcir_offset;
+ uint16_t bdsm_offset = 0;
+ uint8_t checksum = 0;
+ uint32_t i;
+
+ if (!vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, PCI_ANY_ID) ||
+ !vfio_is_vga(vdev) || !vdev->vga) {
+ return;
+ }
+
+ /* Only Gen 6~9 devices have legacy VBIOS as Option ROM */
+ gen = igd_gen(vdev);
+ if (gen < 6 || gen > 9) {
+ return;
+ }
+
+ if (pci_get_word(rom) != 0xaa55) {
+ return;
+ }
+
+ /* Must be a legacy ROM */
+ pcir_offset = pci_get_word(rom + 0x18);
+ if (pcir_offset + 0x14 >= vdev->rom_size ||
+ memcmp(rom + pcir_offset, "PCIR", 4) ||
+ pci_get_byte(rom + pcir_offset + 0x14) != 0x00) {
+ return;
+ }
+
+ /* Search and clear the saved BDSM value */
+ if (igd_vbios_find_saved_bdsm(rom, vdev->rom_size, &bdsm_offset)) {
+ return;
+ }
+ memset(rom + bdsm_offset, 0, sizeof(uint32_t));
+
+ /* Recalculate checksum and patch it. */
+ for (i = 0; i < vdev->rom_size; i++) {
+ checksum += rom[i];
+ }
+ rom[6] -= checksum;
+
+ trace_vfio_pci_igd_vbios_patched(vdev->vbasedev.name);
+}
diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c
index bccf31751fd47387fd89110e27b695e5c822d5c4..c5b4f9091d498d49eb3371c0502e7ab6b7b76b30 100644
--- a/hw/vfio/pci-quirks.c
+++ b/hw/vfio/pci-quirks.c
@@ -1592,3 +1592,8 @@ bool vfio_add_virt_caps(VFIOPCIDevice *vdev, Error **errp)
return true;
}
+
+void vfio_rom_quirk_setup(VFIOPCIDevice *vdev)
+{
+ vfio_igd_legacy_rom_quirk(vdev);
+}
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index c204706e63045c930bda7977adc8034f907b6890..dcfc92aae1c78d3a803665bcaea1e83f66a6d030 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -1119,6 +1119,8 @@ static bool vfio_pci_load_rom(VFIOPCIDevice *vdev, Error **errp)
}
}
+ vfio_rom_quirk_setup(vdev);
+
return true;
}
diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events
index f71d0bbc0a5440e4ccd374fac4733af08438e7be..bfdaf229e42b0d9d40e38c828c97cf47eb831a87 100644
--- a/hw/vfio/trace-events
+++ b/hw/vfio/trace-events
@@ -90,6 +90,7 @@ vfio_pci_igd_bar4_write(const char *name, uint32_t index, uint32_t data, uint32_
vfio_pci_igd_bdsm_enabled(const char *name, int size) "%s %dMB"
vfio_pci_igd_host_bridge_enabled(const char *name) "%s"
vfio_pci_igd_lpc_bridge_enabled(const char *name) "%s"
+vfio_pci_igd_vbios_patched(const char *name) "%s"
# listener.c
vfio_iommu_map_notify(const char *op, uint64_t iova_start, uint64_t iova_end) "iommu %s @ 0x%"PRIx64" - 0x%"PRIx64
--
2.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PULL 02/13] vfio/region: Clarify dma-buf failure messages
2026-07-21 17:05 [PULL 00/13] vfio queue Cédric Le Goater
2026-07-21 17:05 ` [PULL 01/13] vfio/igd: Clear saved BDSM in legacy VBIOS ROM at load time Cédric Le Goater
@ 2026-07-21 17:05 ` Cédric Le Goater
2026-07-21 17:05 ` [PULL 03/13] vfio/pci: don't narrow a failed config read to a plausible value Cédric Le Goater
` (11 subsequent siblings)
13 siblings, 0 replies; 17+ messages in thread
From: Cédric Le Goater @ 2026-07-21 17:05 UTC (permalink / raw)
To: qemu-devel
Cc: Cédric Le Goater, Nicolin Chen, Philippe Mathieu-Daudé
The dma-buf failure messages in vfio_region_create_dma_buf() say "PCI
BAR IOMMU mappings may fail", which suggests the BAR is broken. In
practice, only P2P DMA is affected -- normal passthrough uses the mmap
fallback.
Reword both messages to mention P2P DMA explicitly and clarify that
the mmap fallback is in use. Use warn_report_err_once() at the call
site so per-BAR repetition on mdev devices is suppressed.
Fixes: dcf1b77e834d ("hw/vfio/region: Create dmabuf for PCI BAR per region")
Cc: Nicolin Chen <nicolinc@nvidia.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Signed-off-by: Cédric Le Goater <clg@redhat.com>
---
hw/vfio/region.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/hw/vfio/region.c b/hw/vfio/region.c
index dbde3391802691888ca31d5e329aba5ba680feb4..54ad11a6c8ed8e04fa365262ccb8bd694bdb45f7 100644
--- a/hw/vfio/region.c
+++ b/hw/vfio/region.c
@@ -321,13 +321,12 @@ static bool vfio_region_create_dma_buf(VFIORegion *region, Error **errp)
ret = vfio_device_get_feature(vbasedev, feature);
if (ret < 0) {
if (ret == -ENOTTY) {
- warn_report_once("VFIO dma-buf not supported in kernel: "
- "PCI BAR IOMMU mappings may fail");
+ warn_report_once("VFIO dma-buf not supported in kernel, "
+ "using mmap fallback, P2P DMA will not work");
return true;
}
- /* P2P DMA or exposing device memory use cases are not supported. */
- error_setg_errno(errp, -ret, "%s: failed to create dma-buf: "
- "PCI BAR IOMMU mappings may fail",
+ error_setg_errno(errp, -ret, "%s: dma-buf unavailable, "
+ "using mmap fallback, P2P DMA will not work",
memory_region_name(region->mem));
return false;
}
@@ -448,7 +447,7 @@ int vfio_region_mmap(VFIORegion *region)
}
if (!vfio_region_create_dma_buf(region, &local_err)) {
- error_report_err(local_err);
+ warn_report_err_once(local_err);
}
return 0;
--
2.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PULL 03/13] vfio/pci: don't narrow a failed config read to a plausible value
2026-07-21 17:05 [PULL 00/13] vfio queue Cédric Le Goater
2026-07-21 17:05 ` [PULL 01/13] vfio/igd: Clear saved BDSM in legacy VBIOS ROM at load time Cédric Le Goater
2026-07-21 17:05 ` [PULL 02/13] vfio/region: Clarify dma-buf failure messages Cédric Le Goater
@ 2026-07-21 17:05 ` Cédric Le Goater
2026-07-21 17:05 ` [PULL 04/13] vfio/pci: reject invalid PCI_INTERRUPT_PIN values Cédric Le Goater
` (10 subsequent siblings)
13 siblings, 0 replies; 17+ messages in thread
From: Cédric Le Goater @ 2026-07-21 17:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Denis V. Lunev, Alex Williamson, Cédric Le Goater
From: "Denis V. Lunev" <den@openvz.org>
vfio_pci_read_config() signals a failed host-side read by returning
(uint32_t)-1, regardless of the requested length. vfio_intx_enable()
and vfio_pci_pre_reset() both narrowed that return value straight
into a uint8_t/uint16_t local before checking anything, which
truncates -1 into 0xff or 0xffff - values a real 1- or 2-byte
register read can legitimately produce. From that point on, a
failed read and real all-ones content are indistinguishable.
Keep the full uint32_t result and check it against (uint32_t)-1
before narrowing. In vfio_pci_pre_reset(), skip the corresponding
write-back on a failed read instead of writing back constructed
garbage to the device.
Resolves: Coverity CID 1663684
Resolves: Coverity CID 1663688
Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Alex Williamson <alex@shazbot.org>
CC: Cédric Le Goater <clg@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20260717122232.468955-2-den@openvz.org
[ clg: Added Coverity IDs ]
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Signed-off-by: Cédric Le Goater <clg@redhat.com>
---
hw/vfio/pci.c | 32 +++++++++++++++++++++++++-------
1 file changed, 25 insertions(+), 7 deletions(-)
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index dcfc92aae1c78d3a803665bcaea1e83f66a6d030..b8c937d4be50091691875f2253c4d03ba83df704 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -323,10 +323,16 @@ static void vfio_irqchip_change(Notifier *notify, void *data)
static bool vfio_intx_enable(VFIOPCIDevice *vdev, Error **errp)
{
PCIDevice *pdev = PCI_DEVICE(vdev);
- uint8_t pin = vfio_pci_read_config(pdev, PCI_INTERRUPT_PIN, 1);
+ uint32_t val = vfio_pci_read_config(pdev, PCI_INTERRUPT_PIN, 1);
+ uint8_t pin;
Error *err = NULL;
int32_t fd;
+ if (val == (uint32_t)-1) {
+ error_setg(errp, "failed to read PCI_INTERRUPT_PIN");
+ return false;
+ }
+ pin = val;
if (!pin) {
return true;
@@ -2766,6 +2772,7 @@ bool vfio_pci_add_capabilities(VFIOPCIDevice *vdev, Error **errp)
void vfio_pci_pre_reset(VFIOPCIDevice *vdev)
{
PCIDevice *pdev = PCI_DEVICE(vdev);
+ uint32_t val;
uint16_t cmd;
vfio_disable_interrupts(vdev);
@@ -2774,23 +2781,34 @@ void vfio_pci_pre_reset(VFIOPCIDevice *vdev)
* Stop any ongoing DMA by disconnecting I/O, MMIO, and bus master.
* Also put INTx Disable in known state.
*/
- cmd = vfio_pci_read_config(pdev, PCI_COMMAND, 2);
- cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
- PCI_COMMAND_INTX_DISABLE);
- vfio_pci_write_config(pdev, PCI_COMMAND, cmd, 2);
+ val = vfio_pci_read_config(pdev, PCI_COMMAND, 2);
+ if (val != (uint32_t)-1) {
+ cmd = val;
+ cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+ PCI_COMMAND_INTX_DISABLE);
+ vfio_pci_write_config(pdev, PCI_COMMAND, cmd, 2);
+ }
/* Make sure the device is in D0 */
if (pdev->pm_cap) {
uint16_t pmcsr;
uint8_t state;
- pmcsr = vfio_pci_read_config(pdev, pdev->pm_cap + PCI_PM_CTRL, 2);
+ val = vfio_pci_read_config(pdev, pdev->pm_cap + PCI_PM_CTRL, 2);
+ if (val == (uint32_t)-1) {
+ return;
+ }
+ pmcsr = val;
state = pmcsr & PCI_PM_CTRL_STATE_MASK;
if (state) {
pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
vfio_pci_write_config(pdev, pdev->pm_cap + PCI_PM_CTRL, pmcsr, 2);
/* vfio handles the necessary delay here */
- pmcsr = vfio_pci_read_config(pdev, pdev->pm_cap + PCI_PM_CTRL, 2);
+ val = vfio_pci_read_config(pdev, pdev->pm_cap + PCI_PM_CTRL, 2);
+ if (val == (uint32_t)-1) {
+ return;
+ }
+ pmcsr = val;
state = pmcsr & PCI_PM_CTRL_STATE_MASK;
if (state) {
error_report("vfio: Unable to power on device, stuck in D%d",
--
2.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PULL 04/13] vfio/pci: reject invalid PCI_INTERRUPT_PIN values
2026-07-21 17:05 [PULL 00/13] vfio queue Cédric Le Goater
` (2 preceding siblings ...)
2026-07-21 17:05 ` [PULL 03/13] vfio/pci: don't narrow a failed config read to a plausible value Cédric Le Goater
@ 2026-07-21 17:05 ` Cédric Le Goater
2026-07-21 17:05 ` [PULL 05/13] vfio-user: vfio_user_get_region_info: prevent buffer overflow Cédric Le Goater
` (9 subsequent siblings)
13 siblings, 0 replies; 17+ messages in thread
From: Cédric Le Goater @ 2026-07-21 17:05 UTC (permalink / raw)
To: qemu-devel
Cc: Denis V. Lunev, Alex Williamson, Cédric Le Goater,
Philippe Mathieu-Daudé
From: "Denis V. Lunev" <den@openvz.org>
qemu-kvm aborts a few seconds after starting a VM with a
passed-through GPU whose PCI_INTERRUPT_PIN comes back as an
out-of-range value: vfio_intx_enable() only guards against pin == 0
and stores vdev->intx.pin = pin - 1 with no upper-bound check. That
value later reaches pci_irq_handler()'s
assert(0 <= irq_num && irq_num < PCI_NUM_PINS) via
pci_irq_deassert() -> pci_set_irq(), aborting the process.
Legal PCI_INTERRUPT_PIN values are 0 (no legacy interrupt) or
1-PCI_NUM_PINS (INTA-INTD); reject anything else before it reaches
vdev->intx.pin, whether the out-of-range value came from a read
failure (now caught by the previous commit) or was handed back as
data by the device itself.
Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Alex Williamson <alex@shazbot.org>
CC: Cédric Le Goater <clg@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20260717122232.468955-3-den@openvz.org
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Signed-off-by: Cédric Le Goater <clg@redhat.com>
---
hw/vfio/pci.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index b8c937d4be50091691875f2253c4d03ba83df704..380dd8c15f8d5bb98b725075978eef2e4e1e6c2d 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -338,6 +338,11 @@ static bool vfio_intx_enable(VFIOPCIDevice *vdev, Error **errp)
return true;
}
+ if (pin > PCI_NUM_PINS) {
+ error_setg(errp, "invalid PCI interrupt pin %d", pin);
+ return false;
+ }
+
/*
* Do not alter interrupt state during vfio_realize and cpr load.
* The incoming state is cleared thereafter.
--
2.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PULL 05/13] vfio-user: vfio_user_get_region_info: prevent buffer overflow
2026-07-21 17:05 [PULL 00/13] vfio queue Cédric Le Goater
` (3 preceding siblings ...)
2026-07-21 17:05 ` [PULL 04/13] vfio/pci: reject invalid PCI_INTERRUPT_PIN values Cédric Le Goater
@ 2026-07-21 17:05 ` Cédric Le Goater
2026-07-21 17:05 ` [PULL 06/13] vfio-user: vfio_user_get_region_info: respect max_xfer_size Cédric Le Goater
` (8 subsequent siblings)
13 siblings, 0 replies; 17+ messages in thread
From: Cédric Le Goater @ 2026-07-21 17:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Thanos Makatos, Cédric Le Goater
From: Thanos Makatos <thanos.makatos@nutanix.com>
If the vfio-user responds with a value large enough such that adding
the header size to it overflows, a smaller buffer would be
inadvertently allocated, leading to buffer overflow.
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3867
Signed-off-by: Thanos Makatos <thanos.makatos@nutanix.com>
Fixes: 667866d66620 ("vfio-user: implement VFIO_USER_DEVICE_GET_REGION_INFO")
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20260721122643.30985-2-thanos.makatos@nutanix.com
Signed-off-by: Cédric Le Goater <clg@redhat.com>
---
hw/vfio-user/device.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/hw/vfio-user/device.c b/hw/vfio-user/device.c
index b8d2b7c1a84bb1914a71fdccbbdff675373cef3b..e58167a81879e94520bda24717280e2347422e77 100644
--- a/hw/vfio-user/device.c
+++ b/hw/vfio-user/device.c
@@ -128,12 +128,21 @@ static int vfio_user_get_region_info(VFIOUserProxy *proxy,
error_printf("vfio_user_get_region_info argsz too small\n");
return -E2BIG;
}
+
+ /*
+ * Ensure that size doesn't overflow, otherwise we'll allocate a much
+ * smaller buffer than we need.
+ */
+ if (__builtin_add_overflow(info->argsz, sizeof(VFIOUserHdr), &size)) {
+ error_printf("vfio_user_get_region_info argsz too large\n");
+ return -E2BIG;
+ }
+
if (fds != NULL && fds->send_fds != 0) {
error_printf("vfio_user_get_region_info can't send FDs\n");
return -EINVAL;
}
- size = info->argsz + sizeof(VFIOUserHdr);
msgp = g_malloc0(size);
vfio_user_request_msg(&msgp->hdr, VFIO_USER_DEVICE_GET_REGION_INFO,
--
2.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PULL 06/13] vfio-user: vfio_user_get_region_info: respect max_xfer_size
2026-07-21 17:05 [PULL 00/13] vfio queue Cédric Le Goater
` (4 preceding siblings ...)
2026-07-21 17:05 ` [PULL 05/13] vfio-user: vfio_user_get_region_info: prevent buffer overflow Cédric Le Goater
@ 2026-07-21 17:05 ` Cédric Le Goater
2026-07-21 17:05 ` [PULL 07/13] vfio-user: vfio_user_get_region_info: reject unreasonably short struct Cédric Le Goater
` (7 subsequent siblings)
13 siblings, 0 replies; 17+ messages in thread
From: Cédric Le Goater @ 2026-07-21 17:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Thanos Makatos, Cédric Le Goater
From: Thanos Makatos <thanos.makatos@nutanix.com>
Signed-off-by: Thanos Makatos <thanos.makatos@nutanix.com>
Fixes: 667866d66620 ("vfio-user: implement VFIO_USER_DEVICE_GET_REGION_INFO")
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20260721122643.30985-3-thanos.makatos@nutanix.com
Signed-off-by: Cédric Le Goater <clg@redhat.com>
---
hw/vfio-user/device.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/hw/vfio-user/device.c b/hw/vfio-user/device.c
index e58167a81879e94520bda24717280e2347422e77..8350bb2c018504dbca50a4e9afbfc6be251f5b2a 100644
--- a/hw/vfio-user/device.c
+++ b/hw/vfio-user/device.c
@@ -137,6 +137,10 @@ static int vfio_user_get_region_info(VFIOUserProxy *proxy,
error_printf("vfio_user_get_region_info argsz too large\n");
return -E2BIG;
}
+ if (size > proxy->max_xfer_size) {
+ error_printf("vfio_user_get_region_info argsz too large\n");
+ return -E2BIG;
+ }
if (fds != NULL && fds->send_fds != 0) {
error_printf("vfio_user_get_region_info can't send FDs\n");
--
2.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PULL 07/13] vfio-user: vfio_user_get_region_info: reject unreasonably short struct
2026-07-21 17:05 [PULL 00/13] vfio queue Cédric Le Goater
` (5 preceding siblings ...)
2026-07-21 17:05 ` [PULL 06/13] vfio-user: vfio_user_get_region_info: respect max_xfer_size Cédric Le Goater
@ 2026-07-21 17:05 ` Cédric Le Goater
2026-07-21 17:05 ` [PULL 08/13] vfio-user: vfio_user_get_region_info: prevent excessive malloc Cédric Le Goater
` (6 subsequent siblings)
13 siblings, 0 replies; 17+ messages in thread
From: Cédric Le Goater @ 2026-07-21 17:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Thanos Makatos, Cédric Le Goater
From: Thanos Makatos <thanos.makatos@nutanix.com>
While this isn't technically a bug, it's highly unlikely that the
server wouldn't be writing an entire struct.
Signed-off-by: Thanos Makatos <thanos.makatos@nutanix.com>
Fixes: 667866d66620 ("vfio-user: implement VFIO_USER_DEVICE_GET_REGION_INFO")
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20260721122643.30985-4-thanos.makatos@nutanix.com
Signed-off-by: Cédric Le Goater <clg@redhat.com>
---
hw/vfio-user/device.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/hw/vfio-user/device.c b/hw/vfio-user/device.c
index 8350bb2c018504dbca50a4e9afbfc6be251f5b2a..3d12e8b2a20eb96fb1a8a944070d13bf0e049b67 100644
--- a/hw/vfio-user/device.c
+++ b/hw/vfio-user/device.c
@@ -165,6 +165,11 @@ static int vfio_user_get_region_info(VFIOUserProxy *proxy,
}
trace_vfio_user_get_region_info(msgp->index, msgp->flags, msgp->size);
+ if (msgp->argsz < sizeof(*info)) {
+ error_printf("vfio_user_get_region_info reply argsz too small\n");
+ return -EINVAL;
+ }
+
memcpy(info, &msgp->argsz, info->argsz);
/*
--
2.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PULL 08/13] vfio-user: vfio_user_get_region_info: prevent excessive malloc
2026-07-21 17:05 [PULL 00/13] vfio queue Cédric Le Goater
` (6 preceding siblings ...)
2026-07-21 17:05 ` [PULL 07/13] vfio-user: vfio_user_get_region_info: reject unreasonably short struct Cédric Le Goater
@ 2026-07-21 17:05 ` Cédric Le Goater
2026-07-21 17:05 ` [PULL 09/13] vfio-user: vfio_user_device_io_get_region_info: fix capability check Cédric Le Goater
` (5 subsequent siblings)
13 siblings, 0 replies; 17+ messages in thread
From: Cédric Le Goater @ 2026-07-21 17:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Thanos Makatos, Cédric Le Goater
From: Thanos Makatos <thanos.makatos@nutanix.com>
If the vfio-user server responds with a value larger than max_xfer_size
vfio_device_get_region_info() blindly uses it in the next loop in
g_realloc. An value larger than max_xfer_size is anyway rejected by the
check at the beginning of vfio_user_get_region_info(), however that only
happens _after_ the g_realloc, and if that value is excessively large it
can cause g_realloc to fail, so check it here.
Signed-off-by: Thanos Makatos <thanos.makatos@nutanix.com>
Fixes: 667866d66620 ("vfio-user: implement VFIO_USER_DEVICE_GET_REGION_INFO")
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20260721122643.30985-5-thanos.makatos@nutanix.com
Signed-off-by: Cédric Le Goater <clg@redhat.com>
---
hw/vfio-user/device.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/hw/vfio-user/device.c b/hw/vfio-user/device.c
index 3d12e8b2a20eb96fb1a8a944070d13bf0e049b67..008e5cf6877c84c3d0cf33f25a6ac9a4cf231e06 100644
--- a/hw/vfio-user/device.c
+++ b/hw/vfio-user/device.c
@@ -170,6 +170,16 @@ static int vfio_user_get_region_info(VFIOUserProxy *proxy,
return -EINVAL;
}
+ /*
+ * The server can respond with a larger argsz in the reply to request a
+ * larger buffer on the next iteration via vfio_device_get_region_info().
+ * Reject values that would trigger an oversized realloc.
+ */
+ if (msgp->argsz > proxy->max_xfer_size) {
+ error_printf("vfio_user_get_region_info reply argsz too large\n");
+ return -E2BIG;
+ }
+
memcpy(info, &msgp->argsz, info->argsz);
/*
--
2.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PULL 09/13] vfio-user: vfio_user_device_io_get_region_info: fix capability check
2026-07-21 17:05 [PULL 00/13] vfio queue Cédric Le Goater
` (7 preceding siblings ...)
2026-07-21 17:05 ` [PULL 08/13] vfio-user: vfio_user_get_region_info: prevent excessive malloc Cédric Le Goater
@ 2026-07-21 17:05 ` Cédric Le Goater
2026-07-21 17:05 ` [PULL 10/13] vfio-user: vfio_user_device_io_device_feature: prevent buffer overflow Cédric Le Goater
` (4 subsequent siblings)
13 siblings, 0 replies; 17+ messages in thread
From: Cédric Le Goater @ 2026-07-21 17:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Thanos Makatos, Cédric Le Goater
From: Thanos Makatos <thanos.makatos@nutanix.com>
The existing check for PCI capabilities misses the case where
info->cap_offset == info->argsz, which results in accessing unallocated
memory. Fix the comparison.
Fixes: 667866d66620 ("vfio-user: implement VFIO_USER_DEVICE_GET_REGION_INFO")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3865
Signed-off-by: Thanos Makatos <thanos.makatos@nutanix.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20260721122643.30985-6-thanos.makatos@nutanix.com
Signed-off-by: Cédric Le Goater <clg@redhat.com>
---
hw/vfio-user/device.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/hw/vfio-user/device.c b/hw/vfio-user/device.c
index 008e5cf6877c84c3d0cf33f25a6ac9a4cf231e06..3d0dbe840649b7b678b79afd3dbc7f9caaeb947b 100644
--- a/hw/vfio-user/device.c
+++ b/hw/vfio-user/device.c
@@ -214,7 +214,8 @@ static int vfio_user_device_io_get_region_info(VFIODevice *vbasedev,
/* cap_offset in valid area */
if ((info->flags & VFIO_REGION_INFO_FLAG_CAPS) &&
- (info->cap_offset < sizeof(*info) || info->cap_offset > info->argsz)) {
+ (info->cap_offset < sizeof(*info)
+ || info->cap_offset + sizeof(struct vfio_info_cap_header) > info->argsz)) {
return -EINVAL;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PULL 10/13] vfio-user: vfio_user_device_io_device_feature: prevent buffer overflow
2026-07-21 17:05 [PULL 00/13] vfio queue Cédric Le Goater
` (8 preceding siblings ...)
2026-07-21 17:05 ` [PULL 09/13] vfio-user: vfio_user_device_io_get_region_info: fix capability check Cédric Le Goater
@ 2026-07-21 17:05 ` Cédric Le Goater
2026-07-21 17:05 ` [PULL 11/13] vfio-user: vfio_user_device_io_device_feature: prevent excessive malloc Cédric Le Goater
` (3 subsequent siblings)
13 siblings, 0 replies; 17+ messages in thread
From: Cédric Le Goater @ 2026-07-21 17:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Thanos Makatos, Cédric Le Goater
From: Thanos Makatos <thanos.makatos@nutanix.com>
This isn't in practise a problem since feature->argsz is not
externally provided, it's a good hardening step nonetheless.
Fixes: e2358af5838d ("vfio-user: support VFIO_USER_DEVICE_FEATURE")
Signed-off-by: Thanos Makatos <thanos.makatos@nutanix.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20260721122643.30985-7-thanos.makatos@nutanix.com
Signed-off-by: Cédric Le Goater <clg@redhat.com>
---
hw/vfio-user/device.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/hw/vfio-user/device.c b/hw/vfio-user/device.c
index 3d0dbe840649b7b678b79afd3dbc7f9caaeb947b..353fa5ee21e34a88bcd0eff9de40d9757387a616 100644
--- a/hw/vfio-user/device.c
+++ b/hw/vfio-user/device.c
@@ -79,9 +79,14 @@ vfio_user_device_io_device_feature(VFIODevice *vbasedev,
struct vfio_device_feature *feature)
{
g_autofree VFIOUserDeviceFeature *msgp = NULL;
- int size = sizeof(VFIOUserHdr) + feature->argsz;
VFIOUserProxy *proxy = vbasedev->proxy;
Error *local_err = NULL;
+ int size;
+
+ if (__builtin_add_overflow(feature->argsz, sizeof(VFIOUserHdr), &size)) {
+ error_printf("vfio_user_device_io_device_feature argsz too large\n");
+ return -E2BIG;
+ }
msgp = g_malloc0(size);
--
2.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PULL 11/13] vfio-user: vfio_user_device_io_device_feature: prevent excessive malloc
2026-07-21 17:05 [PULL 00/13] vfio queue Cédric Le Goater
` (9 preceding siblings ...)
2026-07-21 17:05 ` [PULL 10/13] vfio-user: vfio_user_device_io_device_feature: prevent buffer overflow Cédric Le Goater
@ 2026-07-21 17:05 ` Cédric Le Goater
2026-07-21 17:05 ` [PULL 12/13] vfio-user: vfio_user_device_io_set_irqs: prevent buffer overflow Cédric Le Goater
` (2 subsequent siblings)
13 siblings, 0 replies; 17+ messages in thread
From: Cédric Le Goater @ 2026-07-21 17:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Thanos Makatos, Cédric Le Goater
From: Thanos Makatos <thanos.makatos@nutanix.com>
This isn't in practise a problem since feature->argsz is not externally
provided, it's a good hardening step nonetheless.
Fixes: e2358af5838d ("vfio-user: support VFIO_USER_DEVICE_FEATURE")
Signed-off-by: Thanos Makatos <thanos.makatos@nutanix.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20260721122643.30985-8-thanos.makatos@nutanix.com
Signed-off-by: Cédric Le Goater <clg@redhat.com>
---
hw/vfio-user/device.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/hw/vfio-user/device.c b/hw/vfio-user/device.c
index 353fa5ee21e34a88bcd0eff9de40d9757387a616..8feaa568750ed1978dbc273da2054c89ad3bcc96 100644
--- a/hw/vfio-user/device.c
+++ b/hw/vfio-user/device.c
@@ -87,6 +87,10 @@ vfio_user_device_io_device_feature(VFIODevice *vbasedev,
error_printf("vfio_user_device_io_device_feature argsz too large\n");
return -E2BIG;
}
+ if (size > proxy->max_xfer_size) {
+ error_printf("vfio_user_device_io_device_feature argsz too large\n");
+ return -E2BIG;
+ }
msgp = g_malloc0(size);
--
2.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PULL 12/13] vfio-user: vfio_user_device_io_set_irqs: prevent buffer overflow
2026-07-21 17:05 [PULL 00/13] vfio queue Cédric Le Goater
` (10 preceding siblings ...)
2026-07-21 17:05 ` [PULL 11/13] vfio-user: vfio_user_device_io_device_feature: prevent excessive malloc Cédric Le Goater
@ 2026-07-21 17:05 ` Cédric Le Goater
2026-07-21 17:05 ` [PULL 13/13] vfio-user: vfio_user_device_io_set_irqs: prevent excessive malloc Cédric Le Goater
2026-07-22 17:58 ` [PULL 00/13] vfio queue Stefan Hajnoczi
13 siblings, 0 replies; 17+ messages in thread
From: Cédric Le Goater @ 2026-07-21 17:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Thanos Makatos, Cédric Le Goater
From: Thanos Makatos <thanos.makatos@nutanix.com>
This isn't in practise a problem since irq->argsz is not
externally provided, it's a good hardening step nonetheless.
Fixes: ca1add1696 ("vfio-user: implement VFIO_USER_DEVICE_GET/SET_IRQ*")
Signed-off-by: Thanos Makatos <thanos.makatos@nutanix.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20260721122643.30985-9-thanos.makatos@nutanix.com
Signed-off-by: Cédric Le Goater <clg@redhat.com>
---
hw/vfio-user/device.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/hw/vfio-user/device.c b/hw/vfio-user/device.c
index 8feaa568750ed1978dbc273da2054c89ad3bcc96..daac0e21b6b8fd5f91e3bb52044871b18021d337 100644
--- a/hw/vfio-user/device.c
+++ b/hw/vfio-user/device.c
@@ -293,7 +293,10 @@ static int vfio_user_device_io_set_irqs(VFIODevice *vbasedev,
* Handle simple case
*/
if ((irq->flags & VFIO_IRQ_SET_DATA_EVENTFD) == 0) {
- size = sizeof(VFIOUserHdr) + irq->argsz;
+ if (__builtin_add_overflow(irq->argsz, sizeof(VFIOUserHdr), &size)) {
+ error_printf("vfio_user_set_irqs argsz too large\n");
+ return -E2BIG;
+ }
msgp = g_malloc0(size);
vfio_user_request_msg(&msgp->hdr, VFIO_USER_DEVICE_SET_IRQS, size, 0);
--
2.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PULL 13/13] vfio-user: vfio_user_device_io_set_irqs: prevent excessive malloc
2026-07-21 17:05 [PULL 00/13] vfio queue Cédric Le Goater
` (11 preceding siblings ...)
2026-07-21 17:05 ` [PULL 12/13] vfio-user: vfio_user_device_io_set_irqs: prevent buffer overflow Cédric Le Goater
@ 2026-07-21 17:05 ` Cédric Le Goater
2026-07-22 17:58 ` [PULL 00/13] vfio queue Stefan Hajnoczi
13 siblings, 0 replies; 17+ messages in thread
From: Cédric Le Goater @ 2026-07-21 17:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Thanos Makatos, Cédric Le Goater
From: Thanos Makatos <thanos.makatos@nutanix.com>
This isn't in practise a problem since irq->argsz is not externally
provided, it's a good hardening step nonetheless.
Fixes: ca1add1696 ("vfio-user: implement VFIO_USER_DEVICE_GET/SET_IRQ*")
Signed-off-by: Thanos Makatos <thanos.makatos@nutanix.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20260721122643.30985-10-thanos.makatos@nutanix.com
Signed-off-by: Cédric Le Goater <clg@redhat.com>
---
hw/vfio-user/device.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/hw/vfio-user/device.c b/hw/vfio-user/device.c
index daac0e21b6b8fd5f91e3bb52044871b18021d337..1a01e748cd43311cea65c749288fc2003064db09 100644
--- a/hw/vfio-user/device.c
+++ b/hw/vfio-user/device.c
@@ -297,6 +297,11 @@ static int vfio_user_device_io_set_irqs(VFIODevice *vbasedev,
error_printf("vfio_user_set_irqs argsz too large\n");
return -E2BIG;
}
+ if (size > proxy->max_xfer_size) {
+ error_printf("vfio_user_device_io_set_irqs argsz too large\n");
+ return -E2BIG;
+ }
+
msgp = g_malloc0(size);
vfio_user_request_msg(&msgp->hdr, VFIO_USER_DEVICE_SET_IRQS, size, 0);
--
2.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PULL 00/13] vfio queue
2026-07-21 17:05 [PULL 00/13] vfio queue Cédric Le Goater
` (12 preceding siblings ...)
2026-07-21 17:05 ` [PULL 13/13] vfio-user: vfio_user_device_io_set_irqs: prevent excessive malloc Cédric Le Goater
@ 2026-07-22 17:58 ` Stefan Hajnoczi
13 siblings, 0 replies; 17+ messages in thread
From: Stefan Hajnoczi @ 2026-07-22 17:58 UTC (permalink / raw)
To: Cédric Le Goater; +Cc: qemu-devel, Cédric Le Goater
[-- Attachment #1: Type: text/plain, Size: 116 bytes --]
Applied, thanks.
Please update the changelog at https://wiki.qemu.org/ChangeLog/11.1 for any user-visible changes.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 484 bytes --]
^ permalink raw reply [flat|nested] 17+ messages in thread