Blame packages/q/qemu/hw-display-qxl-Pass-requested-buffer-siz.patch

Bernhard M. Wiedemann 399b1f
From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= <philmd@linaro.org>
Bernhard M. Wiedemann 399b1f
Date: Mon, 28 Nov 2022 21:27:39 +0100
Bernhard M. Wiedemann 399b1f
Subject: hw/display/qxl: Pass requested buffer size to qxl_phys2virt()
Bernhard M. Wiedemann 399b1f
MIME-Version: 1.0
Bernhard M. Wiedemann 399b1f
Content-Type: text/plain; charset=UTF-8
Bernhard M. Wiedemann 399b1f
Content-Transfer-Encoding: 8bit
Bernhard M. Wiedemann 399b1f
Bernhard M. Wiedemann 399b1f
Currently qxl_phys2virt() doesn't check for buffer overrun.
Bernhard M. Wiedemann 399b1f
In order to do so in the next commit, pass the buffer size
Bernhard M. Wiedemann 399b1f
as argument.
Bernhard M. Wiedemann 399b1f
Bernhard M. Wiedemann 399b1f
For QXLCursor in qxl_render_cursor() -> qxl_cursor() we
Bernhard M. Wiedemann 399b1f
verify the size of the chunked data ahead, checking we can
Bernhard M. Wiedemann 399b1f
access 'sizeof(QXLCursor) + chunk->data_size' bytes.
Bernhard M. Wiedemann 399b1f
Since in the SPICE_CURSOR_TYPE_MONO case the cursor is
Bernhard M. Wiedemann 399b1f
assumed to fit in one chunk, no change are required.
Bernhard M. Wiedemann 399b1f
In SPICE_CURSOR_TYPE_ALPHA the ahead read is handled in
Bernhard M. Wiedemann 399b1f
qxl_unpack_chunks().
Bernhard M. Wiedemann 399b1f
Bernhard M. Wiedemann 399b1f
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Bernhard M. Wiedemann 399b1f
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Bernhard M. Wiedemann 399b1f
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Bernhard M. Wiedemann 399b1f
Message-Id: <20221128202741.4945-4-philmd@linaro.org>
Bernhard M. Wiedemann 399b1f
(cherry picked from commit 8efec0ef8bbc1e75a7ebf6e325a35806ece9b39f)
Bernhard M. Wiedemann 399b1f
Resolves: bsc#1205808
Bernhard M. Wiedemann 399b1f
Fixes: CVE-2022-4144
Bernhard M. Wiedemann 399b1f
Signed-off-by: Dario Faggioli <dfaggioli@suse.com>
Bernhard M. Wiedemann 399b1f
---
Bernhard M. Wiedemann 399b1f
 hw/display/qxl-logger.c | 11 ++++++++---
Bernhard M. Wiedemann 399b1f
 hw/display/qxl-render.c | 20 ++++++++++++++++----
Bernhard M. Wiedemann 399b1f
 hw/display/qxl.c        | 14 +++++++++-----
Bernhard M. Wiedemann 399b1f
 hw/display/qxl.h        |  4 +++-
Bernhard M. Wiedemann 399b1f
 4 files changed, 36 insertions(+), 13 deletions(-)
Bernhard M. Wiedemann 399b1f
Bernhard M. Wiedemann 399b1f
diff --git a/hw/display/qxl-logger.c b/hw/display/qxl-logger.c
Bernhard M. Wiedemann 399b1f
index 1bcf803db6dabe558aaf1a0df0cd..35c38f62525deb89f11fa7fda3a4 100644
Bernhard M. Wiedemann 399b1f
--- a/hw/display/qxl-logger.c
Bernhard M. Wiedemann 399b1f
+++ b/hw/display/qxl-logger.c
Bernhard M. Wiedemann 399b1f
@@ -106,7 +106,7 @@ static int qxl_log_image(PCIQXLDevice *qxl, QXLPHYSICAL addr, int group_id)
Bernhard M. Wiedemann 399b1f
     QXLImage *image;
