mvadkert / rpms / qemu

Forked from rpms/qemu 6 years ago
Clone
3d039dc
From: Gerd Hoffmann <kraxel@redhat.com>
3d039dc
Date: Tue, 14 Mar 2017 13:26:59 +0100
3d039dc
Subject: [PATCH] cirrus/vnc: zap bitblit support from console code.
3d039dc
3d039dc
There is a special code path (dpy_gfx_copy) to allow graphic emulation
3d039dc
notify user interface code about bitblit operations carryed out by
3d039dc
guests.  It is supported by cirrus and vnc server.  The intended purpose
3d039dc
is to optimize display scrolls and just send over the scroll op instead
3d039dc
of a full display update.
3d039dc
3d039dc
This is rarely used these days though because modern guests simply don't
3d039dc
use the cirrus blitter any more.  Any linux guest using the cirrus drm
3d039dc
driver doesn't.  Any windows guest newer than winxp doesn't ship with a
3d039dc
cirrus driver any more and thus uses the cirrus as simple framebuffer.
3d039dc
3d039dc
So this code tends to bitrot and bugs can go unnoticed for a long time.
3d039dc
See for example commit "3e10c3e vnc: fix qemu crash because of SIGSEGV"
3d039dc
which fixes a bug lingering in the code for almost a year, added by
3d039dc
commit "c7628bf vnc: only alloc server surface with clients connected".
3d039dc
3d039dc
Also the vnc server will throttle the frame rate in case it figures the
3d039dc
network can't keep up (send buffers are full).  This doesn't work with
3d039dc
dpy_gfx_copy, for any copy operation sent to the vnc client we have to
3d039dc
send all outstanding updates beforehand, otherwise the vnc client might
3d039dc
run the client side blit on outdated data and thereby corrupt the
3d039dc
display.  So this dpy_gfx_copy "optimization" might even make things
3d039dc
worse on slow network links.
3d039dc
3d039dc
Lets kill it once for all.
3d039dc
3d039dc
Oh, and one more reason: Turns out (after writing the patch) we have a
3d039dc
security bug in that code path ...
3d039dc
3d039dc
Fixes: CVE-2016-9603
3d039dc
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
3d039dc
Message-id: 1489494419-14340-1-git-send-email-kraxel@redhat.com
3d039dc
(cherry picked from commit 50628d3479e4f9aa97e323506856e394fe7ad7a6)
3d039dc
---
3d039dc
 hw/display/cirrus_vga.c |  12 ++----
3d039dc
 include/ui/console.h    |   7 ----
3d039dc
 ui/console.c            |  28 --------------
3d039dc
 ui/vnc.c                | 100 ------------------------------------------------
3d039dc
 4 files changed, 3 insertions(+), 144 deletions(-)
3d039dc
3d039dc
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
3d039dc
index a093dc8b16..2ef2884823 100644
3d039dc
--- a/hw/display/cirrus_vga.c
3d039dc
+++ b/hw/display/cirrus_vga.c
3d039dc
@@ -795,21 +795,15 @@ static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
3d039dc
         }
3d039dc
     }
3d039dc
 
3d039dc
-    /* we have to flush all pending changes so that the copy
3d039dc
-       is generated at the appropriate moment in time */
3d039dc
-    if (notify)
3d039dc
-        graphic_hw_update(s->vga.con);
3d039dc
-
3d039dc
     (*s->cirrus_rop) (s, s->vga.vram_ptr + s->cirrus_blt_dstaddr,
3d039dc
                       s->vga.vram_ptr + s->cirrus_blt_srcaddr,
3d039dc
 		      s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
3d039dc
 		      s->cirrus_blt_width, s->cirrus_blt_height);
3d039dc
 
3d039dc
     if (notify) {
3d039dc
-        qemu_console_copy(s->vga.con,
3d039dc
-			  sx, sy, dx, dy,
3d039dc
-			  s->cirrus_blt_width / depth,
3d039dc
-			  s->cirrus_blt_height);
3d039dc
+        dpy_gfx_update(s->vga.con, dx, dy,
3d039dc
+                       s->cirrus_blt_width / depth,
3d039dc
+                       s->cirrus_blt_height);
3d039dc
     }
3d039dc
 
