Skip to content

Commit 2b13613

Browse files
berrangemdroth
authored andcommitted
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 <[email protected]> Message-id: [email protected] Signed-off-by: Gerd Hoffmann <[email protected]> (cherry picked from commit ea69744) Signed-off-by: Michael Roth <[email protected]>
1 parent 6e18475 commit 2b13613

File tree

1 file changed

+9
-4
lines changed

1 file changed

+9
-4
lines changed

ui/vnc.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1442,8 +1442,9 @@ static void vnc_jobs_bh(void *opaque)
14421442
* First function called whenever there is more data to be read from
14431443
* the client socket. Will delegate actual work according to whether
14441444
* SASL SSF layers are enabled (thus requiring decryption calls)
1445+
* Returns 0 on success, -1 if client disconnected
14451446
*/
1446-
static void vnc_client_read(VncState *vs)
1447+
static int vnc_client_read(VncState *vs)
14471448
{
14481449
ssize_t ret;
14491450

@@ -1456,8 +1457,9 @@ static void vnc_client_read(VncState *vs)
14561457
if (!ret) {
14571458
if (vs->disconnecting) {
14581459
vnc_disconnect_finish(vs);
1460+
return -1;
14591461
}
1460-
return;
1462+
return 0;
14611463
}
14621464

14631465
while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) {
@@ -1467,7 +1469,7 @@ static void vnc_client_read(VncState *vs)
14671469
ret = vs->read_handler(vs, vs->input.buffer, len);
14681470
if (vs->disconnecting) {
14691471
vnc_disconnect_finish(vs);
1470-
return;
1472+
return -1;
14711473
}
14721474

14731475
if (!ret) {
@@ -1476,14 +1478,17 @@ static void vnc_client_read(VncState *vs)
14761478
vs->read_handler_expect = ret;
14771479
}
14781480
}
1481+
return 0;
14791482
}
14801483

14811484
gboolean vnc_client_io(QIOChannel *ioc G_GNUC_UNUSED,
14821485
GIOCondition condition, void *opaque)
14831486
{
14841487
VncState *vs = opaque;
14851488
if (condition & G_IO_IN) {
1486-
vnc_client_read(vs);
1489+
if (vnc_client_read(vs) < 0) {
1490+
return TRUE;
1491+
}
14871492
}
14881493
if (condition & G_IO_OUT) {
14891494
vnc_client_write(vs);

0 commit comments

Comments
 (0)