ui/vnc-jobs: fix VncRectEntry leak on job cleanup

When a VncJob is freed, its associated VncRectEntry list must also be
freed. Previously, vnc_job_push() and the disconnected path in
vnc_worker_thread_loop() called g_free(job) directly, leaking all
VncRectEntry allocations.

Introduce vnc_job_free() which iterates and frees the rectangle entries
before freeing the job itself, and use it in both paths.

Also add QLIST_REMOVE() in the worker loop before g_free(entry), so
that entries processed during normal operation are properly unlinked.
Without this, vnc_job_free() would iterate dangling pointers to
already-freed entries, causing use-after-free.

Fixes: bd023f953e ("vnc: threaded VNC server")
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
Marc-André Lureau
2026-03-13 20:54:47 +04:00
parent e5ef268596
commit 3cae0b46be

View File

@@ -107,11 +107,25 @@ int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h)
return 1;
}
static void vnc_job_free(VncJob *job)
{
VncRectEntry *entry, *tmp;
if (!job) {
return;
}
QLIST_FOREACH_SAFE(entry, &job->rectangles, next, tmp) {
/* no need for QLIST_REMOVE(entry, next) */
g_free(entry);
}
g_free(job);
}
void vnc_job_push(VncJob *job)
{
vnc_lock_queue(queue);
if (queue->exit || QLIST_EMPTY(&job->rectangles)) {
g_free(job);
vnc_job_free(job);
} else {
QTAILQ_INSERT_TAIL(&queue->jobs, job, next);
qemu_cond_broadcast(&queue->cond);
@@ -296,6 +310,7 @@ static int vnc_worker_thread_loop(VncJobQueue *queue)
n_rectangles += n;
}
}
QLIST_REMOVE(entry, next);
g_free(entry);
}
trace_vnc_job_nrects(&vs, job, n_rectangles);
@@ -324,7 +339,7 @@ disconnected:
QTAILQ_REMOVE(&queue->jobs, job, next);
vnc_unlock_queue(queue);
qemu_cond_broadcast(&queue->cond);
g_free(job);
vnc_job_free(job);
vs.magic = 0;
return 0;
}