summary refs log tree commit diff stats
path: root/ui/vnc-ws.c
diff options
context:
space:
mode:
authorDing Hui <dinghui@sangfor.com.cn>2020-10-29 11:22:41 +0800
committerGerd Hoffmann <kraxel@redhat.com>2020-11-04 08:25:17 +0100
commit2ddafce7f797082ad216657c830afd4546f16e37 (patch)
tree9e362260922b7c502c686c11199ba4a11bcd74e8 /ui/vnc-ws.c
parent3d6e32347a3b57dac7f469a07c5f520e69bd070a (diff)
downloadfocaccia-qemu-2ddafce7f797082ad216657c830afd4546f16e37.tar.gz
focaccia-qemu-2ddafce7f797082ad216657c830afd4546f16e37.zip
vnc: fix resource leak when websocket channel error
When we connect to vnc by websocket channel, and disconnect
(maybe by some network exception) before handshake,
qemu will left CLOSE_WAIT socket and never close it

After 04d2529da2 ("ui: convert VNC server to use QIOChannelSocket")
and dd154c4d9f ("io: fix handling of EOF / error conditions in websock GSource"),
the vnc call qio_channel_add_watch only care about G_IO_IN,
but mising G_IO_HUP and G_IO_ERR.
When the websocket channel get EOF or error, it cannot callback,
because the caller ignore the event, that leads to resource leak

We need handle G_IO_HUP and G_IO_ERR event, then cleanup the channel

Fixes: 04d2529da2 ("ui: convert VNC server to use QIOChannelSocket")
Fixes: dd154c4d9f ("io: fix handling of EOF / error conditions in websock GSource")
Cc: qemu-stable@nongnu.org
Signed-off-by: Ding Hui <dinghui@sangfor.com.cn>
Message-id: 20201029032241.11040-1-dinghui@sangfor.com.cn
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Diffstat (limited to 'ui/vnc-ws.c')
-rw-r--r--ui/vnc-ws.c20
1 files changed, 16 insertions, 4 deletions
diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c
index 95c9703c72..6d79f3e5a5 100644
--- a/ui/vnc-ws.c
+++ b/ui/vnc-ws.c
@@ -41,13 +41,14 @@ static void vncws_tls_handshake_done(QIOTask *task,
             g_source_remove(vs->ioc_tag);
         }
         vs->ioc_tag = qio_channel_add_watch(
-            QIO_CHANNEL(vs->ioc), G_IO_IN, vncws_handshake_io, vs, NULL);
+            QIO_CHANNEL(vs->ioc), G_IO_IN | G_IO_HUP | G_IO_ERR,
+            vncws_handshake_io, vs, NULL);
     }
 }
 
 
 gboolean vncws_tls_handshake_io(QIOChannel *ioc G_GNUC_UNUSED,
-                                GIOCondition condition G_GNUC_UNUSED,
+                                GIOCondition condition,
                                 void *opaque)
 {
     VncState *vs = opaque;
@@ -59,6 +60,11 @@ gboolean vncws_tls_handshake_io(QIOChannel *ioc G_GNUC_UNUSED,
         vs->ioc_tag = 0;
     }
 
+    if (condition & (G_IO_HUP | G_IO_ERR)) {
+        vnc_client_error(vs);
+        return TRUE;
+    }
+
     tls = qio_channel_tls_new_server(
         vs->ioc,
         vs->vd->tlscreds,
@@ -105,13 +111,14 @@ static void vncws_handshake_done(QIOTask *task,
             g_source_remove(vs->ioc_tag);
         }
         vs->ioc_tag = qio_channel_add_watch(
-            vs->ioc, G_IO_IN, vnc_client_io, vs, NULL);
+            vs->ioc, G_IO_IN | G_IO_HUP | G_IO_ERR,
+            vnc_client_io, vs, NULL);
     }
 }
 
 
 gboolean vncws_handshake_io(QIOChannel *ioc G_GNUC_UNUSED,
-                            GIOCondition condition G_GNUC_UNUSED,
+                            GIOCondition condition,
                             void *opaque)
 {
     VncState *vs = opaque;
@@ -122,6 +129,11 @@ gboolean vncws_handshake_io(QIOChannel *ioc G_GNUC_UNUSED,
         vs->ioc_tag = 0;
     }
 
+    if (condition & (G_IO_HUP | G_IO_ERR)) {
+        vnc_client_error(vs);
+        return TRUE;
+    }
+
     wioc = qio_channel_websock_new_server(vs->ioc);
     qio_channel_set_name(QIO_CHANNEL(wioc), "vnc-ws-server-websock");