vnc_worker_thread_loop() copies z_stream stored in its local VncState to
the persistent VncState, and the copied one is freed with deflateEnd()
later. However, deflateEnd() refuses to operate with a copied z_stream
and returns Z_STREAM_ERROR, leaking the allocated memory.
Avoid copying the zlib state to fix the memory leak.
Fixes: bd023f953e5e ("vnc: threaded VNC server")
Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
ui/vnc.h | 2 +-
ui/vnc-enc-zlib.c | 30 +++++++++++++++---------------
ui/vnc-jobs.c | 2 --
ui/vnc.c | 2 +-
4 files changed, 17 insertions(+), 19 deletions(-)
diff --git a/ui/vnc.h b/ui/vnc.h
index 1dc76c270c35..78a5fdfdc0d0 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -265,6 +265,7 @@ typedef struct VncWorker {
uint8_t lossy_rect[VNC_STAT_ROWS][VNC_STAT_COLS];
VncTight tight;
+ VncZlib zlib;
VncZrle zrle;
} VncWorker;
@@ -345,7 +346,6 @@ struct VncState
/* Encoding specific, if you add something here, don't forget to
* update vnc_async_encoding_start()
*/
- VncZlib zlib;
VncHextile hextile;
VncZywrle zywrle;
diff --git a/ui/vnc-enc-zlib.c b/ui/vnc-enc-zlib.c
index 605030730a44..d8b4cf038b02 100644
--- a/ui/vnc-enc-zlib.c
+++ b/ui/vnc-enc-zlib.c
@@ -48,21 +48,21 @@ void vnc_zlib_zfree(void *x, void *addr)
static void vnc_zlib_start(VncState *vs)
{
- buffer_reset(&vs->zlib.zlib);
+ buffer_reset(&vs->worker->zlib.zlib);
// make the output buffer be the zlib buffer, so we can compress it later
- vs->zlib.tmp = vs->output;
- vs->output = vs->zlib.zlib;
+ vs->worker->zlib.tmp = vs->output;
+ vs->output = vs->worker->zlib.zlib;
}
static int vnc_zlib_stop(VncState *vs)
{
- z_streamp zstream = &vs->zlib.stream;
+ z_streamp zstream = &vs->worker->zlib.stream;
int previous_out;
// switch back to normal output/zlib buffers
- vs->zlib.zlib = vs->output;
- vs->output = vs->zlib.tmp;
+ vs->worker->zlib.zlib = vs->output;
+ vs->output = vs->worker->zlib.tmp;
// compress the zlib buffer
@@ -85,24 +85,24 @@ static int vnc_zlib_stop(VncState *vs)
return -1;
}
- vs->zlib.level = vs->worker->tight.compression;
+ vs->worker->zlib.level = vs->worker->tight.compression;
zstream->opaque = vs;
}
- if (vs->worker->tight.compression != vs->zlib.level) {
+ if (vs->worker->tight.compression != vs->worker->zlib.level) {
if (deflateParams(zstream, vs->worker->tight.compression,
Z_DEFAULT_STRATEGY) != Z_OK) {
return -1;
}
- vs->zlib.level = vs->worker->tight.compression;
+ vs->worker->zlib.level = vs->worker->tight.compression;
}
// reserve memory in output buffer
- buffer_reserve(&vs->output, vs->zlib.zlib.offset + 64);
+ buffer_reserve(&vs->output, vs->worker->zlib.zlib.offset + 64);
// set pointers
- zstream->next_in = vs->zlib.zlib.buffer;
- zstream->avail_in = vs->zlib.zlib.offset;
+ zstream->next_in = vs->worker->zlib.zlib.buffer;
+ zstream->avail_in = vs->worker->zlib.zlib.offset;
zstream->next_out = vs->output.buffer + vs->output.offset;
zstream->avail_out = vs->output.capacity - vs->output.offset;
previous_out = zstream->avail_out;
@@ -147,8 +147,8 @@ int vnc_zlib_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
void vnc_zlib_clear(VncState *vs)
{
- if (vs->zlib.stream.opaque) {
- deflateEnd(&vs->zlib.stream);
+ if (vs->worker->zlib.stream.opaque) {
+ deflateEnd(&vs->worker->zlib.stream);
}
- buffer_free(&vs->zlib.zlib);
+ buffer_free(&vs->worker->zlib.zlib);
}
diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c
index d019d88536b7..dbbf62212c79 100644
--- a/ui/vnc-jobs.c
+++ b/ui/vnc-jobs.c
@@ -189,7 +189,6 @@ static void vnc_async_encoding_start(VncState *orig, VncState *local)
local->write_pixels = orig->write_pixels;
local->client_pf = orig->client_pf;
local->client_be = orig->client_be;
- local->zlib = orig->zlib;
local->hextile = orig->hextile;
local->client_width = orig->client_width;
local->client_height = orig->client_height;
@@ -198,7 +197,6 @@ static void vnc_async_encoding_start(VncState *orig, VncState *local)
static void vnc_async_encoding_end(VncState *orig, VncState *local)
{
buffer_free(&local->output);
- orig->zlib = local->zlib;
orig->hextile = local->hextile;
}
diff --git a/ui/vnc.c b/ui/vnc.c
index 17fcf377d7f8..b55d80b9b003 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -3258,7 +3258,7 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
#ifdef CONFIG_PNG
buffer_init(&vs->worker->tight.png, "vnc-tight-png/%p", sioc);
#endif
- buffer_init(&vs->zlib.zlib, "vnc-zlib/%p", sioc);
+ buffer_init(&vs->worker->zlib.zlib, "vnc-zlib/%p", sioc);
buffer_init(&vs->worker->zrle.zrle, "vnc-zrle/%p", sioc);
buffer_init(&vs->worker->zrle.fb, "vnc-zrle-fb/%p", sioc);
buffer_init(&vs->worker->zrle.zlib, "vnc-zrle-zlib/%p", sioc);
--
2.49.0
© 2016 - 2025 Red Hat, Inc.