[Spice-commits] 2 commits - server/red-channel-client.c server/reds-stream.c server/reds-stream.h

Frediano Ziglio fziglio at kemper.freedesktop.org
Thu Sep 7 14:03:15 UTC 2017


 server/red-channel-client.c |   14 +++++++++++++-
 server/reds-stream.c        |   18 +++++++++++++-----
 server/reds-stream.h        |    1 +
 3 files changed, 27 insertions(+), 6 deletions(-)

New commits:
commit 5d7ecb01621e7cacb8840abe2851b95916d45700
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Wed Aug 30 10:27:33 2017 +0100

    Fix crash attempting to connect duplicate channels
    
    You could easily trigger this issue using multiple monitors and a
    modified spice-gtk client with this patch:
    
      --- a/src/channel-main.c
      +++ b/src/channel-main.c
      @@ -1699,6 +1699,7 @@ static gboolean _channel_new(channel_new_t *c)
       {
           g_return_val_if_fail(c != NULL, FALSE);
    
      +    if (c->type == SPICE_CHANNEL_DISPLAY) c->id = 0;
           spice_channel_new(c->session, c->type, c->id);
    
           g_object_unref(c->session);
    
    which cause a crash like
    
    (process:28742): Spice-WARNING **: Failed to create channel client: Client 0x40246f5d0: duplicate channel type 2 id 0
    2017-08-24 09:36:57.451+0000: shutting down, reason=crashed
    
    RedChannelClient is an GInitable type, which means that the object is
    constructed, and then the _init() function is called, which can fail.
    If the _init() fails, the newly-created object will be destroyed. As
    part of _init(), we add a new watch for the stream using the core
    interface that is associated with the channel. After adding the watch,
    our rcc creation fails (due to duplicate ID), and the rcc object is
    unreffed. This results in a call to reds_stream_free() (since the rcc
    now owns the stream). But in reds_stream_free, we were trying to remove
    the watch from the core interface associated with the RedsState. For
    most channels, these two core interfaces are equivalent. But for the
    Display and Cursor channels, it is the core Glib-based interface
    associated with the RedWorker.
    
    The watch in RedsStream by default is bound to the Qemu provided
    SpiceCoreInterface while RedChannelClient bound it to Glib one causing
    the crash when the watch is deleted from RedsStream. Change the bound
    interface.
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Jonathon Jongsma <jjongsma at redhat.com>

diff --git a/server/red-channel-client.c b/server/red-channel-client.c
index 655e41c7..35bb8d92 100644
--- a/server/red-channel-client.c
+++ b/server/red-channel-client.c
@@ -339,6 +339,16 @@ red_channel_client_finalize(GObject *object)
 {
     RedChannelClient *self = RED_CHANNEL_CLIENT(object);
 
+    SpiceCoreInterfaceInternal *core = red_channel_get_core_interface(self->priv->channel);
+    if (self->priv->latency_monitor.timer) {
+        core->timer_remove(core, self->priv->latency_monitor.timer);
+        self->priv->latency_monitor.timer = NULL;
+    }
+    if (self->priv->connectivity_monitor.timer) {
+        core->timer_remove(core, self->priv->connectivity_monitor.timer);
+        self->priv->connectivity_monitor.timer = NULL;
+    }
+
     reds_stream_free(self->priv->stream);
     self->priv->stream = NULL;
 
@@ -921,12 +931,14 @@ static gboolean red_channel_client_initable_init(GInitable *initable,
     }
 
     core = red_channel_get_core_interface(self->priv->channel);
-    if (self->priv->stream)
+    if (self->priv->stream) {
+        reds_stream_set_core_interface(self->priv->stream, core);
         self->priv->stream->watch =
             core->watch_add(core, self->priv->stream->socket,
                             SPICE_WATCH_EVENT_READ,
                             red_channel_client_event,
                             self);
+    }
 
     if (self->priv->monitor_latency
         && reds_stream_get_family(self->priv->stream) != AF_UNIX) {
commit 692c133765f3bf52866448fae26665a098f62c97
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Wed Aug 30 10:13:43 2017 +0100

    reds-stream: Allows to change core interface
    
    When a stream is moved from the main thread to a
    secondary one the events are potentially registered
    using a different core interface. This cause memory
    corruption accessing the watch registered in RedsStream.
    This patch allows to always use the right interface.
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Jonathon Jongsma <jjongsma at redhat.com>

diff --git a/server/reds-stream.c b/server/reds-stream.c
index 2ea54756..e5336265 100644
--- a/server/reds-stream.c
+++ b/server/reds-stream.c
@@ -98,6 +98,7 @@ struct RedsStreamPrivate {
     ssize_t (*writev)(RedsStream *s, const struct iovec *iov, int iovcnt);
 
     RedsState *reds;
+    SpiceCoreInterfaceInternal *core;
 };
 
 static ssize_t stream_write_cb(RedsStream *s, const void *buf, size_t size)
@@ -170,7 +171,7 @@ static ssize_t stream_ssl_read_cb(RedsStream *s, void *buf, size_t size)
 void reds_stream_remove_watch(RedsStream* s)
 {
     if (s->watch) {
-        reds_core_watch_remove(s->priv->reds, s->watch);
+        s->priv->core->watch_remove(s->priv->core, s->watch);
         s->watch = NULL;
     }
 }
@@ -418,6 +419,7 @@ RedsStream *reds_stream_new(RedsState *reds, int socket)
     stream->priv = (RedsStreamPrivate *)(stream+1);
     stream->priv->info = spice_new0(SpiceChannelEventInfo, 1);
     stream->priv->reds = reds;
+    stream->priv->core = reds_get_core_interface(reds);
     reds_stream_set_socket(stream, socket);
 
     stream->priv->read = stream_read_cb;
@@ -427,6 +429,12 @@ RedsStream *reds_stream_new(RedsState *reds, int socket)
     return stream;
 }
 
+void reds_stream_set_core_interface(RedsStream *stream, SpiceCoreInterfaceInternal *core)
+{
+    reds_stream_remove_watch(stream);
+    stream->priv->core = core;
+}
+
 bool reds_stream_is_ssl(RedsStream *stream)
 {
     return (stream->priv->ssl != NULL);
@@ -511,7 +519,7 @@ static void async_read_handler(G_GNUC_UNUSED int fd,
 {
     AsyncRead *async = (AsyncRead *)data;
     RedsStream *stream = async->stream;
-    RedsState *reds = stream->priv->reds;
+    SpiceCoreInterfaceInternal *core = stream->priv->core;
 
     for (;;) {
         int n = async->end - async->now;
@@ -523,9 +531,9 @@ static void async_read_handler(G_GNUC_UNUSED int fd,
             switch (err) {
             case EAGAIN:
                 if (!stream->watch) {
-                    stream->watch = reds_core_watch_add(reds, stream->socket,
-                                                        SPICE_WATCH_EVENT_READ,
-                                                        async_read_handler, async);
+                    stream->watch = core->watch_add(core, stream->socket,
+                                                    SPICE_WATCH_EVENT_READ,
+                                                    async_read_handler, async);
                 }
                 return;
             case EINTR:
diff --git a/server/reds-stream.h b/server/reds-stream.h
index 2dc39c23..55a82745 100644
--- a/server/reds-stream.h
+++ b/server/reds-stream.h
@@ -67,6 +67,7 @@ void reds_stream_remove_watch(RedsStream* s);
 void reds_stream_set_channel(RedsStream *stream, int connection_id,
                              int channel_type, int channel_id);
 RedsStream *reds_stream_new(RedsState *reds, int socket);
+void reds_stream_set_core_interface(RedsStream *stream, SpiceCoreInterfaceInternal *core);
 bool reds_stream_is_ssl(RedsStream *stream);
 RedsStreamSslStatus reds_stream_ssl_accept(RedsStream *stream);
 int reds_stream_enable_ssl(RedsStream *stream, SSL_CTX *ctx);


More information about the Spice-commits mailing list