From 9b3c06b3a43925ba293e08b18552362e07bcf8a7 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Thu, 18 Mar 2010 17:25:30 -0300
Subject: [PATCH 04/14] spice/qxl: ring access security fix.

RH-Author: Gerd Hoffmann <kraxel@redhat.com>
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 <alexl@redhat.com>
RH-Acked-by: Yonit Halperin <yhalperi@redhat.com>
RH-Acked-by: Izik Eidus <ieidus@redhat.com>

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 <kraxel@redhat.com>
---
 hw/qxl.c     |   22 ++++++++++++++++------
 spice-ring.h |   23 +++++++++++++++++++++--
 2 files changed, 37 insertions(+), 8 deletions(-)

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
 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