3d039dc
     /* we don't have to notify the display that this portion has
3d039dc
diff --git a/include/ui/console.h b/include/ui/console.h
3d039dc
index 2703a3aa5a..67927ed851 100644
3d039dc
--- a/include/ui/console.h
3d039dc
+++ b/include/ui/console.h
3d039dc
@@ -189,9 +189,6 @@ typedef struct DisplayChangeListenerOps {
3d039dc
                            int x, int y, int w, int h);
3d039dc
     void (*dpy_gfx_switch)(DisplayChangeListener *dcl,
3d039dc
                            struct DisplaySurface *new_surface);
3d039dc
-    void (*dpy_gfx_copy)(DisplayChangeListener *dcl,
3d039dc
-                         int src_x, int src_y,
3d039dc
-                         int dst_x, int dst_y, int w, int h);
3d039dc
     bool (*dpy_gfx_check_format)(DisplayChangeListener *dcl,
3d039dc
                                  pixman_format_code_t format);
3d039dc
 
3d039dc
@@ -273,8 +270,6 @@ int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info);
3d039dc
 void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h);
3d039dc
 void dpy_gfx_replace_surface(QemuConsole *con,
3d039dc
                              DisplaySurface *surface);
3d039dc
-void dpy_gfx_copy(QemuConsole *con, int src_x, int src_y,
3d039dc
-                  int dst_x, int dst_y, int w, int h);
3d039dc
 void dpy_text_cursor(QemuConsole *con, int x, int y);
3d039dc
 void dpy_text_update(QemuConsole *con, int x, int y, int w, int h);
3d039dc
 void dpy_text_resize(QemuConsole *con, int w, int h);
3d039dc
@@ -398,8 +393,6 @@ void text_consoles_set_display(DisplayState *ds);
3d039dc
 void console_select(unsigned int index);
3d039dc
 void console_color_init(DisplayState *ds);
3d039dc
 void qemu_console_resize(QemuConsole *con, int width, int height);
3d039dc
-void qemu_console_copy(QemuConsole *con, int src_x, int src_y,
3d039dc
-                       int dst_x, int dst_y, int w, int h);
3d039dc
 DisplaySurface *qemu_console_surface(QemuConsole *con);
3d039dc
 
3d039dc
 /* console-gl.c */
3d039dc
diff --git a/ui/console.c b/ui/console.c
3d039dc
index c24bfe422d..ece0c04ddf 100644
3d039dc
--- a/ui/console.c
3d039dc
+++ b/ui/console.c
3d039dc
@@ -1558,27 +1558,6 @@ static void dpy_refresh(DisplayState *s)
3d039dc
     }
3d039dc
 }
3d039dc
 
3d039dc
-void dpy_gfx_copy(QemuConsole *con, int src_x, int src_y,
3d039dc
-                  int dst_x, int dst_y, int w, int h)
3d039dc
-{
3d039dc
-    DisplayState *s = con->ds;
3d039dc
-    DisplayChangeListener *dcl;
3d039dc
-
3d039dc
-    if (!qemu_console_is_visible(con)) {
3d039dc
-        return;
3d039dc
-    }
3d039dc
-    QLIST_FOREACH(dcl, &s->listeners, next) {
3d039dc
-        if (con != (dcl->con ? dcl->con : active_console)) {
3d039dc
-            continue;
3d039dc
-        }
3d039dc
-        if (dcl->ops->dpy_gfx_copy) {
3d039dc
-            dcl->ops->dpy_gfx_copy(dcl, src_x, src_y, dst_x, dst_y, w, h);
3d039dc
-        } else { /* TODO */
3d039dc
-            dcl->ops->dpy_gfx_update(dcl, dst_x, dst_y, w, h);
3d039dc
-        }
3d039dc
-    }
3d039dc
-}
3d039dc
-
3d039dc
 void dpy_text_cursor(QemuConsole *con, int x, int y)
3d039dc
 {
3d039dc
     DisplayState *s = con->ds;
3d039dc
@@ -2104,13 +2083,6 @@ void qemu_console_resize(QemuConsole *s, int width, int height)
3d039dc
     dpy_gfx_replace_surface(s, surface);
3d039dc
 }
3d039dc
 
3d039dc
-void qemu_console_copy(QemuConsole *con, int src_x, int src_y,
3d039dc
-                       int dst_x, int dst_y, int w, int h)
3d039dc
-{
3d039dc
-    assert(con->console_type == GRAPHIC_CONSOLE);
3d039dc
-    dpy_gfx_copy(con, src_x, src_y, dst_x, dst_y, w, h);
3d039dc
-}
3d039dc
-
3d039dc
 DisplaySurface *qemu_console_surface(QemuConsole *console)
3d039dc
 {
3d039dc
     return console->surface;
3d039dc
diff --git a/ui/vnc.c b/ui/vnc.c
3d039dc
index 76a3273e0b..b45bb2c4b8 100644
3d039dc
--- a/ui/vnc.c
3d039dc
+++ b/ui/vnc.c
3d039dc
@@ -872,105 +872,6 @@ int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
3d039dc
     return n;
3d039dc
 }
3d039dc
 
