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>
Paolo Bonzini committed
Aug 26, 2026 at 20:02 UTC
d61c8a6fb7388486353aa267ba0d75b098f16662
1 file changed
+15
-1
hw/i386/vapic.c
+15
-1
@@ -34,6 +34,10 @@
34
#define ROM_BLOCK_SIZE 512
35
#define ROM_BLOCK_MASK (~(ROM_BLOCK_SIZE - 1))
36
37
+/* Option ROM window on PC/Q35 machines; the vapic ROM must live in here. */
38
+#define OPTION_ROM_START 0xc0000
39
+#define OPTION_ROM_END 0xe0000
40
+
41
typedef enum VAPICMode {
42
VAPIC_INACTIVE = 0,
43
VAPIC_ACTIVE = 1,
@@ -592,6 +596,14 @@ static int vapic_map_rom_writable(VAPICROMState *s)
596
size_t rom_size;
597
uint8_t *ram;
598
599
+ /*
600
+ * The VAPIC region should be mapped in place, refuse mapping it
601
+ * outside of the option ROM window.
602
+ */
603
+ if (rom_paddr < OPTION_ROM_START || rom_paddr >= OPTION_ROM_END) {
604
+ return -1;
605
+ }
606
+
607
if (s->rom_mapped_writable) {
608
memory_region_del_subregion(mr, &s->rom);
609
object_unparent(OBJECT(&s->rom));
@@ -606,9 +618,10 @@ static int vapic_map_rom_writable(VAPICROMState *s)
618
}
619
ram = memory_region_get_ram_ptr(section.mr);
620
rom_size = ram[rom_paddr + 2] * ROM_BLOCK_SIZE;
609
- if (rom_size == 0) {
621
+ if (rom_size == 0 || rom_size > OPTION_ROM_END - rom_paddr) {
622
return -1;
623
}
624
+
625
s->rom_size = rom_size;
626
627
/* We need to round to avoid creating subpages
@@ -616,6 +629,7 @@ static int vapic_map_rom_writable(VAPICROMState *s)
629
rom_size += rom_paddr & ~TARGET_PAGE_MASK;
630
rom_paddr &= TARGET_PAGE_MASK;
631
rom_size = TARGET_PAGE_ALIGN(rom_size);
632
+ assert(rom_paddr >= OPTION_ROM_START && rom_paddr + rom_size <= OPTION_ROM_END);
633
634
memory_region_init_alias(&s->rom, OBJECT(s), "kvmvapic-rom", section.mr,
635
rom_paddr, rom_size);