Bernhard M. Wiedemann 399b1f
     QXLImageDescriptor *desc;
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
-    image = qxl_phys2virt(qxl, addr, group_id);
Bernhard M. Wiedemann 399b1f
+    image = qxl_phys2virt(qxl, addr, group_id, sizeof(QXLImage));
Bernhard M. Wiedemann 399b1f
     if (!image) {
Bernhard M. Wiedemann 399b1f
         return 1;
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
@@ -214,7 +214,8 @@ int qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id)
Bernhard M. Wiedemann 399b1f
                 cmd->u.set.position.y,
Bernhard M. Wiedemann 399b1f
                 cmd->u.set.visible ? "yes" : "no",
Bernhard M. Wiedemann 399b1f
                 cmd->u.set.shape);
Bernhard M. Wiedemann 399b1f
-        cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id);
Bernhard M. Wiedemann 399b1f
+        cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id,
Bernhard M. Wiedemann 399b1f
+                               sizeof(QXLCursor));
Bernhard M. Wiedemann 399b1f
         if (!cursor) {
Bernhard M. Wiedemann 399b1f
             return 1;
Bernhard M. Wiedemann 399b1f
         }
Bernhard M. Wiedemann 399b1f
@@ -236,6 +237,7 @@ int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext)
Bernhard M. Wiedemann 399b1f
 {
Bernhard M. Wiedemann 399b1f
     bool compat = ext->flags & QXL_COMMAND_FLAG_COMPAT;
Bernhard M. Wiedemann 399b1f
     void *data;
Bernhard M. Wiedemann 399b1f
+    size_t datasz;
Bernhard M. Wiedemann 399b1f
     int ret;
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
     if (!qxl->cmdlog) {
Bernhard M. Wiedemann 399b1f
@@ -249,15 +251,18 @@ int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext)
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
     switch (ext->cmd.type) {
Bernhard M. Wiedemann 399b1f
     case QXL_CMD_DRAW:
Bernhard M. Wiedemann 399b1f
+        datasz = compat ? sizeof(QXLCompatDrawable) : sizeof(QXLDrawable);
Bernhard M. Wiedemann 399b1f
         break;
Bernhard M. Wiedemann 399b1f
     case QXL_CMD_SURFACE:
Bernhard M. Wiedemann 399b1f
+        datasz = sizeof(QXLSurfaceCmd);
Bernhard M. Wiedemann 399b1f
         break;
Bernhard M. Wiedemann 399b1f
     case QXL_CMD_CURSOR:
Bernhard M. Wiedemann 399b1f
+        datasz = sizeof(QXLCursorCmd);
Bernhard M. Wiedemann 399b1f
         break;
Bernhard M. Wiedemann 399b1f
     default:
Bernhard M. Wiedemann 399b1f
         goto out;
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
-    data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
Bernhard M. Wiedemann 399b1f
+    data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id, datasz);
Bernhard M. Wiedemann 399b1f
     if (!data) {
Bernhard M. Wiedemann 399b1f
         return 1;
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c
Bernhard M. Wiedemann 399b1f
index ca217004bf72e7d394ed7ee9c948..fcfd40c3ac1d622b6d27279e25be 100644
Bernhard M. Wiedemann 399b1f
--- a/hw/display/qxl-render.c
Bernhard M. Wiedemann 399b1f
+++ b/hw/display/qxl-render.c
Bernhard M. Wiedemann 399b1f
@@ -107,7 +107,9 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
Bernhard M. Wiedemann 399b1f
         qxl->guest_primary.resized = 0;
Bernhard M. Wiedemann 399b1f
         qxl->guest_primary.data = qxl_phys2virt(qxl,
Bernhard M. Wiedemann 399b1f
                                                 qxl->guest_primary.surface.mem,
Bernhard M. Wiedemann 399b1f
-                                                MEMSLOT_GROUP_GUEST);
Bernhard M. Wiedemann 399b1f
+                                                MEMSLOT_GROUP_GUEST,
Bernhard M. Wiedemann 399b1f
+                                                qxl->guest_primary.abs_stride
Bernhard M. Wiedemann 399b1f
+                                                * height);
Bernhard M. Wiedemann 399b1f
         if (!qxl->guest_primary.data) {
Bernhard M. Wiedemann 399b1f
             goto end;
Bernhard M. Wiedemann 399b1f
         }
Bernhard M. Wiedemann 399b1f
@@ -228,7 +230,8 @@ static void qxl_unpack_chunks(void *dest, size_t size, PCIQXLDevice *qxl,
Bernhard M. Wiedemann 399b1f
         if (offset == size) {
Bernhard M. Wiedemann 399b1f
             return;
Bernhard M. Wiedemann 399b1f
         }
Bernhard M. Wiedemann 399b1f
-        chunk = qxl_phys2virt(qxl, chunk->next_chunk, group_id);
Bernhard M. Wiedemann 399b1f
+        chunk = qxl_phys2virt(qxl, chunk->next_chunk, group_id,
Bernhard M. Wiedemann 399b1f
+                              sizeof(QXLDataChunk) + chunk->data_size);
Bernhard M. Wiedemann 399b1f
         if (!chunk) {
Bernhard M. Wiedemann 399b1f
             return;
Bernhard M. Wiedemann 399b1f
         }
Bernhard M. Wiedemann 399b1f
@@ -295,7 +298,8 @@ fail:
Bernhard M. Wiedemann 399b1f
 /* called from spice server thread context only */
Bernhard M. Wiedemann 399b1f
 int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
Bernhard M. Wiedemann 399b1f
 {
Bernhard M. Wiedemann 399b1f
-    QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
Bernhard M. Wiedemann 399b1f
+    QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id,
Bernhard M. Wiedemann 399b1f
+                                      sizeof(QXLCursorCmd));
Bernhard M. Wiedemann 399b1f
     QXLCursor *cursor;
Bernhard M. Wiedemann 399b1f
     QEMUCursor *c;
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
@@ -314,7 +318,15 @@ int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
     switch (cmd->type) {
Bernhard M. Wiedemann 399b1f
     case QXL_CURSOR_SET:
Bernhard M. Wiedemann 399b1f
-        cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id);
Bernhard M. Wiedemann 399b1f
+        /* First read the QXLCursor to get QXLDataChunk::data_size ... */
Bernhard M. Wiedemann 399b1f
+        cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id,
Bernhard M. Wiedemann 399b1f
+                               sizeof(QXLCursor));
Bernhard M. Wiedemann 399b1f
+        if (!cursor) {
Bernhard M. Wiedemann 399b1f
+            return 1;
Bernhard M. Wiedemann 399b1f
+        }
Bernhard M. Wiedemann 399b1f
+        /* Then read including the chunked data following QXLCursor. */
Bernhard M. Wiedemann 399b1f
+        cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id,
Bernhard M. Wiedemann 399b1f
+                               sizeof(QXLCursor) + cursor->chunk.data_size);
Bernhard M. Wiedemann 399b1f
         if (!cursor) {
Bernhard M. Wiedemann 399b1f
             return 1;
Bernhard M. Wiedemann 399b1f
         }
