9ae3a8
From 3d842d39e26560dfb7679d88746c314a3545ca18 Mon Sep 17 00:00:00 2001
9ae3a8
From: Gerd Hoffmann <kraxel@redhat.com>
9ae3a8
Date: Wed, 22 Feb 2017 12:36:24 +0100
9ae3a8
Subject: [PATCH 06/24] ui/vnc: fix potential memory corruption issues
9ae3a8
MIME-Version: 1.0
9ae3a8
Content-Type: text/plain; charset=UTF-8
9ae3a8
Content-Transfer-Encoding: 8bit
9ae3a8
9ae3a8
RH-Author: Gerd Hoffmann <kraxel@redhat.com>
9ae3a8
Message-id: <1487766986-6329-7-git-send-email-kraxel@redhat.com>
9ae3a8
Patchwork-id: 73977
9ae3a8
O-Subject: [RHEL-7.4 qemu-kvm PATCH 6/8] ui/vnc: fix potential memory corruption issues
9ae3a8
Bugzilla: 1377977
9ae3a8
RH-Acked-by: Thomas Huth <thuth@redhat.com>
9ae3a8
RH-Acked-by: Marc-André Lureau <mlureau@redhat.com>
9ae3a8
RH-Acked-by: Laurent Vivier <lvivier@redhat.com>
9ae3a8
9ae3a8
From: Peter Lieven <pl@kamp.de>
9ae3a8
9ae3a8
this patch makes the VNC server work correctly if the
9ae3a8
server surface and the guest surface have different sizes.
9ae3a8
9ae3a8
Basically the server surface is adjusted to not exceed VNC_MAX_WIDTH
9ae3a8
x VNC_MAX_HEIGHT and additionally the width is rounded up to multiple of
9ae3a8
VNC_DIRTY_PIXELS_PER_BIT.
9ae3a8
9ae3a8
If we have a resolution whose width is not dividable by VNC_DIRTY_PIXELS_PER_BIT
9ae3a8
we now get a small black bar on the right of the screen.
9ae3a8
9ae3a8
If the surface is too big to fit the limits only the upper left area is shown.
9ae3a8
9ae3a8
On top of that this fixes 2 memory corruption issues:
9ae3a8
9ae3a8
The first was actually discovered during playing
9ae3a8
around with a Windows 7 vServer. During resolution
9ae3a8
change in Windows 7 it happens sometimes that Windows
9ae3a8
changes to an intermediate resolution where
9ae3a8
server_stride % cmp_bytes != 0 (in vnc_refresh_server_surface).
9ae3a8
This happens only if width % VNC_DIRTY_PIXELS_PER_BIT != 0.
9ae3a8
9ae3a8
The second is a theoretical issue, but is maybe exploitable
9ae3a8
by the guest. If for some reason the guest surface size is bigger
9ae3a8
than VNC_MAX_WIDTH x VNC_MAX_HEIGHT we end up in severe corruption since
9ae3a8
this limit is nowhere enforced.
9ae3a8
9ae3a8
Signed-off-by: Peter Lieven <pl@kamp.de>
9ae3a8
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
9ae3a8
(cherry picked from commit bea60dd7679364493a0d7f5b54316c767cf894ef)
9ae3a8
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
9ae3a8
Conflicts:
9ae3a8
	ui/vnc.c  [ in pointer_event, input subsystem differences ]
9ae3a8
---
9ae3a8
 ui/vnc.c | 149 +++++++++++++++++++++++++++++----------------------------------
9ae3a8
 ui/vnc.h |  14 +++---
9ae3a8
 2 files changed, 77 insertions(+), 86 deletions(-)
