619821
From e543257370cce5153bbcf0085a116e6aa4a6d91b Mon Sep 17 00:00:00 2001
619821
From: Gerd Hoffmann <kraxel@redhat.com>
619821
Date: Wed, 22 Feb 2017 12:36:25 +0100
619821
Subject: [PATCH 07/24] vnc: fix memory corruption (CVE-2015-5225)
619821
MIME-Version: 1.0
619821
Content-Type: text/plain; charset=UTF-8
619821
Content-Transfer-Encoding: 8bit
619821
619821
RH-Author: Gerd Hoffmann <kraxel@redhat.com>
619821
Message-id: <1487766986-6329-8-git-send-email-kraxel@redhat.com>
619821
Patchwork-id: 73978
619821
O-Subject: [RHEL-7.4 qemu-kvm PATCH 7/8] vnc: fix memory corruption (CVE-2015-5225)
619821
Bugzilla: 1377977
619821
RH-Acked-by: Thomas Huth <thuth@redhat.com>
619821
RH-Acked-by: Marc-André Lureau <mlureau@redhat.com>
619821
RH-Acked-by: Laurent Vivier <lvivier@redhat.com>
619821
619821
The _cmp_bytes variable added by commit "bea60dd ui/vnc: fix potential
619821
memory corruption issues" can become negative.  Result is (possibly
619821
exploitable) memory corruption.  Reason for that is it uses the stride
619821
instead of bytes per scanline to apply limits.
619821
619821
For the server surface is is actually fine.  vnc creates that itself,
619821
there is never any padding and thus scanline length always equals stride.
619821
619821
For the guest surface scanline length and stride are typically identical
619821
too, but it doesn't has to be that way.  So add and use a new variable
619821
(guest_ll) for the guest scanline length.  Also rename min_stride to
619821
line_bytes to make more clear what it actually is.  Finally sprinkle
619821
in an assert() to make sure we never use a negative _cmp_bytes again.
619821
619821
Reported-by: 范祚至(库特) <zuozhi.fzz@alibaba-inc.com>
619821
Reviewed-by: P J P <ppandit@redhat.com>
619821
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
619821
(cherry picked from commit eb8934b0418b3b1d125edddc4fc334a54334a49b)
619821
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
619821
---
619821
 ui/vnc.c | 15 ++++++++++-----
619821
 1 file changed, 10 insertions(+), 5 deletions(-)
619821
619821
diff --git a/ui/vnc.c b/ui/vnc.c
619821
index 80b7792..d0ada7e 100644
619821
--- a/ui/vnc.c
619821
+++ b/ui/vnc.c
619821
@@ -2676,7 +2676,7 @@ static int vnc_refresh_server_surface(VncDisplay *vd)
619821
                     pixman_image_get_width(vd->server));
619821
     int height = MIN(pixman_image_get_height(vd->guest.fb),
619821
                      pixman_image_get_height(vd->server));
619821
-    int cmp_bytes, server_stride, min_stride, guest_stride, y = 0;
619821
+    int cmp_bytes, server_stride, line_bytes, guest_ll, guest_stride, y = 0;
619821
     uint8_t *guest_row0 = NULL, *server_row0;
619821
     VncState *vs;
619821
     int has_dirty = 0;
619821
@@ -2695,17 +2695,21 @@ static int vnc_refresh_server_surface(VncDisplay *vd)
619821
      * Update server dirty map.
619821
      */
619821
     server_row0 = (uint8_t *)pixman_image_get_data(vd->server);
619821
-    server_stride = guest_stride = pixman_image_get_stride(vd->server);
619821
+    server_stride = guest_stride = guest_ll =
619821
+        pixman_image_get_stride(vd->server);
619821
     cmp_bytes = MIN(VNC_DIRTY_PIXELS_PER_BIT * VNC_SERVER_FB_BYTES,
619821
                     server_stride);
619821
     if (vd->guest.format != VNC_SERVER_FB_FORMAT) {
619821
         int width = pixman_image_get_width(vd->server);
619821
         tmpbuf = qemu_pixman_linebuf_create(VNC_SERVER_FB_FORMAT, width);
619821
     } else {
619821
+        int guest_bpp =
619821
+            PIXMAN_FORMAT_BPP(pixman_image_get_format(vd->guest.fb));
619821
         guest_row0 = (uint8_t *)pixman_image_get_data(vd->guest.fb);
619821
         guest_stride = pixman_image_get_stride(vd->guest.fb);
619821
+        guest_ll = pixman_image_get_width(vd->guest.fb) * ((guest_bpp + 7) / 8);
619821
     }
619821
-    min_stride = MIN(server_stride, guest_stride);
619821
+    line_bytes = MIN(server_stride, guest_ll);
619821
 
619821
     for (;;) {
619821
         int x;
619821
@@ -2736,9 +2740,10 @@ static int vnc_refresh_server_surface(VncDisplay *vd)
619821
             if (!test_and_clear_bit(x, vd->guest.dirty[y])) {
619821
                 continue;
619821
             }
619821
-            if ((x + 1) * cmp_bytes > min_stride) {
619821
-                _cmp_bytes = min_stride - x * cmp_bytes;
619821
+            if ((x + 1) * cmp_bytes > line_bytes) {
619821
+                _cmp_bytes = line_bytes - x * cmp_bytes;
619821
             }
619821
+            assert(_cmp_bytes >= 0);
619821
             if (memcmp(server_ptr, guest_ptr, _cmp_bytes) == 0) {
619821
                 continue;
619821
             }
619821
-- 
619821
1.8.3.1
619821