@samitouri / QOSamiQemu / commits / d61c8a6fb7

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);