From: Chris Webb <chris@arachsys.com>
To: Avi Kivity <avi@redhat.com>, Gerd Hoffmann <kraxel@redhat.com>
Cc: qemu-devel@nongnu.org, kvm@vger.kernel.org
Subject: [Qemu-devel] Re: qemu-kvm segfaults in qemu_del_timer (0.10.5 and 0.10.6)
Date: Wed, 19 Aug 2009 23:47:39 +0100 [thread overview]
Message-ID: <20090819224739.GB17276@arachsys.com> (raw)
In-Reply-To: <4A840DE0.2060202@redhat.com>
Avi Kivity <avi@redhat.com> writes:
> master branch has a patch that fixes a use-after-free when
> disconnecting. Unfortunately it doesn't port cleanly to stable-0.10.
I've collected quite a few more core dumps from segfaults of client virtual
machines now, all of which are VNC related and could quite plausibly be use
of a VncState after it has been freed. I looked at Gerd's patch [198a00:
vnc: rework VncState release workflow] and have taken a stab at the
equivalent patch for stable qemu & qemu-kvm 0.10.
With the following applied, VNC connections and disconnections still work
correctly, so it doesn't horribly break anything, but I can't immediately
confirm whether it will cure the rare segfaults as I haven't yet found a
rapid way of reproducing the crashes other than by waiting for one.
diff --git a/vnc.c b/vnc.c
--- a/vnc.c
+++ b/vnc.c
@@ -200,6 +200,8 @@
static void vnc_write_u8(VncState *vs, uint8_t value);
static void vnc_flush(VncState *vs);
static void vnc_update_client(void *opaque);
+static void vnc_disconnect_start(VncState *vs);
+static void vnc_disconnect_finish(VncState *vs);
static void vnc_client_read(void *opaque);
static void vnc_colordepth(VncState *vs);
@@ -633,8 +635,6 @@
static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
{
- vnc_update_client(vs);
-
vnc_write_u8(vs, 0); /* msg id */
vnc_write_u8(vs, 0);
vnc_write_u16(vs, 1); /* number of rects */
@@ -647,13 +647,21 @@
static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
{
VncDisplay *vd = ds->opaque;
- VncState *vs = vd->clients;
- while (vs != NULL) {
+ VncState *vs, *vn;
+
+ for (vs = vd->clients; vs != NULL; vs = vn) {
+ vn = vs->next;
+ if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
+ vnc_update_client(vs);
+ /* vs might be free()ed here */
+ }
+ }
+
+ for (vs = vd->clients; vs != NULL; vs = vs->next) {
if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT))
vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h);
else /* TODO */
vnc_update(vs, dst_x, dst_y, w, h);
- vs = vs->next;
}
}
@@ -763,6 +771,8 @@
if (vs->csock != -1) {
qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
+ } else {
+ vnc_disconnect_finish(vs);
}
}
@@ -832,6 +842,47 @@
}
}
+static void vnc_disconnect_start(VncState *vs)
+{
+ if (vs->csock == -1)
+ return;
+ qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
+ closesocket(vs->csock);
+ vs->csock = -1;
+}
+
+static void vnc_disconnect_finish(VncState *vs)
+{
+ qemu_del_timer(vs->timer);
+ qemu_free_timer(vs->timer);
+ if (vs->input.buffer) qemu_free(vs->input.buffer);
+ if (vs->output.buffer) qemu_free(vs->output.buffer);
+#ifdef CONFIG_VNC_TLS
+ if (vs->tls_session) {
+ gnutls_deinit(vs->tls_session);
+ vs->tls_session = NULL;
+ }
+#endif /* CONFIG_VNC_TLS */
+ audio_del(vs);
+
+ VncState *p, *parent = NULL;
+ for (p = vs->vd->clients; p != NULL; p = p->next) {
+ if (p == vs) {
+ if (parent)
+ parent->next = p->next;
+ else
+ vs->vd->clients = p->next;
+ break;
+ }
+ parent = p;
+ }
+ if (!vs->vd->clients)
+ dcl->idle = 1;
+
+ qemu_free(vs->old_data);
+ qemu_free(vs);
+}
+
static int vnc_client_io_error(VncState *vs, int ret, int last_errno)
{
if (ret == 0 || ret == -1) {
@@ -849,36 +900,7 @@
}
VNC_DEBUG("Closing down client sock %d %d\n", ret, ret < 0 ? last_errno : 0);
- qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
- closesocket(vs->csock);
- qemu_del_timer(vs->timer);
- qemu_free_timer(vs->timer);
- if (vs->input.buffer) qemu_free(vs->input.buffer);
- if (vs->output.buffer) qemu_free(vs->output.buffer);
-#ifdef CONFIG_VNC_TLS
- if (vs->tls_session) {
- gnutls_deinit(vs->tls_session);
- vs->tls_session = NULL;
- }
-#endif /* CONFIG_VNC_TLS */
- audio_del(vs);
-
- VncState *p, *parent = NULL;
- for (p = vs->vd->clients; p != NULL; p = p->next) {
- if (p == vs) {
- if (parent)
- parent->next = p->next;
- else
- vs->vd->clients = p->next;
- break;
- }
- parent = p;
- }
- if (!vs->vd->clients)
- dcl->idle = 1;
-
- qemu_free(vs->old_data);
- qemu_free(vs);
+ vnc_disconnect_start(vs);
return 0;
}
@@ -887,7 +909,8 @@
static void vnc_client_error(VncState *vs)
{
- vnc_client_io_error(vs, -1, EINVAL);
+ VNC_DEBUG("Closing down client sock: protocol error\n");
+ vnc_disconnect_start(vs);
}
static void vnc_client_write(void *opaque)
@@ -947,8 +970,11 @@
#endif /* CONFIG_VNC_TLS */
ret = recv(vs->csock, buffer_end(&vs->input), 4096, 0);
ret = vnc_client_io_error(vs, ret, socket_error());
- if (!ret)
+ if (!ret) {
+ if (vs->csock == -1)
+ vnc_disconnect_finish(vs);
return;
+ }
vs->input.offset += ret;
@@ -957,8 +983,10 @@
int ret;
ret = vs->read_handler(vs, vs->input.buffer, len);
- if (vs->csock == -1)
+ if (vs->csock == -1) {
+ vnc_disconnect_finish(vs);
return;
+ }
if (!ret) {
memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len));
@@ -973,7 +1001,7 @@
{
buffer_reserve(&vs->output, len);
- if (buffer_empty(&vs->output)) {
+ if (vs->csock != -1 && buffer_empty(&vs->output)) {
qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
}
@@ -1014,7 +1042,7 @@
static void vnc_flush(VncState *vs)
{
- if (vs->output.offset)
+ if (vs->csock != -1 && vs->output.offset)
vnc_client_write(vs);
}
@@ -2282,11 +2310,13 @@
vnc_read_when(vs, protocol_version, 12);
memset(vs->old_data, 0, ds_get_linesize(vs->ds) * ds_get_height(vs->ds));
memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
- vnc_update_client(vs);
reset_keys(vs);
vs->next = vd->clients;
vd->clients = vs;
+
+ vnc_update_client(vs);
+ /* vs might be free()ed here */
}
static void vnc_listen_read(void *opaque)
next prev parent reply other threads:[~2009-08-19 22:48 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-08-12 15:01 [Qemu-devel] qemu-kvm segfaults in qemu_del_timer (0.10.5 and 0.10.6) Chris Webb
2009-08-12 15:38 ` [Qemu-devel] " Avi Kivity
2009-08-12 16:24 ` Chris Webb
2009-08-13 12:23 ` Chris Webb
2009-08-13 12:41 ` Chris Webb
2009-08-13 12:42 ` Avi Kivity
2009-08-13 12:43 ` Chris Webb
2009-08-13 12:45 ` Chris Webb
2009-08-13 12:58 ` Avi Kivity
2009-08-19 22:47 ` Chris Webb [this message]
2009-08-24 15:45 ` Chris Webb
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20090819224739.GB17276@arachsys.com \
--to=chris@arachsys.com \
--cc=avi@redhat.com \
--cc=kraxel@redhat.com \
--cc=kvm@vger.kernel.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).