97168e
From 0e6bd3911c4971f575aac7e9cd726467b52fe544 Mon Sep 17 00:00:00 2001
32790f
From: Jon Maloy <jmaloy@redhat.com>
32790f
Date: Mon, 5 Dec 2022 15:32:55 -0500
97168e
Subject: [PATCH 3/5] hw/display/qxl: Pass requested buffer size to
32790f
 qxl_phys2virt()
32790f
MIME-Version: 1.0
32790f
Content-Type: text/plain; charset=UTF-8
32790f
Content-Transfer-Encoding: 8bit
32790f
32790f
RH-Author: Jon Maloy <jmaloy@redhat.com>
97168e
RH-MergeRequest: 240: hw/display/qxl: Have qxl_log_command Return early if no log_cmd handler
97168e
RH-Bugzilla: 2148545
32790f
RH-Acked-by: Gerd Hoffmann <kraxel@redhat.com>
32790f
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
97168e
RH-Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com>
97168e
RH-Commit: [3/5] 8e362d67fe7fef9eb457cfb15d75b298fed725c3 (jmaloy/jons-qemu-kvm)
32790f
97168e
BZ: https://bugzilla.redhat.com/show_bug.cgi?id=2148545
32790f
CVE: CVE-2022-4144
32790f
Upstream: Merged
32790f
32790f
commit 8efec0ef8bbc1e75a7ebf6e325a35806ece9b39f
32790f
Author: Philippe Mathieu-Daudé <philmd@linaro.org>
32790f
Date:   Mon Nov 28 21:27:39 2022 +0100
32790f
32790f
    hw/display/qxl: Pass requested buffer size to qxl_phys2virt()
32790f
32790f
    Currently qxl_phys2virt() doesn't check for buffer overrun.
32790f
    In order to do so in the next commit, pass the buffer size
32790f
    as argument.
32790f
32790f
    For QXLCursor in qxl_render_cursor() -> qxl_cursor() we
32790f
    verify the size of the chunked data ahead, checking we can
32790f
    access 'sizeof(QXLCursor) + chunk->data_size' bytes.
32790f
    Since in the SPICE_CURSOR_TYPE_MONO case the cursor is
32790f
    assumed to fit in one chunk, no change are required.
32790f
    In SPICE_CURSOR_TYPE_ALPHA the ahead read is handled in
32790f
    qxl_unpack_chunks().
32790f
32790f
    Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
32790f
    Acked-by: Gerd Hoffmann <kraxel@redhat.com>
32790f
    Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
32790f
    Message-Id: <20221128202741.4945-4-philmd@linaro.org>
32790f
32790f
(cherry picked from commit 8efec0ef8bbc1e75a7ebf6e325a35806ece9b39f)
32790f
Signed-off-by: Jon Maloy <jmaloy@redhat.com>
32790f
---
32790f
 hw/display/qxl-logger.c | 11 ++++++++---
32790f
 hw/display/qxl-render.c | 20 ++++++++++++++++----
32790f
 hw/display/qxl.c        | 14 +++++++++-----
32790f
 hw/display/qxl.h        |  4 +++-
32790f
 4 files changed, 36 insertions(+), 13 deletions(-)
32790f
32790f
diff --git a/hw/display/qxl-logger.c b/hw/display/qxl-logger.c
32790f
index 1bcf803db6..35c38f6252 100644
32790f
--- a/hw/display/qxl-logger.c
32790f
+++ b/hw/display/qxl-logger.c
32790f
@@ -106,7 +106,7 @@ static int qxl_log_image(PCIQXLDevice *qxl, QXLPHYSICAL addr, int group_id)
32790f
     QXLImage *image;
32790f
     QXLImageDescriptor *desc;
32790f
 
32790f
-    image = qxl_phys2virt(qxl, addr, group_id);
32790f
+    image = qxl_phys2virt(qxl, addr, group_id, sizeof(QXLImage));
32790f
     if (!image) {
32790f
         return 1;
32790f
     }
32790f
@@ -214,7 +214,8 @@ int qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id)
32790f
                 cmd->u.set.position.y,
32790f
                 cmd->u.set.visible ? "yes" : "no",
32790f
                 cmd->u.set.shape);
32790f
-        cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id);
32790f
+        cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id,
32790f
+                               sizeof(QXLCursor));
32790f
         if (!cursor) {
32790f
             return 1;
32790f
         }
32790f
@@ -236,6 +237,7 @@ int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext)
32790f
 {
32790f
     bool compat = ext->flags & QXL_COMMAND_FLAG_COMPAT;
32790f
     void *data;
32790f
+    size_t datasz;
32790f
     int ret;
32790f
 
32790f
     if (!qxl->cmdlog) {
32790f
@@ -249,15 +251,18 @@ int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext)
32790f
 
32790f
     switch (ext->cmd.type) {
32790f
     case QXL_CMD_DRAW:
32790f
+        datasz = compat ? sizeof(QXLCompatDrawable) : sizeof(QXLDrawable);
32790f
         break;
32790f
     case QXL_CMD_SURFACE:
32790f
+        datasz = sizeof(QXLSurfaceCmd);
32790f
         break;
32790f
     case QXL_CMD_CURSOR:
32790f
+        datasz = sizeof(QXLCursorCmd);
32790f
         break;
32790f
     default:
32790f
         goto out;
32790f
     }
32790f
-    data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
32790f
+    data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id, datasz);
32790f
     if (!data) {
32790f
         return 1;
32790f
     }
32790f
diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c
32790f
index ca217004bf..fcfd40c3ac 100644
32790f
--- a/hw/display/qxl-render.c
32790f
+++ b/hw/display/qxl-render.c
32790f
@@ -107,7 +107,9 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
32790f
         qxl->guest_primary.resized = 0;
