[Spice-commits] 2 commits - src/channel-main.c

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Wed Sep 16 11:43:24 UTC 2020


 src/channel-main.c |  123 +++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 88 insertions(+), 35 deletions(-)

New commits:
commit ab42be2b00d12d0bc98c6ddea08a7f969e83b2ac
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Mon Aug 10 15:35:26 2020 +0100

    channel-main: Copy SpiceMigrationDstInfo into spice_migrate
    
    The message could disappear while the structure is used.
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Uri Lublin <uril at redhat.com>

diff --git a/src/channel-main.c b/src/channel-main.c
index 8caf727..5f81975 100644
--- a/src/channel-main.c
+++ b/src/channel-main.c
@@ -121,7 +121,7 @@ struct _SpiceMainChannelPrivate  {
 
 struct spice_migrate {
     struct coroutine *from;
-    SpiceMigrationDstInfo *info;
+    SpiceMigrationDstInfo info;
     SpiceSession *session;
     int ref_count;
     guint nchannels;
@@ -2258,6 +2258,8 @@ static void
 spice_migrate_unref(spice_migrate *mig)
 {
     if (mig != NULL && --mig->ref_count == 0) {
+        g_free(mig->info.host_data);
+        g_free(mig->info.cert_subject_data);
         g_free(mig);
     }
 }
@@ -2396,7 +2398,6 @@ static gboolean migrate_connect(spice_migrate *mig)
     const char *host;
 
     g_return_val_if_fail(mig != NULL, FALSE);
-    g_return_val_if_fail(mig->info != NULL, FALSE);
     g_return_val_if_fail(mig->nchannels == 0, FALSE);
     c = SPICE_CHANNEL(mig->src_channel)->priv;
     g_return_val_if_fail(c != NULL, FALSE);
@@ -2404,7 +2405,7 @@ static gboolean migrate_connect(spice_migrate *mig)
 
     spice_session_set_migration_state(mig->session, SPICE_SESSION_MIGRATION_CONNECTING);
 
-    SpiceMigrationDstInfo *info = mig->info;
+    SpiceMigrationDstInfo *info = &mig->info;
     SPICE_DEBUG("migrate_begin %u %s %d %d",
                 info->host_size, info->host_data, info->port, info->sport);
     port = info->port;
@@ -2461,7 +2462,13 @@ static void main_migrate_connect(SpiceChannel *channel,
     mig = spice_new0(spice_migrate, 1);
     mig->ref_count = 1;
     mig->src_channel = channel;
-    mig->info = dst_info;
+    mig->info = *dst_info;
+    if (dst_info->host_data) {
+        mig->info.host_data = (void *) g_strdup((char*) dst_info->host_data);
+    }
+    if (dst_info->cert_subject_data) {
+        mig->info.cert_subject_data = (void *) g_strdup((char*) dst_info->cert_subject_data);
+    }
     mig->from = coroutine_self();
     mig->do_seamless = do_seamless;
     mig->src_mig_version = src_mig_version;
commit 8f1147b4119f920b69eb9c577121cbd5ac1e1d70
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Mon Aug 10 15:27:09 2020 +0100

    channel-main: Use heap and reference counting for spice_migrate
    
    Don't use the stack, it will potentially disappear (see mig
    variable in main_migrate_connect).
    For instance channels use this structure when they are freed. As
    the free is done in delayed mode the initial coroutine could be
    ended releasing the stack and causing a segmentation fault.
    
    This fixes https://bugzilla.redhat.com/show_bug.cgi?id=1867564.
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Uri Lublin <uril at redhat.com>

diff --git a/src/channel-main.c b/src/channel-main.c
index 79fe63c..8caf727 100644
--- a/src/channel-main.c
+++ b/src/channel-main.c
@@ -123,6 +123,7 @@ struct spice_migrate {
     struct coroutine *from;
     SpiceMigrationDstInfo *info;
     SpiceSession *session;
+    int ref_count;
     guint nchannels;
     SpiceChannel *src_channel;
     SpiceChannel *dst_channel;
@@ -175,8 +176,8 @@ static void channel_set_handlers(SpiceChannelClass *klass);
 static void agent_send_msg_queue(SpiceMainChannel *channel);
 static void agent_free_msg_queue(SpiceMainChannel *channel);
 static void migrate_channel_event_cb(SpiceChannel *channel, SpiceChannelEvent event,
-                                     gpointer data);
-static gboolean main_migrate_handshake_done(gpointer data);
+                                     spice_migrate *mig);
+static gboolean main_migrate_handshake_done(spice_migrate *mig);
 static void spice_main_channel_send_migration_handshake(SpiceChannel *channel);
 static void file_xfer_flushed(SpiceMainChannel *channel, gboolean success);
 static void file_xfer_read_async_cb(GObject *source_object,
@@ -193,6 +194,7 @@ static void file_transfer_operation_task_finished(SpiceFileTransferTask *xfer_ta
                                                   GError *error,
                                                   gpointer userdata);
 static void file_transfer_operation_send_progress(SpiceFileTransferTask *xfer_task);
+static void spice_migrate_unref(spice_migrate *mig);
 
 /* ------------------------------------------------------------------ */
 
@@ -387,6 +389,7 @@ static void spice_main_channel_finalize(GObject *obj)
 {
     SpiceMainChannelPrivate *c = SPICE_MAIN_CHANNEL(obj)->priv;
 
+    spice_migrate_unref(c->migrate_data);
     g_free(c->agent_msg_data);
     agent_free_msg_queue(SPICE_MAIN_CHANNEL(obj));
 
@@ -2242,11 +2245,50 @@ static void main_handle_agent_token(SpiceChannel *channel, SpiceMsgIn *in)
     agent_send_msg_queue(SPICE_MAIN_CHANNEL(channel));
 }
 
+static spice_migrate*
+spice_migrate_ref(spice_migrate *mig)
+{
+    if (mig != NULL) {
+        mig->ref_count++;
+    }
+    return mig;
+}
+
+static void
+spice_migrate_unref(spice_migrate *mig)
+{
+    if (mig != NULL && --mig->ref_count == 0) {
+        g_free(mig);
+    }
+}
+
+static inline void
+spice_migrate_idle_add(gboolean (*func)(spice_migrate *mig), spice_migrate *mig)
+{
+    g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, (GSourceFunc) func, spice_migrate_ref(mig),
+                    (GDestroyNotify) spice_migrate_unref);
+}
+
+static void
+spice_migrate_closure_unref(spice_migrate *mig, GClosure *closure)
+{
+    spice_migrate_unref(mig);
+}
+
+static gulong
+spice_migrate_signal_connect(gpointer instance, const gchar *detailed_signal,
+                             GCallback func, spice_migrate *mig)
+{
+    return g_signal_connect_data(instance, detailed_signal, func, spice_migrate_ref(mig),
+                                 (GClosureNotify) spice_migrate_closure_unref,
+                                 (GConnectFlags) 0);
+}
+
 /* main context */
-static void migrate_channel_new_cb(SpiceSession *s, SpiceChannel *channel, gpointer data)
+static void migrate_channel_new_cb(SpiceSession *s, SpiceChannel *channel, spice_migrate *mig)
 {
-    g_signal_connect(channel, "channel-event",
-                     G_CALLBACK(migrate_channel_event_cb), data);
+    spice_migrate_signal_connect(channel, "channel-event",
+                                 G_CALLBACK(migrate_channel_event_cb), mig);
 }
 
 static void
@@ -2267,7 +2309,7 @@ static void spice_main_channel_send_migration_handshake(SpiceChannel *channel)
 
     if (!spice_channel_test_capability(channel, SPICE_MAIN_CAP_SEAMLESS_MIGRATE)) {
         c->migrate_data->do_seamless = false;
-        g_idle_add(main_migrate_handshake_done, c->migrate_data);
+        spice_migrate_idle_add(main_migrate_handshake_done, c->migrate_data);
     } else {
         SpiceMsgcMainMigrateDstDoSeamless msg_data;
         SpiceMsgOut *msg_out;
@@ -2282,13 +2324,12 @@ static void spice_main_channel_send_migration_handshake(SpiceChannel *channel)
 
 /* main context */
 static void migrate_channel_event_cb(SpiceChannel *channel, SpiceChannelEvent event,
-                                     gpointer data)
+                                     spice_migrate *mig)
 {
-    spice_migrate *mig = data;
     SpiceChannelPrivate  *c = SPICE_CHANNEL(channel)->priv;
 
     g_return_if_fail(mig->nchannels > 0);
-    g_signal_handlers_disconnect_by_func(channel, migrate_channel_event_cb, data);
+    g_signal_handlers_disconnect_by_func(channel, migrate_channel_event_cb, mig);
 
     switch (event) {
     case SPICE_CHANNEL_OPENED:
@@ -2299,7 +2340,8 @@ static void migrate_channel_event_cb(SpiceChannel *channel, SpiceChannelEvent ev
 
                 c->state = SPICE_CHANNEL_STATE_MIGRATION_HANDSHAKE;
                 mig->dst_channel = channel;
-                main_priv->migrate_data = mig;
+                spice_migrate_unref(main_priv->migrate_data);
+                main_priv->migrate_data = spice_migrate_ref(mig);
             } else {
                 c->state = SPICE_CHANNEL_STATE_MIGRATING;
                 mig->nchannels--;
@@ -2332,9 +2374,8 @@ static void migrate_channel_event_cb(SpiceChannel *channel, SpiceChannelEvent ev
 }
 
 /* main context */
-static gboolean main_migrate_handshake_done(gpointer data)
+static gboolean main_migrate_handshake_done(spice_migrate *mig)
 {
-    spice_migrate *mig = data;
     SpiceChannelPrivate  *c = SPICE_CHANNEL(mig->dst_channel)->priv;
 
     g_return_val_if_fail(c->channel_type == SPICE_CHANNEL_MAIN, FALSE);
@@ -2348,9 +2389,8 @@ static gboolean main_migrate_handshake_done(gpointer data)
 }
 
 /* main context */
-static gboolean migrate_connect(gpointer data)
+static gboolean migrate_connect(spice_migrate *mig)
 {
-    spice_migrate *mig = data;
     SpiceChannelPrivate  *c;
     int port, sport;
     const char *host;
@@ -2393,8 +2433,8 @@ static gboolean migrate_connect(gpointer data)
     g_object_set(mig->session, "host", host, NULL);
     spice_session_set_port(mig->session, port, FALSE);
     spice_session_set_port(mig->session, sport, TRUE);
-    g_signal_connect(mig->session, "channel-new",
-                     G_CALLBACK(migrate_channel_new_cb), mig);
+    spice_migrate_signal_connect(mig->session, "channel-new",
+                                 G_CALLBACK(migrate_channel_new_cb), mig);
 
     g_signal_emit(mig->src_channel, signals[SPICE_MIGRATION_STARTED], 0,
                   mig->session);
@@ -2414,50 +2454,56 @@ static void main_migrate_connect(SpiceChannel *channel,
 {
     SpiceMainChannelPrivate *main_priv = SPICE_MAIN_CHANNEL(channel)->priv;
     int reply_type = SPICE_MSGC_MAIN_MIGRATE_CONNECT_ERROR;
-    spice_migrate mig = { 0, };
+    spice_migrate *mig;
     SpiceMsgOut *out;
     SpiceSession *session;
 
-    mig.src_channel = channel;
-    mig.info = dst_info;
-    mig.from = coroutine_self();
-    mig.do_seamless = do_seamless;
-    mig.src_mig_version = src_mig_version;
+    mig = spice_new0(spice_migrate, 1);
+    mig->ref_count = 1;
+    mig->src_channel = channel;
+    mig->info = dst_info;
+    mig->from = coroutine_self();
+    mig->do_seamless = do_seamless;
+    mig->src_mig_version = src_mig_version;
 
     CHANNEL_DEBUG(channel, "migrate connect");
     session = spice_channel_get_session(channel);
-    mig.session = spice_session_new_from_session(session);
-    if (mig.session == NULL)
+    mig->session = spice_session_new_from_session(session);
+    if (mig->session == NULL) {
         goto end;
-    if (!spice_session_set_migration_session(session, mig.session))
+    }
+    if (!spice_session_set_migration_session(session, mig->session)) {
         goto end;
+    }
 
-    main_priv->migrate_data = &mig;
+    spice_migrate_unref(main_priv->migrate_data);
+    main_priv->migrate_data = spice_migrate_ref(mig);
 
     /* no need to track idle, call is sync for this coroutine */
-    g_idle_add(migrate_connect, &mig);
+    spice_migrate_idle_add(migrate_connect, mig);
 
     /* switch to main loop and wait for connections */
     coroutine_yield(NULL);
 
-    if (mig.nchannels != 0) {
+    if (mig->nchannels != 0) {
         CHANNEL_DEBUG(channel, "migrate failed: some channels failed to connect");
         spice_session_abort_migration(session);
     } else {
-        if (mig.do_seamless) {
+        if (mig->do_seamless) {
             SPICE_DEBUG("migration (seamless): connections all ok");
             reply_type = SPICE_MSGC_MAIN_MIGRATE_CONNECTED_SEAMLESS;
         } else {
             SPICE_DEBUG("migration (semi-seamless): connections all ok");
             reply_type = SPICE_MSGC_MAIN_MIGRATE_CONNECTED;
         }
-        spice_session_start_migrating(session, mig.do_seamless);
+        spice_session_start_migrating(session, mig->do_seamless);
     }
 
 end:
     CHANNEL_DEBUG(channel, "migrate connect reply %d", reply_type);
     out = spice_msg_out_new(channel, reply_type);
     spice_msg_out_send(out);
+    spice_migrate_unref(mig);
 }
 
 /* coroutine context */
@@ -2489,7 +2535,7 @@ static void main_handle_migrate_dst_seamless_ack(SpiceChannel *channel, SpiceMsg
 
     g_return_if_fail(c->state == SPICE_CHANNEL_STATE_MIGRATION_HANDSHAKE);
     main_priv->migrate_data->do_seamless = true;
-    g_idle_add(main_migrate_handshake_done, main_priv->migrate_data);
+    spice_migrate_idle_add(main_migrate_handshake_done, main_priv->migrate_data);
 }
 
 static void main_handle_migrate_dst_seamless_nack(SpiceChannel *channel, SpiceMsgIn *in)
@@ -2501,7 +2547,7 @@ static void main_handle_migrate_dst_seamless_nack(SpiceChannel *channel, SpiceMs
 
     g_return_if_fail(c->state == SPICE_CHANNEL_STATE_MIGRATION_HANDSHAKE);
     main_priv->migrate_data->do_seamless = false;
-    g_idle_add(main_migrate_handshake_done, main_priv->migrate_data);
+    spice_migrate_idle_add(main_migrate_handshake_done, main_priv->migrate_data);
 }
 
 /* main context */


More information about the Spice-commits mailing list