Commit d61c8a6fb7 for qemu.org
commit d61c8a6fb7388486353aa267ba0d75b098f16662
Author: Paolo Bonzini <pbonzini@redhat.com>
Date: Wed Aug 26 20:02:56 2026 +0200
vapic: confine the VAPIC region to 0xc0000..0xe0000
The VAPIC region is mapped as writable RAM, at very high priority,
above existing memory. If the guest is allowed to map it everywhere,
it can overlap PCI BARs or even SMRAM. Ensure that the whole
region first in the 128K of low memory that are reserved to
option ROMs.
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4206
Reported-by: Artem Dinaburg <https://gitlab.com/artem35>
Cc: qemu-stable@nongnu.org
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
diff --git a/hw/i386/vapic.c b/hw/i386/vapic.c
index 8dd9188d96..9adce17262 100644
--- a/hw/i386/vapic.c
+++ b/hw/i386/vapic.c
@@ -34,6 +34,10 @@
#define ROM_BLOCK_SIZE 512
#define ROM_BLOCK_MASK (~(ROM_BLOCK_SIZE - 1))
+/* Option ROM window on PC/Q35 machines; the vapic ROM must live in here. */
+#define OPTION_ROM_START 0xc0000
+#define OPTION_ROM_END 0xe0000
+
typedef enum VAPICMode {
VAPIC_INACTIVE = 0,
VAPIC_ACTIVE = 1,
@@ -592,6 +596,14 @@ static int vapic_map_rom_writable(VAPICROMState *s)
size_t rom_size;
uint8_t *ram;
+ /*
+ * The VAPIC region should be mapped in place, refuse mapping it
+ * outside of the option ROM window.
+ */
+ if (rom_paddr < OPTION_ROM_START || rom_paddr >= OPTION_ROM_END) {
+ return -1;
+ }
+
if (s->rom_mapped_writable) {
memory_region_del_subregion(mr, &s->rom);
object_unparent(OBJECT(&s->rom));
@@ -606,9 +618,10 @@ static int vapic_map_rom_writable(VAPICROMState *s)
}
ram = memory_region_get_ram_ptr(section.mr);
rom_size = ram[rom_paddr + 2] * ROM_BLOCK_SIZE;
- if (rom_size == 0) {
+ if (rom_size == 0 || rom_size > OPTION_ROM_END - rom_paddr) {
return -1;
}
+
s->rom_size = rom_size;
/* We need to round to avoid creating subpages
@@ -616,6 +629,7 @@ static int vapic_map_rom_writable(VAPICROMState *s)
rom_size += rom_paddr & ~TARGET_PAGE_MASK;
rom_paddr &= TARGET_PAGE_MASK;
rom_size = TARGET_PAGE_ALIGN(rom_size);
+ assert(rom_paddr >= OPTION_ROM_START && rom_paddr + rom_size <= OPTION_ROM_END);
memory_region_init_alias(&s->rom, OBJECT(s), "kvmvapic-rom", section.mr,
rom_paddr, rom_size);