3d039dc
-static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
3d039dc
-{
3d039dc
-    /* send bitblit op to the vnc client */
3d039dc
-    vnc_lock_output(vs);
3d039dc
-    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
3d039dc
-    vnc_write_u8(vs, 0);
3d039dc
-    vnc_write_u16(vs, 1); /* number of rects */
3d039dc
-    vnc_framebuffer_update(vs, dst_x, dst_y, w, h, VNC_ENCODING_COPYRECT);
3d039dc
-    vnc_write_u16(vs, src_x);
3d039dc
-    vnc_write_u16(vs, src_y);
3d039dc
-    vnc_unlock_output(vs);
3d039dc
-    vnc_flush(vs);
3d039dc
-}
3d039dc
-
3d039dc
-static void vnc_dpy_copy(DisplayChangeListener *dcl,
3d039dc
-                         int src_x, int src_y,
3d039dc
-                         int dst_x, int dst_y, int w, int h)
3d039dc
-{
3d039dc
-    VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
3d039dc
-    VncState *vs, *vn;
3d039dc
-    uint8_t *src_row;
3d039dc
-    uint8_t *dst_row;
3d039dc
-    int i, x, y, pitch, inc, w_lim, s;
3d039dc
-    int cmp_bytes;
3d039dc
-
3d039dc
-    if (!vd->server) {
3d039dc
-        /* no client connected */
3d039dc
-        return;
3d039dc
-    }
3d039dc
-
3d039dc
-    vnc_refresh_server_surface(vd);
3d039dc
-    QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
3d039dc
-        if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
3d039dc
-            vs->force_update = 1;
3d039dc
-            vnc_update_client(vs, 1, true);
3d039dc
-            /* vs might be free()ed here */
3d039dc
-        }
3d039dc
-    }
3d039dc
-
3d039dc
-    if (!vd->server) {
3d039dc
-        /* no client connected */
3d039dc
-        return;
3d039dc
-    }
3d039dc
-    /* do bitblit op on the local surface too */
3d039dc
-    pitch = vnc_server_fb_stride(vd);
3d039dc
-    src_row = vnc_server_fb_ptr(vd, src_x, src_y);
3d039dc
-    dst_row = vnc_server_fb_ptr(vd, dst_x, dst_y);
3d039dc
-    y = dst_y;
3d039dc
-    inc = 1;
3d039dc
-    if (dst_y > src_y) {
3d039dc
-        /* copy backwards */
3d039dc
-        src_row += pitch * (h-1);
3d039dc
-        dst_row += pitch * (h-1);
3d039dc
-        pitch = -pitch;
3d039dc
-        y = dst_y + h - 1;
3d039dc
-        inc = -1;
3d039dc
-    }
3d039dc
-    w_lim = w - (VNC_DIRTY_PIXELS_PER_BIT - (dst_x % VNC_DIRTY_PIXELS_PER_BIT));
3d039dc
-    if (w_lim < 0) {
3d039dc
-        w_lim = w;
3d039dc
-    } else {
3d039dc
-        w_lim = w - (w_lim % VNC_DIRTY_PIXELS_PER_BIT);
3d039dc
-    }
3d039dc
-    for (i = 0; i < h; i++) {
3d039dc
-        for (x = 0; x <= w_lim;
3d039dc
-                x += s, src_row += cmp_bytes, dst_row += cmp_bytes) {
3d039dc
-            if (x == w_lim) {
3d039dc
-                if ((s = w - w_lim) == 0)
3d039dc
-                    break;
3d039dc
-            } else if (!x) {
3d039dc
-                s = (VNC_DIRTY_PIXELS_PER_BIT -
3d039dc
-                    (dst_x % VNC_DIRTY_PIXELS_PER_BIT));
3d039dc
-                s = MIN(s, w_lim);
3d039dc
-            } else {
3d039dc
-                s = VNC_DIRTY_PIXELS_PER_BIT;
3d039dc
-            }
3d039dc
-            cmp_bytes = s * VNC_SERVER_FB_BYTES;
3d039dc
-            if (memcmp(src_row, dst_row, cmp_bytes) == 0)
3d039dc
-                continue;
3d039dc
-            memmove(dst_row, src_row, cmp_bytes);
3d039dc
-            QTAILQ_FOREACH(vs, &vd->clients, next) {
3d039dc
-                if (!vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
3d039dc
-                    set_bit(((x + dst_x) / VNC_DIRTY_PIXELS_PER_BIT),
3d039dc
-                            vs->dirty[y]);
3d039dc
-                }
3d039dc
-            }
3d039dc
-        }
3d039dc
-        src_row += pitch - w * VNC_SERVER_FB_BYTES;
3d039dc
-        dst_row += pitch - w * VNC_SERVER_FB_BYTES;
3d039dc
-        y += inc;
3d039dc
-    }
3d039dc
-
3d039dc
-    QTAILQ_FOREACH(vs, &vd->clients, next) {
3d039dc
-        if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
3d039dc
-            vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h);
3d039dc
-        }
3d039dc
-    }
3d039dc
-}
3d039dc
-
3d039dc
 static void vnc_mouse_set(DisplayChangeListener *dcl,
3d039dc
                           int x, int y, int visible)
3d039dc
 {
3d039dc
@@ -3123,7 +3024,6 @@ static gboolean vnc_listen_io(QIOChannel *ioc,
3d039dc
 static const DisplayChangeListenerOps dcl_ops = {
3d039dc
     .dpy_name             = "vnc",
3d039dc
     .dpy_refresh          = vnc_refresh,
3d039dc
-    .dpy_gfx_copy         = vnc_dpy_copy,
3d039dc
     .dpy_gfx_update       = vnc_dpy_update,
3d039dc
     .dpy_gfx_switch       = vnc_dpy_switch,
3d039dc
     .dpy_gfx_check_format = qemu_pixman_check_format,