From 9b3c06b3a43925ba293e08b18552362e07bcf8a7 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 18 Mar 2010 17:25:30 -0300 Subject: [PATCH 04/14] spice/qxl: ring access security fix. RH-Author: Gerd Hoffmann Message-id: <1268933140-655-5-git-send-email-kraxel@redhat.com> Patchwork-id: 7898 O-Subject: [RHEL-6 kvm PATCH v3 04/14] spice/qxl: ring access security fix. Bugzilla: 568820 RH-Acked-by: Alexander Larsson RH-Acked-by: Yonit Halperin RH-Acked-by: Izik Eidus Add range checks to the ring access macros. bugzilla: #568820 -- EMBARGOED CVE-2010-0431 qemu: Insufficient guest provided pointers validation [rhel-6.0] Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 22 ++++++++++++++++------ spice-ring.h | 23 +++++++++++++++++++++-- 2 files changed, 37 insertions(+), 8 deletions(-) Signed-off-by: Eduardo Habkost --- hw/qxl.c | 22 ++++++++++++++++------ spice-ring.h | 23 +++++++++++++++++++++-- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/hw/qxl.c b/hw/qxl.c index a0d7d75..e58158f 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -281,6 +281,7 @@ static int _qxl_get_command(PCIQXLDevice *d, QXLCommand *cmd) { QXLCommandRing *ring; QXLUpdate *update; + QXLCommand *tmp_cmd; int notify; if (d->mode == QXL_MODE_VGA) { @@ -300,7 +301,8 @@ static int _qxl_get_command(PCIQXLDevice *d, QXLCommand *cmd) if (RING_IS_EMPTY(ring)) { return false; } - *cmd = *RING_CONS_ITEM(ring); + RING_CONS_ITEM(ring, tmp_cmd); + *cmd = *tmp_cmd; RING_POP(ring, notify); if (notify) { qxl_send_events(d, QXL_INTERRUPT_DISPLAY); @@ -320,6 +322,7 @@ static int _qxl_has_command(PCIQXLDevice *d) static int _qxl_get_cursor_command(PCIQXLDevice *d, QXLCommand *cmd) { QXLCursorRing *ring; + QXLCommand *tmp_cmd; int notify; if (d->mode == QXL_MODE_VGA) { @@ -330,7 +333,8 @@ static int _qxl_get_cursor_command(PCIQXLDevice *d, QXLCommand *cmd) if (RING_IS_EMPTY(ring)) { return 0; } - *cmd = *RING_CONS_ITEM(ring); + RING_CONS_ITEM(ring, tmp_cmd); + *cmd = *tmp_cmd; RING_POP(ring, notify); if (notify) { qxl_send_events(d, QXL_INTERRUPT_CURSOR); @@ -370,6 +374,7 @@ static int _qxl_req_cursor_notification(PCIQXLDevice *d) static inline void qxl_push_free_res(PCIQXLDevice *d) { QXLReleaseRing *ring = &d->ram->release_ring; + uint64_t *item; assert(d->mode != QXL_MODE_VGA); if (RING_IS_EMPTY(ring) || (d->num_free_res == QXL_FREE_BUNCH_SIZE && @@ -380,7 +385,8 @@ static inline void qxl_push_free_res(PCIQXLDevice *d) if (notify) { qxl_send_events(d, QXL_INTERRUPT_DISPLAY); } - *RING_PROD_ITEM(ring) = 0; + RING_PROD_ITEM(ring, item); + *item = 0; d->num_free_res = 0; d->last_release = NULL; } @@ -397,7 +403,7 @@ static void _qxl_release_resource(PCIQXLDevice *d, QXLReleaseInfo *release_info) return; } ring = &d->ram->release_ring; - item = RING_PROD_ITEM(ring); + RING_PROD_ITEM(ring, item); if (*item == 0) { release_info->next = 0; *item = id; @@ -515,6 +521,7 @@ static void qxl_reset_state(PCIQXLDevice *d) { QXLRam *ram = d->ram; QXLRom *rom = d->rom; + uint64_t *item; assert(RING_IS_EMPTY(&ram->cmd_ring)); assert(RING_IS_EMPTY(&ram->cursor_ring)); @@ -527,7 +534,8 @@ static void qxl_reset_state(PCIQXLDevice *d) RING_INIT(&ram->cmd_ring); RING_INIT(&ram->cursor_ring); RING_INIT(&ram->release_ring); - *RING_PROD_ITEM(&ram->release_ring) = 0; + RING_PROD_ITEM(&ram->release_ring, item); + *item = 0; d->num_free_res = 0; d->last_release = NULL; memset(&d->dirty_rect, 0, sizeof(d->dirty_rect)); @@ -709,6 +717,7 @@ static void init_qxl_ram(PCIQXLDevice *d, uint8_t *buf, uint32_t actual_ram_size { uint32_t draw_area_size; uint32_t ram_header_size; + UINT64 *item; d->ram_start = buf; @@ -722,7 +731,8 @@ static void init_qxl_ram(PCIQXLDevice *d, uint8_t *buf, uint32_t actual_ram_size RING_INIT(&d->ram->cmd_ring); RING_INIT(&d->ram->cursor_ring); RING_INIT(&d->ram->release_ring); - *RING_PROD_ITEM(&d->ram->release_ring) = 0; + RING_PROD_ITEM(&d->ram->release_ring, item); + *item = 0; if (d->id == 0) { d->shadow_rom.draw_area_offset = VGA_RAM_SIZE; diff --git a/spice-ring.h b/spice-ring.h index 0d93a08..8d76205 100644 --- a/spice-ring.h +++ b/spice-ring.h @@ -70,7 +70,17 @@ typedef struct ATTR_PACKED name { \ #define RING_IS_FULL(r) (((r)->prod - (r)->cons) == (r)->num_items) -#define RING_PROD_ITEM(r) (&(r)->items[(r)->prod & RING_INDEX_MASK(r)].el) + +#define RING_PROD_ITEM(r, ret) { \ + typeof(r) start = r; \ + typeof(r) end = r + 1; \ + UINT32 prod = (r)->prod & RING_INDEX_MASK(r); \ + typeof(&(r)->items[prod]) m_item = &(r)->items[prod]; \ + if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \ + abort(); \ + } \ + ret = &m_item->el; \ +} #define RING_PROD_WAIT(r, wait) \ if (((wait) = RING_IS_FULL(r))) { \ @@ -85,7 +95,16 @@ typedef struct ATTR_PACKED name { \ (notify) = (r)->prod == (r)->notify_on_prod; -#define RING_CONS_ITEM(r) (&(r)->items[(r)->cons & RING_INDEX_MASK(r)].el) +#define RING_CONS_ITEM(r, ret) { \ + typeof(r) start = r; \ + typeof(r) end = r + 1; \ + UINT32 cons = (r)->cons & RING_INDEX_MASK(r); \ + typeof(&(r)->items[cons]) m_item = &(r)->items[cons]; \ + if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \ + abort(); \ + } \ + ret = &m_item->el; \ +} #define RING_CONS_WAIT(r, wait) \ if (((wait) = RING_IS_EMPTY(r))) { \ -- 1.6.3.rc4.29.g8146