1From 6dbbf055148c6f1b7d8a3251a65bd6f3d1e1f622 Mon Sep 17 00:00:00 2001 2From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= <philmd@linaro.org> 3Date: Mon, 28 Nov 2022 21:27:40 +0100 4Subject: [PATCH] hw/display/qxl: Avoid buffer overrun in qxl_phys2virt 5 (CVE-2022-4144) 6MIME-Version: 1.0 7Content-Type: text/plain; charset=UTF-8 8Content-Transfer-Encoding: 8bit 9 10Have qxl_get_check_slot_offset() return false if the requested 11buffer size does not fit within the slot memory region. 12 13Similarly qxl_phys2virt() now returns NULL in such case, and 14qxl_dirty_one_surface() aborts. 15 16This avoids buffer overrun in the host pointer returned by 17memory_region_get_ram_ptr(). 18 19Fixes: CVE-2022-4144 (out-of-bounds read) 20Reported-by: Wenxu Yin (@awxylitol) 21Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1336 22 23CVE: CVE-2022-4144 24Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/6dbbf055148c6f1b7d8a3251a65bd6f3d1e1f622] 25Comments: Deleted patch hunk in qxl.h,as it contains change 26in comments which is not present in current version of qemu 27 28Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> 29Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> 30Message-Id: <20221128202741.4945-5-philmd@linaro.org> 31Signed-off-by: Bhabu Bindu <bhabu.bindu@kpit.com> 32--- 33 hw/display/qxl.c | 27 +++++++++++++++++++++++---- 34 1 files changed, 23 insertions(+), 4 deletions(-) 35 36diff --git a/hw/display/qxl.c b/hw/display/qxl.c 37index 231d733250..0b21626aad 100644 38--- a/hw/display/qxl.c 39+++ b/hw/display/qxl.c 40@@ -1424,11 +1424,13 @@ static void qxl_reset_surfaces(PCIQXLDevice *d) 41 42 /* can be also called from spice server thread context */ 43 static bool qxl_get_check_slot_offset(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, 44- uint32_t *s, uint64_t *o) 45+ uint32_t *s, uint64_t *o, 46+ size_t size_requested) 47 { 48 uint64_t phys = le64_to_cpu(pqxl); 49 uint32_t slot = (phys >> (64 - 8)) & 0xff; 50 uint64_t offset = phys & 0xffffffffffff; 51+ uint64_t size_available; 52 53 if (slot >= NUM_MEMSLOTS) { 54 qxl_set_guest_bug(qxl, "slot too large %d >= %d", slot, 55@@ -1452,6 +1454,23 @@ static bool qxl_get_check_slot_offset(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, 56 slot, offset, qxl->guest_slots[slot].size); 57 return false; 58 } 59+ size_available = memory_region_size(qxl->guest_slots[slot].mr); 60+ if (qxl->guest_slots[slot].offset + offset >= size_available) { 61+ qxl_set_guest_bug(qxl, 62+ "slot %d offset %"PRIu64" > region size %"PRIu64"\n", 63+ slot, qxl->guest_slots[slot].offset + offset, 64+ size_available); 65+ return false; 66+ } 67+ size_available -= qxl->guest_slots[slot].offset + offset; 68+ if (size_requested > size_available) { 69+ qxl_set_guest_bug(qxl, 70+ "slot %d offset %"PRIu64" size %zu: " 71+ "overrun by %"PRIu64" bytes\n", 72+ slot, offset, size_requested, 73+ size_requested - size_available); 74+ return false; 75+ } 76 77 *s = slot; 78 *o = offset; 79@@ -1471,7 +1490,7 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id, 80 offset = le64_to_cpu(pqxl) & 0xffffffffffff; 81 return (void *)(intptr_t)offset; 82 case MEMSLOT_GROUP_GUEST: 83- if (!qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset)) { 84+ if (!qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset, size)) { 85 return NULL; 86 } 87 ptr = memory_region_get_ram_ptr(qxl->guest_slots[slot].mr); 88@@ -1937,9 +1956,9 @@ static void qxl_dirty_one_surface(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, 89 uint32_t slot; 90 bool rc; 91 92- rc = qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset); 93- assert(rc == true); 94 size = (uint64_t)height * abs(stride); 95+ rc = qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset, size); 96+ assert(rc == true); 97 trace_qxl_surfaces_dirty(qxl->id, offset, size); 98 qxl_set_dirty(qxl->guest_slots[slot].mr, 99 qxl->guest_slots[slot].offset + offset, 100