Bernhard M. Wiedemann 399b1f
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
Bernhard M. Wiedemann 399b1f
index 5b10f697f1872751730114b73331..231d733250032a8ad93a1caa507d 100644
Bernhard M. Wiedemann 399b1f
--- a/hw/display/qxl.c
Bernhard M. Wiedemann 399b1f
+++ b/hw/display/qxl.c
Bernhard M. Wiedemann 399b1f
@@ -274,7 +274,8 @@ static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay)
Bernhard M. Wiedemann 399b1f
                                           QXL_IO_MONITORS_CONFIG_ASYNC));
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
-    cfg = qxl_phys2virt(qxl, qxl->guest_monitors_config, MEMSLOT_GROUP_GUEST);
Bernhard M. Wiedemann 399b1f
+    cfg = qxl_phys2virt(qxl, qxl->guest_monitors_config, MEMSLOT_GROUP_GUEST,
Bernhard M. Wiedemann 399b1f
+                        sizeof(QXLMonitorsConfig));
Bernhard M. Wiedemann 399b1f
     if (cfg != NULL && cfg->count == 1) {
Bernhard M. Wiedemann 399b1f
         qxl->guest_primary.resized = 1;
Bernhard M. Wiedemann 399b1f
         qxl->guest_head0_width  = cfg->heads[0].width;
Bernhard M. Wiedemann 399b1f
@@ -459,7 +460,8 @@ static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
Bernhard M. Wiedemann 399b1f
     switch (le32_to_cpu(ext->cmd.type)) {
Bernhard M. Wiedemann 399b1f
     case QXL_CMD_SURFACE:
Bernhard M. Wiedemann 399b1f
     {
Bernhard M. Wiedemann 399b1f
-        QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
Bernhard M. Wiedemann 399b1f
+        QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id,
Bernhard M. Wiedemann 399b1f
+                                           sizeof(QXLSurfaceCmd));
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
         if (!cmd) {
Bernhard M. Wiedemann 399b1f
             return 1;
Bernhard M. Wiedemann 399b1f
@@ -494,7 +496,8 @@ static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
     case QXL_CMD_CURSOR:
Bernhard M. Wiedemann 399b1f
     {
Bernhard M. Wiedemann 399b1f
-        QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
Bernhard M. Wiedemann 399b1f
+        QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id,
Bernhard M. Wiedemann 399b1f
+                                          sizeof(QXLCursorCmd));
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
         if (!cmd) {
Bernhard M. Wiedemann 399b1f
             return 1;
Bernhard M. Wiedemann 399b1f
@@ -1456,7 +1459,8 @@ static bool qxl_get_check_slot_offset(PCIQXLDevice *qxl, QXLPHYSICAL pqxl,
Bernhard M. Wiedemann 399b1f
 }
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
 /* can be also called from spice server thread context */
Bernhard M. Wiedemann 399b1f
-void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id)
Bernhard M. Wiedemann 399b1f
+void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id,
Bernhard M. Wiedemann 399b1f
+                    size_t size)
Bernhard M. Wiedemann 399b1f
 {
Bernhard M. Wiedemann 399b1f
     uint64_t offset;
Bernhard M. Wiedemann 399b1f
     uint32_t slot;
Bernhard M. Wiedemann 399b1f
@@ -1964,7 +1968,7 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl)
Bernhard M. Wiedemann 399b1f
         }
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
         cmd = qxl_phys2virt(qxl, qxl->guest_surfaces.cmds[i],
Bernhard M. Wiedemann 399b1f
-                            MEMSLOT_GROUP_GUEST);
Bernhard M. Wiedemann 399b1f
+                            MEMSLOT_GROUP_GUEST, sizeof(QXLSurfaceCmd));
Bernhard M. Wiedemann 399b1f
         assert(cmd);
