Compare commits

...

9 Commits

Author SHA1 Message Date
Michael Roth
db51dfc1fc Update version for 2.5.1.1 release
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com
2016-05-09 11:55:58 -05:00
Michael S. Tsirkin
5b7236f725 cadence_uart: bounds check write offset
cadence_uart_init() initializes an I/O memory region of size 0x1000
bytes.  However in uart_write(), the 'offset' parameter (offset within
region) is divided by 4 and then used to index the array 'r' of size
CADENCE_UART_R_MAX which is much smaller: (0x48/4).  If 'offset>>=2'
exceeds CADENCE_UART_R_MAX, this will cause an out-of-bounds memory
write where the offset and the value are controlled by guest.

This will corrupt QEMU memory, in most situations this causes the vm to
crash.

Fix by checking the offset against the array size.

Cc: qemu-stable@nongnu.org
Reported-by: 李强 <liqiang6-s@360.cn>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Alistair Francis <alistair.francis@xilinx.com>
Message-id: 20160418100735.GA517@redhat.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 5eb0b194e9)
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2016-05-09 11:55:58 -05:00
Gerd Hoffmann
0bcdb632f8 Revert "ehci: make idt processing more robust"
This reverts commit 156a2e4dbf.

Breaks FreeBSD.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit a49923d283)
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2016-05-08 22:37:18 -05:00
Gerd Hoffmann
706bab670b ehci: apply limit to iTD/sidt descriptors
Commit "156a2e4 ehci: make idt processing more robust" tries to avoid a
DoS by the guest (create a circular iTD queue and let qemu ehci
emulation run in circles forever).  Unfortunately this has two problems:
First it misses the case of siTDs, and second it reportedly breaks
FreeBSD.

So lets go for a different approach: just count the number of iTDs and
siTDs we have seen per frame and apply a limit.  That should really
catch all cases now.

Reported-by: 杜少博 <dushaobo@360.cn>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 1ae3f2f178)
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2016-05-08 22:37:09 -05:00
Gerd Hoffmann
44b86aa32e vga: make sure vga register setup for vbe stays intact (CVE-2016-3712).
Call vbe_update_vgaregs() when the guest touches GFX, SEQ or CRT
registers, to make sure the vga registers will always have the
values needed by vbe mode.  This makes sure the sanity checks
applied by vbe_fixup_regs() are effective.

Without this guests can muck with shift_control, can turn on planar
vga modes or text mode emulation while VBE is active, making qemu
take code paths meant for CGA compatibility, but with the very
large display widths and heigts settable using VBE registers.

Which is good for one or another buffer overflow.  Not that
critical as they typically read overflows happening somewhere
in the display code.  So guests can DoS by crashing qemu with a
segfault, but it is probably not possible to break out of the VM.

Fixes: CVE-2016-3712
Reported-by: Zuozhi Fzz <zuozhi.fzz@alibaba-inc.com>
Reported-by: P J P <ppandit@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2016-05-08 20:56:43 -05:00
Gerd Hoffmann
a6e5e5dd4b vga: update vga register setup on vbe changes
Call the new vbe_update_vgaregs() function on vbe configuration
changes, to make sure vga registers are up-to-date.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2016-05-08 20:56:40 -05:00
Gerd Hoffmann
2f2f74e87c vga: factor out vga register setup
When enabling vbe mode qemu will setup a bunch of vga registers to make
sure the vga emulation operates in correct mode for a linear
framebuffer.  Move that code to a separate function so we can call it
from other places too.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2016-05-08 20:56:38 -05:00
Gerd Hoffmann
46aff2c7e9 vga: add vbe_enabled() helper
Makes code a bit easier to read.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2016-05-08 20:56:34 -05:00
Gerd Hoffmann
4f0323d26c 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>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2016-05-08 20:56:30 -05:00
4 changed files with 89 additions and 49 deletions

View File

@@ -1 +1 @@
2.5.1
2.5.1.1

View File

