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> Signed-off-by: Paolo Bonzini <[email protected]> --- hw/i386/vapic.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/hw/i386/vapic.c b/hw/i386/vapic.c index 78dc2312bca..5c3911cf9c8 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)); @@ -607,10 +619,11 @@ 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) { memory_region_unref(section.mr); return -1; } + s->rom_size = rom_size; /* We need to round to avoid creating subpages @@ -618,6 +631,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); -- 2.55.0
