mirror of
https://github.com/qemu/qemu.git
synced 2024-11-25 03:43:37 +08:00
vga: fix banked access bounds checking (CVE-2016-3710)
vga allows banked access to video memory using the window at 0xa00000 and it supports a different access modes with different address calculations. The VBE bochs extentions support banked access too, using the VBE_DISPI_INDEX_BANK register. The code tries to take the different address calculations into account and applies different limits to VBE_DISPI_INDEX_BANK depending on the current access mode. Which is probably effective in stopping misprogramming by accident. But from a security point of view completely useless as an attacker can easily change access modes after setting the bank register. Drop the bogus check, add range checks to vga_mem_{readb,writeb} instead. Fixes: CVE-2016-3710 Reported-by: Qinghao Tang <luodalongde@gmail.com> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
parent
277abf15a6
commit
3bf1817079
@ -179,6 +179,7 @@ static void vga_update_memory_access(VGACommonState *s)
|
|||||||
size = 0x8000;
|
size = 0x8000;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
assert(offset + size <= s->vram_size);
|
||||||
memory_region_init_alias(&s->chain4_alias, memory_region_owner(&s->vram),
|
memory_region_init_alias(&s->chain4_alias, memory_region_owner(&s->vram),
|
||||||
"vga.chain4", &s->vram, offset, size);
|
"vga.chain4", &s->vram, offset, size);
|
||||||
memory_region_add_subregion_overlap(s->legacy_address_space, base,
|
memory_region_add_subregion_overlap(s->legacy_address_space, base,
|
||||||
@ -716,11 +717,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
|
|||||||
vbe_fixup_regs(s);
|
vbe_fixup_regs(s);
|
||||||
break;
|
break;
|
||||||
case VBE_DISPI_INDEX_BANK:
|
case VBE_DISPI_INDEX_BANK:
|
||||||
if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
|
val &= s->vbe_bank_mask;
|
||||||
val &= (s->vbe_bank_mask >> 2);
|
|
||||||
} else {
|
|
||||||
val &= s->vbe_bank_mask;
|
|
||||||
}
|
|
||||||
s->vbe_regs[s->vbe_index] = val;
|
s->vbe_regs[s->vbe_index] = val;
|
||||||
s->bank_offset = (val << 16);
|
s->bank_offset = (val << 16);
|
||||||
vga_update_memory_access(s);
|
vga_update_memory_access(s);
|
||||||
@ -819,13 +816,21 @@ uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr)
|
|||||||
|
|
||||||
if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
|
if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
|
||||||
/* chain 4 mode : simplest access */
|
/* chain 4 mode : simplest access */
|
||||||
|
assert(addr < s->vram_size);
|
||||||
ret = s->vram_ptr[addr];
|
ret = s->vram_ptr[addr];
|
||||||
} else if (s->gr[VGA_GFX_MODE] & 0x10) {
|
} else if (s->gr[VGA_GFX_MODE] & 0x10) {
|
||||||
/* odd/even mode (aka text mode mapping) */
|
/* odd/even mode (aka text mode mapping) */
|
||||||
plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
|
plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
|
||||||
ret = s->vram_ptr[((addr & ~1) << 1) | plane];
|
addr = ((addr & ~1) << 1) | plane;
|
||||||
|
if (addr >= s->vram_size) {
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
ret = s->vram_ptr[addr];
|
||||||
} else {
|
} else {
|
||||||
/* standard VGA latched access */
|
/* standard VGA latched access */
|
||||||
|
if (addr * sizeof(uint32_t) >= s->vram_size) {
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
s->latch = ((uint32_t *)s->vram_ptr)[addr];
|
s->latch = ((uint32_t *)s->vram_ptr)[addr];
|
||||||
|
|
||||||
if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
|
if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
|
||||||
@ -882,6 +887,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
|
|||||||
plane = addr & 3;
|
plane = addr & 3;
|
||||||
mask = (1 << plane);
|
mask = (1 << plane);
|
||||||
if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
|
if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
|
||||||
|
assert(addr < s->vram_size);
|
||||||
s->vram_ptr[addr] = val;
|
s->vram_ptr[addr] = val;
|
||||||
#ifdef DEBUG_VGA_MEM
|
#ifdef DEBUG_VGA_MEM
|
||||||
printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
|
printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
|
||||||
@ -895,6 +901,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
|
|||||||
mask = (1 << plane);
|
mask = (1 << plane);
|
||||||
if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
|
if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
|
||||||
addr = ((addr & ~1) << 1) | plane;
|
addr = ((addr & ~1) << 1) | plane;
|
||||||
|
if (addr >= s->vram_size) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
s->vram_ptr[addr] = val;
|
s->vram_ptr[addr] = val;
|
||||||
#ifdef DEBUG_VGA_MEM
|
#ifdef DEBUG_VGA_MEM
|
||||||
printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
|
printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
|
||||||
@ -968,6 +977,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
|
|||||||
mask = s->sr[VGA_SEQ_PLANE_WRITE];
|
mask = s->sr[VGA_SEQ_PLANE_WRITE];
|
||||||
s->plane_updated |= mask; /* only used to detect font change */
|
s->plane_updated |= mask; /* only used to detect font change */
|
||||||
write_mask = mask16[mask];
|
write_mask = mask16[mask];
|
||||||
|
if (addr * sizeof(uint32_t) >= s->vram_size) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
((uint32_t *)s->vram_ptr)[addr] =
|
((uint32_t *)s->vram_ptr)[addr] =
|
||||||
(((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
|
(((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
|
||||||
(val & write_mask);
|
(val & write_mask);
|
||||||
|
Loading…
Reference in New Issue
Block a user