[Spice-devel] [PATCH spice-server 1/5] Fix crash attempting to connect duplicate channels

Christophe Fergeau cfergeau at redhat.com
Fri Aug 25 14:53:36 UTC 2017


On Thu, Aug 24, 2017 at 03:37:16PM +0100, Frediano Ziglio wrote:
> You could easily trigger this issue using multiple monitors and
> a modified 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
> 
> One issue is that g_initable_new in this case returns NULL (dcc.c).

I would split this commit in 2 parts, one simple NULL dereference fix,
and a second one with your watch changes.

> 
> The other is that the watch in RedsStream is supposed to be bound
> to the Qemu provided SpiceCoreInterface while RedChannelClient bound
> it to Glib one causing the crash when the watch is deleted from
> RedsStream. To avoid this a new watch is saved in
> RedChannelClientPrivate.
> 
> Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
> ---
>  server/dcc.c                |  4 +++-
>  server/red-channel-client.c | 39 ++++++++++++++++++++++++++++-----------
>  2 files changed, 31 insertions(+), 12 deletions(-)
> 
> diff --git a/server/dcc.c b/server/dcc.c
> index 4490507b..2e1acd23 100644
> --- a/server/dcc.c
> +++ b/server/dcc.c
> @@ -516,7 +516,9 @@ DisplayChannelClient *dcc_new(DisplayChannel *display,
>                           NULL);
>      spice_debug("New display (client %p) dcc %p stream %p", client, dcc, stream);
>      common_graphics_channel_set_during_target_migrate(COMMON_GRAPHICS_CHANNEL(display), mig_target);
> -    dcc->priv->id = common_graphics_channel_get_qxl(COMMON_GRAPHICS_CHANNEL(display))->id;
> +    if (dcc) {
> +        dcc->priv->id = common_graphics_channel_get_qxl(COMMON_GRAPHICS_CHANNEL(display))->id;
> +    }
>  
>      return dcc;
>  }
> diff --git a/server/red-channel-client.c b/server/red-channel-client.c
> index f1042dd4..1162ddca 100644
> --- a/server/red-channel-client.c
> +++ b/server/red-channel-client.c
> @@ -120,6 +120,7 @@ struct RedChannelClientPrivate
>      RedChannel *channel;
>      RedClient  *client;
>      RedsStream *stream;
> +    SpiceWatch *watch;
>      gboolean monitor_latency;
>  
>      struct {
> @@ -339,6 +340,20 @@ 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->watch) {
> +        core->watch_remove(core, self->priv->watch);
> +        self->priv->watch = NULL;
> +    }
> +    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;
> +    }
> +

These latency_monitor/connectivity_monitor hunks seem unrelated to this
patch?
Apart from this, looks good to me, though I don't really like this whole
RedsStream API :-/

Christophe

>      reds_stream_free(self->priv->stream);
>      self->priv->stream = NULL;
>  
> @@ -922,7 +937,7 @@ static gboolean red_channel_client_initable_init(GInitable *initable,
>  
>      core = red_channel_get_core_interface(self->priv->channel);
>      if (self->priv->stream)
> -        self->priv->stream->watch =
> +        self->priv->watch =
>              core->watch_add(core, self->priv->stream->socket,
>                              SPICE_WATCH_EVENT_READ,
>                              red_channel_client_event,
> @@ -1003,9 +1018,11 @@ void red_channel_client_destroy(RedChannelClient *rcc)
>  void red_channel_client_shutdown(RedChannelClient *rcc)
>  {
>      if (rcc->priv->stream && !rcc->priv->stream->shutdown) {
> -        SpiceCoreInterfaceInternal *core = red_channel_get_core_interface(rcc->priv->channel);
> -        core->watch_remove(core, rcc->priv->stream->watch);
> -        rcc->priv->stream->watch = NULL;
> +        if (rcc->priv->watch) {
> +            SpiceCoreInterfaceInternal *core = red_channel_get_core_interface(rcc->priv->channel);
> +            core->watch_remove(core, rcc->priv->watch);
> +            rcc->priv->watch = NULL;
> +        }
>          shutdown(rcc->priv->stream->socket, SHUT_RDWR);
>          rcc->priv->stream->shutdown = TRUE;
>      }
> @@ -1294,10 +1311,10 @@ void red_channel_client_push(RedChannelClient *rcc)
>          red_channel_client_send_item(rcc, pipe_item);
>      }
>      if (red_channel_client_no_item_being_sent(rcc) && g_queue_is_empty(&rcc->priv->pipe)
> -        && rcc->priv->stream->watch) {
> +        && rcc->priv->watch) {
>          SpiceCoreInterfaceInternal *core;
>          core = red_channel_get_core_interface(rcc->priv->channel);
> -        core->watch_update_mask(core, rcc->priv->stream->watch,
> +        core->watch_update_mask(core, rcc->priv->watch,
>                                  SPICE_WATCH_EVENT_READ);
>      }
>      rcc->priv->during_send = FALSE;
> @@ -1511,10 +1528,10 @@ static inline gboolean prepare_pipe_add(RedChannelClient *rcc, RedPipeItem *item
>          red_pipe_item_unref(item);
>          return FALSE;
>      }
> -    if (g_queue_is_empty(&rcc->priv->pipe) && rcc->priv->stream->watch) {
> +    if (g_queue_is_empty(&rcc->priv->pipe) && rcc->priv->watch) {
>          SpiceCoreInterfaceInternal *core;
>          core = red_channel_get_core_interface(rcc->priv->channel);
> -        core->watch_update_mask(core, rcc->priv->stream->watch,
> +        core->watch_update_mask(core, rcc->priv->watch,
>                                  SPICE_WATCH_EVENT_READ | SPICE_WATCH_EVENT_WRITE);
>      }
>      return TRUE;
> @@ -1678,9 +1695,9 @@ void red_channel_client_disconnect(RedChannelClient *rcc)
>      spice_printerr("rcc=%p (channel=%p type=%d id=%d)", rcc, channel,
>                     type, id);
>      red_channel_client_pipe_clear(rcc);
> -    if (rcc->priv->stream->watch) {
> -        core->watch_remove(core, rcc->priv->stream->watch);
> -        rcc->priv->stream->watch = NULL;
> +    if (rcc->priv->watch) {
> +        core->watch_remove(core, rcc->priv->watch);
> +        rcc->priv->watch = NULL;
>      }
>      if (rcc->priv->latency_monitor.timer) {
>          core->timer_remove(core, rcc->priv->latency_monitor.timer);
> -- 
> 2.13.5
> 
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/spice-devel


More information about the Spice-devel mailing list