9ae3a8
9ae3a8
diff --git a/ui/vnc.c b/ui/vnc.c
9ae3a8
index 51f95be..80b7792 100644
9ae3a8
--- a/ui/vnc.c
9ae3a8
+++ b/ui/vnc.c
9ae3a8
@@ -427,14 +427,10 @@ static void framebuffer_update_request(VncState *vs, int incremental,
9ae3a8
 static void vnc_refresh(DisplayChangeListener *dcl);
9ae3a8
 static int vnc_refresh_server_surface(VncDisplay *vd);
9ae3a8
 
9ae3a8
-static void vnc_dpy_update(DisplayChangeListener *dcl,
9ae3a8
-                           int x, int y, int w, int h)
9ae3a8
-{
9ae3a8
-    VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
9ae3a8
-    struct VncSurface *s = &vd->guest;
9ae3a8
-    int width = surface_width(vd->ds);
9ae3a8
-    int height = surface_height(vd->ds);
9ae3a8
-
9ae3a8
+static void vnc_set_area_dirty(DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT],
9ae3a8
+                               VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT),
9ae3a8
+                               int width, int height,
9ae3a8
+                               int x, int y, int w, int h) {
9ae3a8
     /* this is needed this to ensure we updated all affected
9ae3a8
      * blocks if x % VNC_DIRTY_PIXELS_PER_BIT != 0 */
9ae3a8
     w += (x % VNC_DIRTY_PIXELS_PER_BIT);
9ae3a8
@@ -446,11 +442,22 @@ static void vnc_dpy_update(DisplayChangeListener *dcl,
9ae3a8
     h = MIN(y + h, height);
9ae3a8
 
9ae3a8
     for (; y < h; y++) {
9ae3a8
-        bitmap_set(s->dirty[y], x / VNC_DIRTY_PIXELS_PER_BIT,
9ae3a8
+        bitmap_set(dirty[y], x / VNC_DIRTY_PIXELS_PER_BIT,
9ae3a8
                    DIV_ROUND_UP(w, VNC_DIRTY_PIXELS_PER_BIT));
9ae3a8
     }
9ae3a8
 }
9ae3a8
 
9ae3a8
+static void vnc_dpy_update(DisplayChangeListener *dcl,
9ae3a8
+                           int x, int y, int w, int h)
9ae3a8
+{
9ae3a8
+    VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
9ae3a8
+    struct VncSurface *s = &vd->guest;
9ae3a8
+    int width = pixman_image_get_width(vd->server);
9ae3a8
+    int height = pixman_image_get_height(vd->server);
9ae3a8
+
9ae3a8
+    vnc_set_area_dirty(s->dirty, width, height, x, y, w, h);
9ae3a8
+}
9ae3a8
+
9ae3a8
 void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
9ae3a8
                             int32_t encoding)
9ae3a8
 {
9ae3a8
@@ -512,17 +519,15 @@ void buffer_advance(Buffer *buf, size_t len)
9ae3a8
 
9ae3a8
 static void vnc_desktop_resize(VncState *vs)
9ae3a8
 {
9ae3a8
-    DisplaySurface *ds = vs->vd->ds;
9ae3a8
-
9ae3a8
     if (vs->csock == -1 || !vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
9ae3a8
         return;
9ae3a8
     }
9ae3a8
-    if (vs->client_width == surface_width(ds) &&
9ae3a8
-        vs->client_height == surface_height(ds)) {
9ae3a8
+    if (vs->client_width == pixman_image_get_width(vs->vd->server) &&
9ae3a8
+        vs->client_height == pixman_image_get_height(vs->vd->server)) {
9ae3a8
         return;
9ae3a8
     }
9ae3a8
-    vs->client_width = surface_width(ds);
9ae3a8
-    vs->client_height = surface_height(ds);
9ae3a8
+    vs->client_width = pixman_image_get_width(vs->vd->server);
9ae3a8
+    vs->client_height = pixman_image_get_height(vs->vd->server);
9ae3a8
     vnc_lock_output(vs);
9ae3a8
     vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
9ae3a8
     vnc_write_u8(vs, 0);
9ae3a8
@@ -566,31 +571,24 @@ void *vnc_server_fb_ptr(VncDisplay *vd, int x, int y)
9ae3a8
     ptr += x * VNC_SERVER_FB_BYTES;
9ae3a8
     return ptr;
9ae3a8
 }
9ae3a8
-/* this sets only the visible pixels of a dirty bitmap */
9ae3a8
-#define VNC_SET_VISIBLE_PIXELS_DIRTY(bitmap, w, h) {\
9ae3a8
-        int y;\
9ae3a8
-        memset(bitmap, 0x00, sizeof(bitmap));\
9ae3a8
-        for (y = 0; y < h; y++) {\
9ae3a8
-            bitmap_set(bitmap[y], 0,\
9ae3a8
-                       DIV_ROUND_UP(w, VNC_DIRTY_PIXELS_PER_BIT));\
9ae3a8
-        } \
9ae3a8
-    }
9ae3a8
 
9ae3a8
 static void vnc_dpy_switch(DisplayChangeListener *dcl,
9ae3a8
                            DisplaySurface *surface)
9ae3a8
 {
9ae3a8
     VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
9ae3a8
     VncState *vs;
9ae3a8
+    int width, height;
9ae3a8
 
9ae3a8
     vnc_abort_display_jobs(vd);
9ae3a8
 
9ae3a8
     /* server surface */
9ae3a8
     qemu_pixman_image_unref(vd->server);
9ae3a8
     vd->ds = surface;
9ae3a8
+    width = MIN(VNC_MAX_WIDTH, ROUND_UP(surface_width(vd->ds),
9ae3a8
+                                        VNC_DIRTY_PIXELS_PER_BIT));
9ae3a8
+    height = MIN(VNC_MAX_HEIGHT, surface_height(vd->ds));
9ae3a8
     vd->server = pixman_image_create_bits(VNC_SERVER_FB_FORMAT,
9ae3a8
-                                          surface_width(vd->ds),
9ae3a8
-                                          surface_height(vd->ds),
9ae3a8
-                                          NULL, 0);
9ae3a8
+                                          width, height, NULL, 0);
9ae3a8
 
9ae3a8
     /* guest surface */
9ae3a8
 #if 0 /* FIXME */
9ae3a8
@@ -600,9 +598,9 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl,
9ae3a8
     qemu_pixman_image_unref(vd->guest.fb);
9ae3a8
     vd->guest.fb = pixman_image_ref(surface->image);
9ae3a8
     vd->guest.format = surface->format;
9ae3a8
-    VNC_SET_VISIBLE_PIXELS_DIRTY(vd->guest.dirty,
9ae3a8
-                                 surface_width(vd->ds),
9ae3a8
-                                 surface_height(vd->ds));
9ae3a8
+    memset(vd->guest.dirty, 0x00, sizeof(vd->guest.dirty));
9ae3a8
+    vnc_set_area_dirty(vd->guest.dirty, width, height, 0, 0,
9ae3a8
+                       width, height);
9ae3a8
 
9ae3a8
     QTAILQ_FOREACH(vs, &vd->clients, next) {
9ae3a8
         vnc_colordepth(vs);
9ae3a8
@@ -610,9 +608,9 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl,
9ae3a8
         if (vs->vd->cursor) {
9ae3a8
             vnc_cursor_define(vs);
9ae3a8
         }
9ae3a8
-        VNC_SET_VISIBLE_PIXELS_DIRTY(vs->dirty,
9ae3a8
-                                     surface_width(vd->ds),
9ae3a8
-                                     surface_height(vd->ds));
9ae3a8
+        memset(vs->dirty, 0x00, sizeof(vs->dirty));
9ae3a8
+        vnc_set_area_dirty(vs->dirty, width, height, 0, 0,
9ae3a8
+                           width, height);
9ae3a8
     }
9ae3a8
 }
9ae3a8
 
9ae3a8
@@ -916,8 +914,8 @@ static int vnc_update_client(VncState *vs, int has_dirty)
9ae3a8
          */
9ae3a8
         job = vnc_job_new(vs);
9ae3a8
 
9ae3a8
-        height = MIN(pixman_image_get_height(vd->server), vs->client_height);
9ae3a8
-        width = MIN(pixman_image_get_width(vd->server), vs->client_width);
9ae3a8
+        height = pixman_image_get_height(vd->server);
9ae3a8
+        width = pixman_image_get_width(vd->server);
9ae3a8
 
9ae3a8
         y = 0;
9ae3a8
         for (;;) {
9ae3a8
@@ -1500,8 +1498,8 @@ static void check_pointer_type_change(Notifier *notifier, void *data)
9ae3a8
         vnc_write_u8(vs, 0);
9ae3a8
         vnc_write_u16(vs, 1);
9ae3a8
         vnc_framebuffer_update(vs, absolute, 0,
9ae3a8
-                               surface_width(vs->vd->ds),
9ae3a8
-                               surface_height(vs->vd->ds),
9ae3a8
+                               pixman_image_get_width(vs->vd->server),
9ae3a8
+                               pixman_image_get_height(vs->vd->server),
9ae3a8
                                VNC_ENCODING_POINTER_TYPE_CHANGE);
9ae3a8
         vnc_unlock_output(vs);
9ae3a8
         vnc_flush(vs);
9ae3a8
@@ -1513,8 +1511,8 @@ static void pointer_event(VncState *vs, int button_mask, int x, int y)
9ae3a8
 {
9ae3a8
     int buttons = 0;
9ae3a8
     int dz = 0;
9ae3a8
-    int width = surface_width(vs->vd->ds);
9ae3a8
-    int height = surface_height(vs->vd->ds);
9ae3a8
+    int width = pixman_image_get_width(vs->vd->server);
9ae3a8
+    int height = pixman_image_get_height(vs->vd->server);
9ae3a8
 
9ae3a8
     if (button_mask & 0x01)
9ae3a8
         buttons |= MOUSE_EVENT_LBUTTON;
9ae3a8
@@ -1866,29 +1864,18 @@ static void ext_key_event(VncState *vs, int down,
9ae3a8
 }
9ae3a8
 
9ae3a8
 static void framebuffer_update_request(VncState *vs, int incremental,
9ae3a8
-                                       int x_position, int y_position,
9ae3a8
-                                       int w, int h)
9ae3a8
+                                       int x, int y, int w, int h)
9ae3a8
 {
9ae3a8
-    int i;
9ae3a8
-    const size_t width = surface_width(vs->vd->ds) / VNC_DIRTY_PIXELS_PER_BIT;
9ae3a8
-    const size_t height = surface_height(vs->vd->ds);
9ae3a8
-
9ae3a8
-    if (y_position > height) {
9ae3a8
-        y_position = height;
9ae3a8
-    }
9ae3a8
-    if (y_position + h >= height) {
9ae3a8
-        h = height - y_position;
9ae3a8
-    }
9ae3a8
+    int width = pixman_image_get_width(vs->vd->server);
9ae3a8
+    int height = pixman_image_get_height(vs->vd->server);
9ae3a8
 
9ae3a8
     vs->need_update = 1;
9ae3a8
-    if (!incremental) {
9ae3a8
-        vs->force_update = 1;
9ae3a8
-        for (i = 0; i < h; i++) {
9ae3a8
-            bitmap_set(vs->dirty[y_position + i], 0, width);
9ae3a8
-            bitmap_clear(vs->dirty[y_position + i], width,
9ae3a8
-                         VNC_DIRTY_BITS - width);
9ae3a8
-        }
9ae3a8
+
9ae3a8
+    if (incremental) {
9ae3a8
+        return;
9ae3a8
     }
9ae3a8
+
9ae3a8
+    vnc_set_area_dirty(vs->dirty, width, height, x, y, w, h);
9ae3a8
 }
9ae3a8
 
9ae3a8
 static void send_ext_key_event_ack(VncState *vs)
9ae3a8
@@ -1898,8 +1885,8 @@ static void send_ext_key_event_ack(VncState *vs)
9ae3a8
     vnc_write_u8(vs, 0);
9ae3a8
     vnc_write_u16(vs, 1);
9ae3a8
     vnc_framebuffer_update(vs, 0, 0,
9ae3a8
-                           surface_width(vs->vd->ds),
9ae3a8
-                           surface_height(vs->vd->ds),
9ae3a8
+                           pixman_image_get_width(vs->vd->server),
9ae3a8
+                           pixman_image_get_height(vs->vd->server),
9ae3a8
                            VNC_ENCODING_EXT_KEY_EVENT);
9ae3a8
     vnc_unlock_output(vs);
9ae3a8
     vnc_flush(vs);
9ae3a8
@@ -1912,8 +1899,8 @@ static void send_ext_audio_ack(VncState *vs)
9ae3a8
     vnc_write_u8(vs, 0);
9ae3a8
     vnc_write_u16(vs, 1);
9ae3a8
     vnc_framebuffer_update(vs, 0, 0,
9ae3a8
-                           surface_width(vs->vd->ds),
9ae3a8
-                           surface_height(vs->vd->ds),
9ae3a8
+                           pixman_image_get_width(vs->vd->server),
9ae3a8
+                           pixman_image_get_height(vs->vd->server),
9ae3a8
                            VNC_ENCODING_AUDIO);
9ae3a8
     vnc_unlock_output(vs);
9ae3a8
     vnc_flush(vs);
9ae3a8
@@ -2101,8 +2088,8 @@ static void vnc_colordepth(VncState *vs)
9ae3a8
         vnc_write_u8(vs, 0);
9ae3a8
         vnc_write_u16(vs, 1); /* number of rects */
9ae3a8
         vnc_framebuffer_update(vs, 0, 0,
9ae3a8
-                               surface_width(vs->vd->ds),
9ae3a8
-                               surface_height(vs->vd->ds),
9ae3a8
+                               pixman_image_get_width(vs->vd->server),
9ae3a8
+                               pixman_image_get_height(vs->vd->server),
9ae3a8
                                VNC_ENCODING_WMVi);
9ae3a8
         pixel_format_message(vs);
9ae3a8
         vnc_unlock_output(vs);
9ae3a8
@@ -2317,8 +2304,8 @@ static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
9ae3a8
     }
9ae3a8
     vnc_set_share_mode(vs, mode);
9ae3a8
 
9ae3a8
-    vs->client_width = surface_width(vs->vd->ds);
9ae3a8
-    vs->client_height = surface_height(vs->vd->ds);
9ae3a8
+    vs->client_width = pixman_image_get_width(vs->vd->server);
9ae3a8
+    vs->client_height = pixman_image_get_height(vs->vd->server);
9ae3a8
     vnc_write_u16(vs, vs->client_width);
9ae3a8
     vnc_write_u16(vs, vs->client_height);
9ae3a8
 
9ae3a8
@@ -2685,12 +2672,12 @@ static void vnc_rect_updated(VncDisplay *vd, int x, int y, struct timeval * tv)
9ae3a8
 
9ae3a8
 static int vnc_refresh_server_surface(VncDisplay *vd)
9ae3a8
 {
9ae3a8
-    int width = pixman_image_get_width(vd->guest.fb);
9ae3a8
-    int height = pixman_image_get_height(vd->guest.fb);
9ae3a8
-    int y;
9ae3a8
+    int width = MIN(pixman_image_get_width(vd->guest.fb),
9ae3a8
+                    pixman_image_get_width(vd->server));
9ae3a8
+    int height = MIN(pixman_image_get_height(vd->guest.fb),
9ae3a8
+                     pixman_image_get_height(vd->server));
9ae3a8
+    int cmp_bytes, server_stride, min_stride, guest_stride, y = 0;
9ae3a8
     uint8_t *guest_row0 = NULL, *server_row0;
9ae3a8
-    int guest_stride = 0, server_stride;
9ae3a8
-    int cmp_bytes;
9ae3a8
     VncState *vs;
9ae3a8
     int has_dirty = 0;
9ae3a8
     pixman_image_t *tmpbuf = NULL;
9ae3a8
@@ -2707,10 +2694,10 @@ static int vnc_refresh_server_surface(VncDisplay *vd)
9ae3a8
      * Check and copy modified bits from guest to server surface.
9ae3a8
      * Update server dirty map.
9ae3a8
      */
9ae3a8
-    cmp_bytes = VNC_DIRTY_PIXELS_PER_BIT * VNC_SERVER_FB_BYTES;
9ae3a8
-    if (cmp_bytes > vnc_server_fb_stride(vd)) {
9ae3a8
-        cmp_bytes = vnc_server_fb_stride(vd);
9ae3a8
-    }
9ae3a8
+    server_row0 = (uint8_t *)pixman_image_get_data(vd->server);
9ae3a8
+    server_stride = guest_stride = pixman_image_get_stride(vd->server);
9ae3a8
+    cmp_bytes = MIN(VNC_DIRTY_PIXELS_PER_BIT * VNC_SERVER_FB_BYTES,
9ae3a8
+                    server_stride);
9ae3a8
     if (vd->guest.format != VNC_SERVER_FB_FORMAT) {
9ae3a8
         int width = pixman_image_get_width(vd->server);
9ae3a8
         tmpbuf = qemu_pixman_linebuf_create(VNC_SERVER_FB_FORMAT, width);
9ae3a8
@@ -2718,10 +2705,8 @@ static int vnc_refresh_server_surface(VncDisplay *vd)
9ae3a8
         guest_row0 = (uint8_t *)pixman_image_get_data(vd->guest.fb);
9ae3a8
         guest_stride = pixman_image_get_stride(vd->guest.fb);
9ae3a8
     }
9ae3a8
-    server_row0 = (uint8_t *)pixman_image_get_data(vd->server);
9ae3a8
-    server_stride = pixman_image_get_stride(vd->server);
9ae3a8
+    min_stride = MIN(server_stride, guest_stride);
9ae3a8
 
9ae3a8
-    y = 0;
9ae3a8
     for (;;) {
9ae3a8
         int x;
9ae3a8
         uint8_t *guest_ptr, *server_ptr;
9ae3a8
@@ -2747,13 +2732,17 @@ static int vnc_refresh_server_surface(VncDisplay *vd)
9ae3a8
 
9ae3a8
         for (; x < DIV_ROUND_UP(width, VNC_DIRTY_PIXELS_PER_BIT);
9ae3a8
              x++, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
9ae3a8
+            int _cmp_bytes = cmp_bytes;
9ae3a8
             if (!test_and_clear_bit(x, vd->guest.dirty[y])) {
9ae3a8
                 continue;
9ae3a8
             }
9ae3a8
-            if (memcmp(server_ptr, guest_ptr, cmp_bytes) == 0) {
9ae3a8
+            if ((x + 1) * cmp_bytes > min_stride) {
9ae3a8
+                _cmp_bytes = min_stride - x * cmp_bytes;
9ae3a8
+            }
9ae3a8
+            if (memcmp(server_ptr, guest_ptr, _cmp_bytes) == 0) {
9ae3a8
                 continue;
9ae3a8
             }
9ae3a8
-            memcpy(server_ptr, guest_ptr, cmp_bytes);
9ae3a8
+            memcpy(server_ptr, guest_ptr, _cmp_bytes);
9ae3a8
             if (!vd->non_adaptive) {
9ae3a8
                 vnc_rect_updated(vd, x * VNC_DIRTY_PIXELS_PER_BIT,
9ae3a8
                                  y, &tv;;
9ae3a8
diff --git a/ui/vnc.h b/ui/vnc.h
9ae3a8
index ebf4bdd..8d534b6 100644
9ae3a8
--- a/ui/vnc.h
9ae3a8
+++ b/ui/vnc.h
9ae3a8
@@ -77,14 +77,15 @@ typedef void VncSendHextileTile(VncState *vs,
9ae3a8
                                 void *last_fg,
9ae3a8
                                 int *has_bg, int *has_fg);
9ae3a8
 
9ae3a8
-/* VNC_MAX_WIDTH must be a multiple of 16. */
9ae3a8
-#define VNC_MAX_WIDTH 2560
9ae3a8
-#define VNC_MAX_HEIGHT 2048
9ae3a8
-
9ae3a8
 /* VNC_DIRTY_PIXELS_PER_BIT is the number of dirty pixels represented
9ae3a8
- * by one bit in the dirty bitmap */
9ae3a8
+ * by one bit in the dirty bitmap, should be a power of 2 */
9ae3a8
 #define VNC_DIRTY_PIXELS_PER_BIT 16
9ae3a8
 
9ae3a8
+/* VNC_MAX_WIDTH must be a multiple of VNC_DIRTY_PIXELS_PER_BIT. */
9ae3a8
+
9ae3a8
+#define VNC_MAX_WIDTH ROUND_UP(2560, VNC_DIRTY_PIXELS_PER_BIT)
9ae3a8
+#define VNC_MAX_HEIGHT 2048
9ae3a8
+
9ae3a8
 /* VNC_DIRTY_BITS is the number of bits in the dirty bitmap. */
9ae3a8
 #define VNC_DIRTY_BITS (VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT)
9ae3a8
 
9ae3a8
@@ -126,7 +127,8 @@ typedef struct VncRectStat VncRectStat;
9ae3a8
 struct VncSurface
9ae3a8
 {
9ae3a8
     struct timeval last_freq_check;
9ae3a8
-    DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT], VNC_MAX_WIDTH / 16);
9ae3a8
+    DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT],
9ae3a8
+                   VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT);
9ae3a8
     VncRectStat stats[VNC_STAT_ROWS][VNC_STAT_COLS];
9ae3a8
     pixman_image_t *fb;
9ae3a8
     pixman_format_code_t format;
9ae3a8
-- 
9ae3a8
1.8.3.1
9ae3a8