@@ -374,6 +374,9 @@ static void uart_write(void *opaque, hwaddr offset,
DB_PRINT(" offset:%x data:%08x\n", (unsigned)offset, (unsigned)value);
offset >>= 2;
if (offset >= CADENCE_UART_R_MAX) {
return;
}
switch (offset) {
case R_IER: /* ier (wts imr) */
s->r[R_IMR] |= value;

View File

@@ -140,6 +140,13 @@ static uint32_t expand4[256];
static uint16_t expand2[256];
static uint8_t expand4to8[16];
static void vbe_update_vgaregs(VGACommonState *s);
static inline bool vbe_enabled(VGACommonState *s)
{
return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
}
static void vga_update_memory_access(VGACommonState *s)
{
hwaddr base, offset, size;
@@ -177,6 +184,7 @@ static void vga_update_memory_access(VGACommonState *s)
size = 0x8000;
break;
}
assert(offset + size <= s->vram_size);
memory_region_init_alias(&s->chain4_alias, memory_region_owner(&s->vram),
"vga.chain4", &s->vram, offset, size);
memory_region_add_subregion_overlap(s->legacy_address_space, base,
@@ -476,6 +484,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
#endif
s->sr[s->sr_index] = val & sr_mask[s->sr_index];
vbe_update_vgaregs(s);
if (s->sr_index == VGA_SEQ_CLOCK_MODE) {
s->update_retrace_info(s);
}
@@ -507,6 +516,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
#endif
s->gr[s->gr_index] = val & gr_mask[s->gr_index];
vbe_update_vgaregs(s);
vga_update_memory_access(s);
break;
case VGA_CRT_IM:
@@ -525,10 +535,12 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
if (s->cr_index == VGA_CRTC_OVERFLOW) {
s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) |
(val & 0x10);
vbe_update_vgaregs(s);
}
return;
}
s->cr[s->cr_index] = val;
vbe_update_vgaregs(s);
switch(s->cr_index) {
case VGA_CRTC_H_TOTAL:
@@ -561,7 +573,7 @@ static void vbe_fixup_regs(VGACommonState *s)
uint16_t *r = s->vbe_regs;
uint32_t bits, linelength, maxy, offset;
if (!(r[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
if (!vbe_enabled(s)) {
/* vbe is turned off -- nothing to do */
return;
}
@@ -636,6 +648,49 @@ static void vbe_fixup_regs(VGACommonState *s)
s->vbe_start_addr = offset / 4;
}
/* we initialize the VGA graphic mode */
static void vbe_update_vgaregs(VGACommonState *s)
{
int h, shift_control;
if (!vbe_enabled(s)) {
/* vbe is turned off -- nothing to do */
return;
}
/* graphic mode + memory map 1 */
s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
VGA_GR06_GRAPHICS_MODE;
s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
/* width */
s->cr[VGA_CRTC_H_DISP] =
(s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
/* height (only meaningful if < 1024) */
h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
s->cr[VGA_CRTC_V_DISP_END] = h;
s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
((h >> 7) & 0x02) | ((h >> 3) & 0x40);
/* line compare to 1023 */
s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
shift_control = 0;
s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
} else {
shift_control = 2;
/* set chain 4 mode */
s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
/* activate all planes */
s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
}
s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
(shift_control << 5);
s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
}
static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
{
VGACommonState *s = opaque;
@@ -712,13 +767,10 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
case VBE_DISPI_INDEX_Y_OFFSET:
s->vbe_regs[s->vbe_index] = val;
vbe_fixup_regs(s);
vbe_update_vgaregs(s);
break;
case VBE_DISPI_INDEX_BANK:
if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
val &= (s->vbe_bank_mask >> 2);
} else {
val &= s->vbe_bank_mask;
}
val &= s->vbe_bank_mask;
s->vbe_regs[s->vbe_index] = val;
s->bank_offset = (val << 16);
vga_update_memory_access(s);
@@ -726,52 +778,19 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
case VBE_DISPI_INDEX_ENABLE:
if ((val & VBE_DISPI_ENABLED) &&
!(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
int h, shift_control;
s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = 0;
s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
s->vbe_regs[VBE_DISPI_INDEX_ENABLE] |= VBE_DISPI_ENABLED;
vbe_fixup_regs(s);
vbe_update_vgaregs(s);
/* clear the screen */
if (!(val & VBE_DISPI_NOCLEARMEM)) {
memset(s->vram_ptr, 0,
s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
}
/* we initialize the VGA graphic mode */
/* graphic mode + memory map 1 */
s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
VGA_GR06_GRAPHICS_MODE;
s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
/* width */
s->cr[VGA_CRTC_H_DISP] =
(s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
/* height (only meaningful if < 1024) */
h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
s->cr[VGA_CRTC_V_DISP_END] = h;
s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
((h >> 7) & 0x02) | ((h >> 3) & 0x40);
/* line compare to 1023 */
s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
shift_control = 0;
s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
} else {
shift_control = 2;
/* set chain 4 mode */
s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
/* activate all planes */
s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
}
s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
(shift_control << 5);
s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
} else {
s->bank_offset = 0;
}
@@ -817,13 +836,21 @@ uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr)
if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
/* chain 4 mode : simplest access */
assert(addr < s->vram_size);
ret = s->vram_ptr[addr];
} else if (s->gr[VGA_GFX_MODE] & 0x10) {
/* odd/even mode (aka text mode mapping) */
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 {
/* standard VGA latched access */
if (addr * sizeof(uint32_t) >= s->vram_size) {
return 0xff;
}
s->latch = ((uint32_t *)s->vram_ptr)[addr];
if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
@@ -880,6 +907,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
plane = addr & 3;
mask = (1 << plane);
if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
assert(addr < s->vram_size);
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
@@ -893,6 +921,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
mask = (1 << plane);
if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
addr = ((addr & ~1) << 1) | plane;
if (addr >= s->vram_size) {
return;
}
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
@@ -966,6 +997,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
mask = s->sr[VGA_SEQ_PLANE_WRITE];
s->plane_updated |= mask; /* only used to detect font change */
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] & ~write_mask) |
(val & write_mask);
@@ -1044,7 +1078,7 @@ static void vga_get_offsets(VGACommonState *s,
{
uint32_t start_addr, line_offset, line_compare;
if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
if (vbe_enabled(s)) {
line_offset = s->vbe_line_offset;
start_addr = s->vbe_start_addr;
line_compare = 65535;
@@ -1369,7 +1403,7 @@ static int vga_get_bpp(VGACommonState *s)
{
int ret;
if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
if (vbe_enabled(s)) {
ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
} else {
ret = 0;
@@ -1381,7 +1415,7 @@ static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
{
int width, height;
if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
if (vbe_enabled(s)) {
width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
} else {

View File

@@ -1390,7 +1390,7 @@ static int ehci_process_itd(EHCIState *ehci,
{
USBDevice *dev;
USBEndpoint *ep;
uint32_t i, len, pid, dir, devaddr, endp, xfers = 0;
uint32_t i, len, pid, dir, devaddr, endp;
uint32_t pg, off, ptr1, ptr2, max, mult;
ehci->periodic_sched_active = PERIODIC_ACTIVE;
@@ -1482,10 +1482,9 @@ static int ehci_process_itd(EHCIState *ehci,
ehci_raise_irq(ehci, USBSTS_INT);
}
itd->transact[i] &= ~ITD_XACT_ACTIVE;
xfers++;
}
}
return xfers ? 0 : -1;
return 0;
}
@@ -2004,6 +2003,7 @@ static int ehci_state_writeback(EHCIQueue *q)
static void ehci_advance_state(EHCIState *ehci, int async)
{
EHCIQueue *q = NULL;
int itd_count = 0;
int again;
do {
@@ -2028,10 +2028,12 @@ static void ehci_advance_state(EHCIState *ehci, int async)
case EST_FETCHITD:
again = ehci_state_fetchitd(ehci, async);
itd_count++;
break;
case EST_FETCHSITD:
again = ehci_state_fetchsitd(ehci, async);
itd_count++;
break;
case EST_ADVANCEQUEUE:
@@ -2080,7 +2082,8 @@ static void ehci_advance_state(EHCIState *ehci, int async)
break;
}
if (again < 0) {
if (again < 0 || itd_count > 16) {
/* TODO: notify guest (raise HSE irq?) */
fprintf(stderr, "processing error - resetting ehci HC\n");
ehci_reset(ehci);
again = 0;