|
| 1 | +From 6dbbf055148c6f1b7d8a3251a65bd6f3d1e1f622 Mon Sep 17 00:00:00 2001 |
| 2 | +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= < [email protected]> |
| 3 | +Date: Mon, 28 Nov 2022 21:27:40 +0100 |
| 4 | +Subject: [PATCH] hw/display/qxl: Avoid buffer overrun in qxl_phys2virt |
| 5 | + (CVE-2022-4144) |
| 6 | +MIME-Version: 1.0 |
| 7 | +Content-Type: text/plain; charset=UTF-8 |
| 8 | +Content-Transfer-Encoding: 8bit |
| 9 | + |
| 10 | +Have qxl_get_check_slot_offset() return false if the requested |
| 11 | +buffer size does not fit within the slot memory region. |
| 12 | + |
| 13 | +Similarly qxl_phys2virt() now returns NULL in such case, and |
| 14 | +qxl_dirty_one_surface() aborts. |
| 15 | + |
| 16 | +This avoids buffer overrun in the host pointer returned by |
| 17 | +memory_region_get_ram_ptr(). |
| 18 | + |
| 19 | +Fixes: CVE-2022-4144 (out-of-bounds read) |
| 20 | +Reported-by: Wenxu Yin (@awxylitol) |
| 21 | +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1336 |
| 22 | + |
| 23 | +CVE: CVE-2022-4144 |
| 24 | +Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/6dbbf055148c6f1b7d8a3251a65bd6f3d1e1f622] |
| 25 | +Comments: Deleted patch hunk in qxl.h,as it contains change |
| 26 | +in comments which is not present in current version of qemu |
| 27 | + |
| 28 | +Signed-off-by: Philippe Mathieu-Daudé < [email protected]> |
| 29 | +Signed-off-by: Stefan Hajnoczi < [email protected]> |
| 30 | + |
| 31 | +Signed-off-by: Bhabu Bindu < [email protected]> |
| 32 | +--- |
| 33 | + hw/display/qxl.c | 27 +++++++++++++++++++++++---- |
| 34 | + 1 files changed, 23 insertions(+), 4 deletions(-) |
| 35 | + |
| 36 | +diff --git a/hw/display/qxl.c b/hw/display/qxl.c |
| 37 | +index 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, |
0 commit comments