Bernhard M. Wiedemann 399b1f
         assert(cmd->type == QXL_SURFACE_CMD_CREATE);
Bernhard M. Wiedemann 399b1f
         qxl_dirty_one_surface(qxl, cmd->u.surface_create.data,
Bernhard M. Wiedemann 399b1f
diff --git a/hw/display/qxl.h b/hw/display/qxl.h
Bernhard M. Wiedemann 399b1f
index 78b3a6c9ba8e3a598d6553867a6c..bf03138ab477a2adc7bf23f4e662 100644
Bernhard M. Wiedemann 399b1f
--- a/hw/display/qxl.h
Bernhard M. Wiedemann 399b1f
+++ b/hw/display/qxl.h
Bernhard M. Wiedemann 399b1f
@@ -153,6 +153,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(PCIQXLDevice, PCI_QXL)
Bernhard M. Wiedemann 399b1f
  * @qxl: QXL device
Bernhard M. Wiedemann 399b1f
  * @phys: physical offset of buffer within the VRAM
Bernhard M. Wiedemann 399b1f
  * @group_id: memory slot group
Bernhard M. Wiedemann 399b1f
+ * @size: size of the buffer
Bernhard M. Wiedemann 399b1f
  *
Bernhard M. Wiedemann 399b1f
  * Returns a host pointer to a buffer placed at offset @phys within the
Bernhard M. Wiedemann 399b1f
  * active slot @group_id of the PCI VGA RAM memory region associated with
Bernhard M. Wiedemann 399b1f
@@ -166,7 +167,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(PCIQXLDevice, PCI_QXL)
Bernhard M. Wiedemann 399b1f
  * the incoming ram_addr_t.
Bernhard M. Wiedemann 399b1f
  *
Bernhard M. Wiedemann 399b1f
  */
Bernhard M. Wiedemann 399b1f
-void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
Bernhard M. Wiedemann 399b1f
+void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id,
Bernhard M. Wiedemann 399b1f
+                    size_t size);
Bernhard M. Wiedemann 399b1f
 void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...)
Bernhard M. Wiedemann 399b1f
     G_GNUC_PRINTF(2, 3);
Bernhard M. Wiedemann 399b1f