32790f
         qxl->guest_primary.data = qxl_phys2virt(qxl,
32790f
                                                 qxl->guest_primary.surface.mem,
32790f
-                                                MEMSLOT_GROUP_GUEST);
32790f
+                                                MEMSLOT_GROUP_GUEST,
32790f
+                                                qxl->guest_primary.abs_stride
32790f
+                                                * height);
32790f
         if (!qxl->guest_primary.data) {
32790f
             goto end;
32790f
         }
32790f
@@ -228,7 +230,8 @@ static void qxl_unpack_chunks(void *dest, size_t size, PCIQXLDevice *qxl,
32790f
         if (offset == size) {
32790f
             return;
32790f
         }
32790f
-        chunk = qxl_phys2virt(qxl, chunk->next_chunk, group_id);
32790f
+        chunk = qxl_phys2virt(qxl, chunk->next_chunk, group_id,
32790f
+                              sizeof(QXLDataChunk) + chunk->data_size);
32790f
         if (!chunk) {
32790f
             return;
32790f
         }
32790f
@@ -295,7 +298,8 @@ fail:
32790f
 /* called from spice server thread context only */
32790f
 int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
32790f
 {
32790f
-    QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
32790f
+    QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id,
32790f
+                                      sizeof(QXLCursorCmd));
32790f
     QXLCursor *cursor;
32790f
     QEMUCursor *c;
32790f
 
32790f
@@ -314,7 +318,15 @@ int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
32790f
     }
32790f
     switch (cmd->type) {
32790f
     case QXL_CURSOR_SET:
32790f
-        cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id);
32790f
+        /* First read the QXLCursor to get QXLDataChunk::data_size ... */
32790f
+        cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id,
32790f
+                               sizeof(QXLCursor));
32790f
+        if (!cursor) {
32790f
+            return 1;
32790f
+        }
32790f
+        /* Then read including the chunked data following QXLCursor. */
32790f
+        cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id,
32790f
+                               sizeof(QXLCursor) + cursor->chunk.data_size);
32790f
         if (!cursor) {
32790f
             return 1;
32790f
         }
32790f
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
32790f
index 29c80b4289..aa9065183e 100644
32790f
--- a/hw/display/qxl.c
32790f
+++ b/hw/display/qxl.c
32790f
@@ -274,7 +274,8 @@ static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay)
32790f
                                           QXL_IO_MONITORS_CONFIG_ASYNC));
32790f
     }
32790f
 
32790f
-    cfg = qxl_phys2virt(qxl, qxl->guest_monitors_config, MEMSLOT_GROUP_GUEST);
32790f
+    cfg = qxl_phys2virt(qxl, qxl->guest_monitors_config, MEMSLOT_GROUP_GUEST,
32790f
+                        sizeof(QXLMonitorsConfig));
32790f
     if (cfg != NULL && cfg->count == 1) {
32790f
         qxl->guest_primary.resized = 1;
32790f
         qxl->guest_head0_width  = cfg->heads[0].width;
32790f
@@ -459,7 +460,8 @@ static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
32790f
     switch (le32_to_cpu(ext->cmd.type)) {
32790f
     case QXL_CMD_SURFACE:
32790f
     {
32790f
-        QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
32790f
+        QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id,
32790f
+                                           sizeof(QXLSurfaceCmd));
32790f
 
32790f
         if (!cmd) {
32790f
             return 1;
32790f
@@ -494,7 +496,8 @@ static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
32790f
     }
32790f
     case QXL_CMD_CURSOR:
32790f
     {
32790f
-        QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
32790f
+        QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id,
32790f
+                                          sizeof(QXLCursorCmd));
32790f
 
32790f
         if (!cmd) {
32790f
             return 1;
32790f
@@ -1444,7 +1447,8 @@ static bool qxl_get_check_slot_offset(PCIQXLDevice *qxl, QXLPHYSICAL pqxl,
32790f
 }
32790f
 
32790f
 /* can be also called from spice server thread context */
32790f
-void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id)
32790f
+void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id,
32790f
+                    size_t size)
32790f
 {
32790f
     uint64_t offset;
32790f
     uint32_t slot;
32790f
@@ -1952,7 +1956,7 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl)
32790f
         }
32790f
 
32790f
         cmd = qxl_phys2virt(qxl, qxl->guest_surfaces.cmds[i],
32790f
-                            MEMSLOT_GROUP_GUEST);
32790f
+                            MEMSLOT_GROUP_GUEST, sizeof(QXLSurfaceCmd));
32790f
         assert(cmd);
32790f
         assert(cmd->type == QXL_SURFACE_CMD_CREATE);
32790f
         qxl_dirty_one_surface(qxl, cmd->u.surface_create.data,
32790f
diff --git a/hw/display/qxl.h b/hw/display/qxl.h
32790f
index c938f88a2f..c784315daa 100644
32790f
--- a/hw/display/qxl.h
32790f
+++ b/hw/display/qxl.h
32790f
@@ -153,6 +153,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(PCIQXLDevice, PCI_QXL)
32790f
  * @qxl: QXL device
32790f
  * @phys: physical offset of buffer within the VRAM
32790f
  * @group_id: memory slot group
32790f
+ * @size: size of the buffer
32790f
  *
32790f
  * Returns a host pointer to a buffer placed at offset @phys within the
32790f
  * active slot @group_id of the PCI VGA RAM memory region associated with
32790f
@@ -166,7 +167,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(PCIQXLDevice, PCI_QXL)
32790f
  * the incoming ram_addr_t.
32790f
  *
32790f
  */
32790f
-void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
32790f
+void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id,
32790f
+                    size_t size);
32790f
 void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...)
32790f
     GCC_FMT_ATTR(2, 3);
32790f
 
32790f
-- 
32790f
2.37.3
32790f