Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12:Update
qemu-linux-user.7445
0411-cirrus-vnc-zap-bitblit-support-from.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0411-cirrus-vnc-zap-bitblit-support-from.patch of Package qemu-linux-user.7445
From a2057bde4cf1640c95d6d537d12dade71537d17c Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann <kraxel@redhat.com> Date: Tue, 14 Mar 2017 13:26:59 +0100 Subject: [PATCH] cirrus/vnc: zap bitblit support from console code. There is a special code path (dpy_gfx_copy) to allow graphic emulation notify user interface code about bitblit operations carryed out by guests. It is supported by cirrus and vnc server. The intended purpose is to optimize display scrolls and just send over the scroll op instead of a full display update. This is rarely used these days though because modern guests simply don't use the cirrus blitter any more. Any linux guest using the cirrus drm driver doesn't. Any windows guest newer than winxp doesn't ship with a cirrus driver any more and thus uses the cirrus as simple framebuffer. So this code tends to bitrot and bugs can go unnoticed for a long time. See for example commit "3e10c3e vnc: fix qemu crash because of SIGSEGV" which fixes a bug lingering in the code for almost a year, added by commit "c7628bf vnc: only alloc server surface with clients connected". Also the vnc server will throttle the frame rate in case it figures the network can't keep up (send buffers are full). This doesn't work with dpy_gfx_copy, for any copy operation sent to the vnc client we have to send all outstanding updates beforehand, otherwise the vnc client might run the client side blit on outdated data and thereby corrupt the display. So this dpy_gfx_copy "optimization" might even make things worse on slow network links. Lets kill it once for all. Oh, and one more reason: Turns out (after writing the patch) we have a security bug in that code path ... Fixes: CVE-2016-9603 Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Message-id: 1489494419-14340-1-git-send-email-kraxel@redhat.com (cherry picked from commit 50628d3479e4f9aa97e323506856e394fe7ad7a6) [BR: BSC#1028656] Signed-off-by: Bruce Rogers <brogers@suse.com> --- hw/display/cirrus_vga.c | 12 ++----- include/ui/console.h | 8 ----- ui/console.c | 28 --------------- ui/vnc.c | 91 ------------------------------------------------- 4 files changed, 3 insertions(+), 136 deletions(-) diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c index e65bf0221a..2fb2a79f97 100644 --- a/hw/display/cirrus_vga.c +++ b/hw/display/cirrus_vga.c @@ -790,21 +790,15 @@ static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) } } - /* we have to flush all pending changes so that the copy - is generated at the appropriate moment in time */ - if (notify) - graphic_hw_update(s->vga.con); - (*s->cirrus_rop) (s, s->vga.vram_ptr + s->cirrus_blt_dstaddr, s->vga.vram_ptr + s->cirrus_blt_srcaddr, s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, s->cirrus_blt_width, s->cirrus_blt_height); if (notify) { - qemu_console_copy(s->vga.con, - sx, sy, dx, dy, - s->cirrus_blt_width / depth, - s->cirrus_blt_height); + dpy_gfx_update(s->vga.con, dx, dy, + s->cirrus_blt_width / depth, + s->cirrus_blt_height); } /* we don't have to notify the display that this portion has diff --git a/include/ui/console.h b/include/ui/console.h index 1264ed0c2a..11b802c5f3 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -158,10 +158,6 @@ typedef struct DisplayChangeListenerOps { int x, int y, int w, int h); void (*dpy_gfx_switch)(DisplayChangeListener *dcl, struct DisplaySurface *new_surface); - void (*dpy_gfx_copy)(DisplayChangeListener *dcl, - int src_x, int src_y, - int dst_x, int dst_y, int w, int h); - void (*dpy_text_cursor)(DisplayChangeListener *dcl, int x, int y); void (*dpy_text_resize)(DisplayChangeListener *dcl, @@ -217,8 +213,6 @@ int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info); void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h); void dpy_gfx_replace_surface(QemuConsole *con, DisplaySurface *surface); -void dpy_gfx_copy(QemuConsole *con, int src_x, int src_y, - int dst_x, int dst_y, int w, int h); void dpy_text_cursor(QemuConsole *con, int x, int y); void dpy_text_update(QemuConsole *con, int x, int y, int w, int h); void dpy_text_resize(QemuConsole *con, int w, int h); @@ -302,8 +296,6 @@ void text_consoles_set_display(DisplayState *ds); void console_select(unsigned int index); void console_color_init(DisplayState *ds); void qemu_console_resize(QemuConsole *con, int width, int height); -void qemu_console_copy(QemuConsole *con, int src_x, int src_y, - int dst_x, int dst_y, int w, int h); DisplaySurface *qemu_console_surface(QemuConsole *con); DisplayState *qemu_console_displaystate(QemuConsole *console); diff --git a/ui/console.c b/ui/console.c index 24413e8937..9c81d9ed8e 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1418,27 +1418,6 @@ void dpy_refresh(DisplayState *s) } } -void dpy_gfx_copy(QemuConsole *con, int src_x, int src_y, - int dst_x, int dst_y, int w, int h) -{ - DisplayState *s = con->ds; - DisplayChangeListener *dcl; - - if (!qemu_console_is_visible(con)) { - return; - } - QLIST_FOREACH(dcl, &s->listeners, next) { - if (con != (dcl->con ? dcl->con : active_console)) { - continue; - } - if (dcl->ops->dpy_gfx_copy) { - dcl->ops->dpy_gfx_copy(dcl, src_x, src_y, dst_x, dst_y, w, h); - } else { /* TODO */ - dcl->ops->dpy_gfx_update(dcl, dst_x, dst_y, w, h); - } - } -} - void dpy_text_cursor(QemuConsole *con, int x, int y) { DisplayState *s = con->ds; @@ -1857,13 +1836,6 @@ void qemu_console_resize(QemuConsole *s, int width, int height) dpy_gfx_replace_surface(s, surface); } -void qemu_console_copy(QemuConsole *con, int src_x, int src_y, - int dst_x, int dst_y, int w, int h) -{ - assert(con->console_type == GRAPHIC_CONSOLE); - dpy_gfx_copy(con, src_x, src_y, dst_x, dst_y, w, h); -} - DisplaySurface *qemu_console_surface(QemuConsole *console) { return console->surface; diff --git a/ui/vnc.c b/ui/vnc.c index dbe3f2b2fa..0111be6ee0 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -731,96 +731,6 @@ int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h) return n; } -static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h) -{ - /* send bitblit op to the vnc client */ - vnc_lock_output(vs); - vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); - vnc_write_u8(vs, 0); - vnc_write_u16(vs, 1); /* number of rects */ - vnc_framebuffer_update(vs, dst_x, dst_y, w, h, VNC_ENCODING_COPYRECT); - vnc_write_u16(vs, src_x); - vnc_write_u16(vs, src_y); - vnc_unlock_output(vs); - vnc_flush(vs); -} - -static void vnc_dpy_copy(DisplayChangeListener *dcl, - int src_x, int src_y, - int dst_x, int dst_y, int w, int h) -{ - VncDisplay *vd = container_of(dcl, VncDisplay, dcl); - VncState *vs, *vn; - uint8_t *src_row; - uint8_t *dst_row; - int i, x, y, pitch, inc, w_lim, s; - int cmp_bytes; - - vnc_refresh_server_surface(vd); - QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) { - if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) { - vs->force_update = 1; - vnc_update_client(vs, 1, true); - /* vs might be free()ed here */ - } - } - - /* do bitblit op on the local surface too */ - pitch = vnc_server_fb_stride(vd); - src_row = vnc_server_fb_ptr(vd, src_x, src_y); - dst_row = vnc_server_fb_ptr(vd, dst_x, dst_y); - y = dst_y; - inc = 1; - if (dst_y > src_y) { - /* copy backwards */ - src_row += pitch * (h-1); - dst_row += pitch * (h-1); - pitch = -pitch; - y = dst_y + h - 1; - inc = -1; - } - w_lim = w - (VNC_DIRTY_PIXELS_PER_BIT - (dst_x % VNC_DIRTY_PIXELS_PER_BIT)); - if (w_lim < 0) { - w_lim = w; - } else { - w_lim = w - (w_lim % VNC_DIRTY_PIXELS_PER_BIT); - } - for (i = 0; i < h; i++) { - for (x = 0; x <= w_lim; - x += s, src_row += cmp_bytes, dst_row += cmp_bytes) { - if (x == w_lim) { - if ((s = w - w_lim) == 0) - break; - } else if (!x) { - s = (VNC_DIRTY_PIXELS_PER_BIT - - (dst_x % VNC_DIRTY_PIXELS_PER_BIT)); - s = MIN(s, w_lim); - } else { - s = VNC_DIRTY_PIXELS_PER_BIT; - } - cmp_bytes = s * VNC_SERVER_FB_BYTES; - if (memcmp(src_row, dst_row, cmp_bytes) == 0) - continue; - memmove(dst_row, src_row, cmp_bytes); - QTAILQ_FOREACH(vs, &vd->clients, next) { - if (!vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) { - set_bit(((x + dst_x) / VNC_DIRTY_PIXELS_PER_BIT), - vs->dirty[y]); - } - } - } - src_row += pitch - w * VNC_SERVER_FB_BYTES; - dst_row += pitch - w * VNC_SERVER_FB_BYTES; - y += inc; - } - - QTAILQ_FOREACH(vs, &vd->clients, next) { - if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) { - vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h); - } - } -} - static void vnc_mouse_set(DisplayChangeListener *dcl, int x, int y, int visible) { @@ -2963,7 +2873,6 @@ static void vnc_listen_websocket_read(void *opaque) static const DisplayChangeListenerOps dcl_ops = { .dpy_name = "vnc", .dpy_refresh = vnc_refresh, - .dpy_gfx_copy = vnc_dpy_copy, .dpy_gfx_update = vnc_dpy_update, .dpy_gfx_switch = vnc_dpy_switch, .dpy_mouse_set = vnc_mouse_set,
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor