From 5a693efda84d7df5136cc2bd31c959bb1530b0c9 Mon Sep 17 00:00:00 2001 From: Gonglei Date: Fri, 8 Jul 2016 11:37:36 +0800 Subject: [PATCH 1/3] vnc: fix incorrect checking condition when updating client vs->disconnecting is set to TRUE and vs->ioc is closed, but vs->ioc isn't set to NULL, so that the vnc_disconnect_finish() isn't invoked when you update client in vnc_update_client() after vnc_disconnect_start invoked. Let's using change the checking condition to avoid resource leak. Signed-off-by: Haibin Wang Signed-off-by: Gonglei Reviewed-by: Daniel P. Berrange Message-id: 1467949056-81208-1-git-send-email-arei.gonglei@huawei.com Signed-off-by: Gerd Hoffmann --- ui/vnc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/vnc.c b/ui/vnc.c index 18c0b56c3a..bd602b6c08 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -1025,7 +1025,7 @@ static int find_and_clear_dirty_height(VncState *vs, static int vnc_update_client(VncState *vs, int has_dirty, bool sync) { vs->has_dirty += has_dirty; - if (vs->need_update && vs->ioc != NULL) { + if (vs->need_update && !vs->disconnecting) { VncDisplay *vd = vs->vd; VncJob *job; int y; From 095497ffc66b7f031ff2a17f1e50f5cb105ce588 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Thu, 30 Jun 2016 12:00:46 +0200 Subject: [PATCH 2/3] vnc-enc-tight: use thread local storage for palette currently the color counting palette is allocated from heap, used and destroyed for each single subrect. Use a static palette per thread for this purpose and avoid the malloc and free for each update. Signed-off-by: Peter Lieven Reviewed-by: Paolo Bonzini Message-id: 1467280846-9674-1-git-send-email-pl@kamp.de Signed-off-by: Gerd Hoffmann --- ui/vnc-enc-tight.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c index e5cba0e5a7..b8581dd2e9 100644 --- a/ui/vnc-enc-tight.c +++ b/ui/vnc-enc-tight.c @@ -349,7 +349,7 @@ tight_detect_smooth_image(VncState *vs, int w, int h) tight_fill_palette##bpp(VncState *vs, int x, int y, \ int max, size_t count, \ uint32_t *bg, uint32_t *fg, \ - VncPalette **palette) { \ + VncPalette *palette) { \ uint##bpp##_t *data; \ uint##bpp##_t c0, c1, ci; \ int i, n0, n1; \ @@ -396,23 +396,23 @@ tight_detect_smooth_image(VncState *vs, int w, int h) return 0; \ } \ \ - *palette = palette_new(max, bpp); \ - palette_put(*palette, c0); \ - palette_put(*palette, c1); \ - palette_put(*palette, ci); \ + palette_init(palette, max, bpp); \ + palette_put(palette, c0); \ + palette_put(palette, c1); \ + palette_put(palette, ci); \ \ for (i++; i < count; i++) { \ if (data[i] == ci) { \ continue; \ } else { \ ci = data[i]; \ - if (!palette_put(*palette, (uint32_t)ci)) { \ + if (!palette_put(palette, (uint32_t)ci)) { \ return 0; \ } \ } \ } \ \ - return palette_size(*palette); \ + return palette_size(palette); \ } DEFINE_FILL_PALETTE_FUNCTION(8) @@ -421,7 +421,7 @@ DEFINE_FILL_PALETTE_FUNCTION(32) static int tight_fill_palette(VncState *vs, int x, int y, size_t count, uint32_t *bg, uint32_t *fg, - VncPalette **palette) + VncPalette *palette) { int max; @@ -1457,9 +1457,11 @@ static int send_sub_rect_jpeg(VncState *vs, int x, int y, int w, int h, } #endif +static __thread VncPalette color_count_palette; + static int send_sub_rect(VncState *vs, int x, int y, int w, int h) { - VncPalette *palette = NULL; + VncPalette *palette = &color_count_palette; uint32_t bg = 0, fg = 0; int colors; int ret = 0; @@ -1488,7 +1490,7 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h) } #endif - colors = tight_fill_palette(vs, x, y, w * h, &bg, &fg, &palette); + colors = tight_fill_palette(vs, x, y, w * h, &bg, &fg, palette); #ifdef CONFIG_VNC_JPEG if (allow_jpeg && vs->tight.quality != (uint8_t)-1) { @@ -1501,7 +1503,6 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h) ret = send_sub_rect_nojpeg(vs, x, y, w, h, bg, fg, colors, palette); #endif - palette_destroy(palette); return ret; } From ea697449884d83b83fefbc9cd87bdde0c94b49d6 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 27 Jun 2016 16:48:49 +0100 Subject: [PATCH 3/3] ui: avoid crash if vnc client disconnects with writes pending The vnc_client_read() function is called from the vnc_client_io() event handler callback when there is incoming data to process. If it detects that the client has disconnected, then it will trigger cleanup and free'ing of the VncState client struct at a safe time. Unfortunately, the vnc_client_io() event handler will also call vnc_client_write() to handle any outgoing data writes. So if vnc_client_io() was invoked with both G_IO_IN and G_IO_OUT events set, and the client disconnects, we may try to write to a client which has just been freed. https://bugs.launchpad.net/qemu/+bug/1594861 Signed-off-by: Daniel P. Berrange Message-id: 1467042529-3372-1-git-send-email-berrange@redhat.com Signed-off-by: Gerd Hoffmann --- ui/vnc.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/ui/vnc.c b/ui/vnc.c index bd602b6c08..e3f857cc90 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -1436,8 +1436,9 @@ static void vnc_jobs_bh(void *opaque) * First function called whenever there is more data to be read from * the client socket. Will delegate actual work according to whether * SASL SSF layers are enabled (thus requiring decryption calls) + * Returns 0 on success, -1 if client disconnected */ -static void vnc_client_read(VncState *vs) +static int vnc_client_read(VncState *vs) { ssize_t ret; @@ -1450,8 +1451,9 @@ static void vnc_client_read(VncState *vs) if (!ret) { if (vs->disconnecting) { vnc_disconnect_finish(vs); + return -1; } - return; + return 0; } while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) { @@ -1461,7 +1463,7 @@ static void vnc_client_read(VncState *vs) ret = vs->read_handler(vs, vs->input.buffer, len); if (vs->disconnecting) { vnc_disconnect_finish(vs); - return; + return -1; } if (!ret) { @@ -1470,6 +1472,7 @@ static void vnc_client_read(VncState *vs) vs->read_handler_expect = ret; } } + return 0; } gboolean vnc_client_io(QIOChannel *ioc G_GNUC_UNUSED, @@ -1477,7 +1480,9 @@ gboolean vnc_client_io(QIOChannel *ioc G_GNUC_UNUSED, { VncState *vs = opaque; if (condition & G_IO_IN) { - vnc_client_read(vs); + if (vnc_client_read(vs) < 0) { + return TRUE; + } } if (condition & G_IO_OUT) { vnc_client_write(vs);