Blame SOURCES/0028-channel-main-Use-heap-and-reference-counting-for-spi.patch

76100f
From 8f1147b4119f920b69eb9c577121cbd5ac1e1d70 Mon Sep 17 00:00:00 2001
76100f
From: Frediano Ziglio <freddy77@gmail.com>
76100f
Date: Mon, 10 Aug 2020 15:27:09 +0100
76100f
Subject: [PATCH 28/31] channel-main: Use heap and reference counting for
76100f
 spice_migrate
76100f
76100f
Don't use the stack, it will potentially disappear (see mig
76100f
variable in main_migrate_connect).
76100f
For instance channels use this structure when they are freed. As
76100f
the free is done in delayed mode the initial coroutine could be
76100f
ended releasing the stack and causing a segmentation fault.
76100f
76100f
This fixes https://bugzilla.redhat.com/show_bug.cgi?id=1867564.
76100f
76100f
Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
76100f
Acked-by: Uri Lublin <uril@redhat.com>
76100f
---
76100f
 src/channel-main.c | 110 ++++++++++++++++++++++++++++++++-------------
76100f
 1 file changed, 78 insertions(+), 32 deletions(-)
76100f
76100f
diff --git a/src/channel-main.c b/src/channel-main.c
76100f
index 79fe63c..8caf727 100644
76100f
--- a/src/channel-main.c
76100f
+++ b/src/channel-main.c
76100f
@@ -123,6 +123,7 @@ struct spice_migrate {
76100f
     struct coroutine *from;
76100f
     SpiceMigrationDstInfo *info;
76100f
     SpiceSession *session;
76100f
+    int ref_count;
76100f
     guint nchannels;
76100f
     SpiceChannel *src_channel;
76100f
     SpiceChannel *dst_channel;
76100f
@@ -175,8 +176,8 @@ static void channel_set_handlers(SpiceChannelClass *klass);
76100f
 static void agent_send_msg_queue(SpiceMainChannel *channel);
76100f
 static void agent_free_msg_queue(SpiceMainChannel *channel);
76100f
 static void migrate_channel_event_cb(SpiceChannel *channel, SpiceChannelEvent event,
76100f
-                                     gpointer data);
76100f
-static gboolean main_migrate_handshake_done(gpointer data);
76100f
+                                     spice_migrate *mig);
76100f
+static gboolean main_migrate_handshake_done(spice_migrate *mig);
76100f
 static void spice_main_channel_send_migration_handshake(SpiceChannel *channel);
76100f
 static void file_xfer_flushed(SpiceMainChannel *channel, gboolean success);
76100f
 static void file_xfer_read_async_cb(GObject *source_object,
76100f
@@ -193,6 +194,7 @@ static void file_transfer_operation_task_finished(SpiceFileTransferTask *xfer_ta
76100f
                                                   GError *error,
76100f
                                                   gpointer userdata);
76100f
 static void file_transfer_operation_send_progress(SpiceFileTransferTask *xfer_task);
76100f
+static void spice_migrate_unref(spice_migrate *mig);
76100f
 
76100f
 /* ------------------------------------------------------------------ */
76100f
 
76100f
@@ -387,6 +389,7 @@ static void spice_main_channel_finalize(GObject *obj)
76100f
 {
76100f
     SpiceMainChannelPrivate *c = SPICE_MAIN_CHANNEL(obj)->priv;
76100f
 
76100f
+    spice_migrate_unref(c->migrate_data);
76100f
     g_free(c->agent_msg_data);
76100f
     agent_free_msg_queue(SPICE_MAIN_CHANNEL(obj));
76100f
 
76100f
@@ -2242,11 +2245,50 @@ static void main_handle_agent_token(SpiceChannel *channel, SpiceMsgIn *in)
76100f
     agent_send_msg_queue(SPICE_MAIN_CHANNEL(channel));
76100f
 }
76100f
 
76100f
+static spice_migrate*
76100f
+spice_migrate_ref(spice_migrate *mig)
76100f
+{
76100f
+    if (mig != NULL) {
76100f
+        mig->ref_count++;
76100f
+    }
76100f
+    return mig;
76100f
+}
76100f
+
76100f
+static void
76100f
+spice_migrate_unref(spice_migrate *mig)
76100f
+{
76100f
+    if (mig != NULL && --mig->ref_count == 0) {
76100f
+        g_free(mig);
76100f
+    }
76100f
+}
76100f
+
76100f
+static inline void
76100f
+spice_migrate_idle_add(gboolean (*func)(spice_migrate *mig), spice_migrate *mig)
76100f
+{
76100f
+    g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, (GSourceFunc) func, spice_migrate_ref(mig),
76100f
+                    (GDestroyNotify) spice_migrate_unref);
76100f
+}
76100f
+
76100f
+static void
76100f
+spice_migrate_closure_unref(spice_migrate *mig, GClosure *closure)
76100f
+{
76100f
+    spice_migrate_unref(mig);
76100f
+}
76100f
+
76100f
+static gulong
76100f
+spice_migrate_signal_connect(gpointer instance, const gchar *detailed_signal,
76100f
+                             GCallback func, spice_migrate *mig)
76100f
+{
76100f
+    return g_signal_connect_data(instance, detailed_signal, func, spice_migrate_ref(mig),
76100f
+                                 (GClosureNotify) spice_migrate_closure_unref,
76100f
+                                 (GConnectFlags) 0);
76100f
+}
76100f
+
76100f
 /* main context */
76100f
-static void migrate_channel_new_cb(SpiceSession *s, SpiceChannel *channel, gpointer data)
76100f
+static void migrate_channel_new_cb(SpiceSession *s, SpiceChannel *channel, spice_migrate *mig)
76100f
 {
76100f
-    g_signal_connect(channel, "channel-event",
76100f
-                     G_CALLBACK(migrate_channel_event_cb), data);
76100f
+    spice_migrate_signal_connect(channel, "channel-event",
76100f
+                                 G_CALLBACK(migrate_channel_event_cb), mig);
76100f
 }
76100f
 
76100f
 static void
76100f
@@ -2267,7 +2309,7 @@ static void spice_main_channel_send_migration_handshake(SpiceChannel *channel)
76100f
 
76100f
     if (!spice_channel_test_capability(channel, SPICE_MAIN_CAP_SEAMLESS_MIGRATE)) {
76100f
         c->migrate_data->do_seamless = false;
76100f
-        g_idle_add(main_migrate_handshake_done, c->migrate_data);
76100f
+        spice_migrate_idle_add(main_migrate_handshake_done, c->migrate_data);
76100f
     } else {
76100f
         SpiceMsgcMainMigrateDstDoSeamless msg_data;
76100f
         SpiceMsgOut *msg_out;
76100f
@@ -2282,13 +2324,12 @@ static void spice_main_channel_send_migration_handshake(SpiceChannel *channel)
76100f
 
76100f
 /* main context */
76100f
 static void migrate_channel_event_cb(SpiceChannel *channel, SpiceChannelEvent event,
76100f
-                                     gpointer data)
76100f
+                                     spice_migrate *mig)
76100f
 {
76100f
-    spice_migrate *mig = data;
76100f
     SpiceChannelPrivate  *c = SPICE_CHANNEL(channel)->priv;
76100f
 
76100f
     g_return_if_fail(mig->nchannels > 0);
76100f
-    g_signal_handlers_disconnect_by_func(channel, migrate_channel_event_cb, data);
76100f
+    g_signal_handlers_disconnect_by_func(channel, migrate_channel_event_cb, mig);
76100f
 
76100f
     switch (event) {
76100f
     case SPICE_CHANNEL_OPENED:
76100f
@@ -2299,7 +2340,8 @@ static void migrate_channel_event_cb(SpiceChannel *channel, SpiceChannelEvent ev
76100f
 
76100f
                 c->state = SPICE_CHANNEL_STATE_MIGRATION_HANDSHAKE;
76100f
                 mig->dst_channel = channel;
76100f
-                main_priv->migrate_data = mig;
76100f
+                spice_migrate_unref(main_priv->migrate_data);
76100f
+                main_priv->migrate_data = spice_migrate_ref(mig);
76100f
             } else {
76100f
                 c->state = SPICE_CHANNEL_STATE_MIGRATING;
76100f
                 mig->nchannels--;
76100f
@@ -2332,9 +2374,8 @@ static void migrate_channel_event_cb(SpiceChannel *channel, SpiceChannelEvent ev
76100f
 }
76100f
 
76100f
 /* main context */
76100f
-static gboolean main_migrate_handshake_done(gpointer data)
76100f
+static gboolean main_migrate_handshake_done(spice_migrate *mig)
76100f
 {
76100f
-    spice_migrate *mig = data;
76100f
     SpiceChannelPrivate  *c = SPICE_CHANNEL(mig->dst_channel)->priv;
76100f
 
76100f
     g_return_val_if_fail(c->channel_type == SPICE_CHANNEL_MAIN, FALSE);
76100f
@@ -2348,9 +2389,8 @@ static gboolean main_migrate_handshake_done(gpointer data)
76100f
 }
76100f
 
76100f
 /* main context */
76100f
-static gboolean migrate_connect(gpointer data)
76100f
+static gboolean migrate_connect(spice_migrate *mig)
76100f
 {
76100f
-    spice_migrate *mig = data;
76100f
     SpiceChannelPrivate  *c;
76100f
     int port, sport;
76100f
     const char *host;
76100f
@@ -2393,8 +2433,8 @@ static gboolean migrate_connect(gpointer data)
76100f
     g_object_set(mig->session, "host", host, NULL);
76100f
     spice_session_set_port(mig->session, port, FALSE);
76100f
     spice_session_set_port(mig->session, sport, TRUE);
76100f
-    g_signal_connect(mig->session, "channel-new",
76100f
-                     G_CALLBACK(migrate_channel_new_cb), mig);
76100f
+    spice_migrate_signal_connect(mig->session, "channel-new",
76100f
+                                 G_CALLBACK(migrate_channel_new_cb), mig);
76100f
 
76100f
     g_signal_emit(mig->src_channel, signals[SPICE_MIGRATION_STARTED], 0,
76100f
                   mig->session);
76100f
@@ -2414,50 +2454,56 @@ static void main_migrate_connect(SpiceChannel *channel,
76100f
 {
76100f
     SpiceMainChannelPrivate *main_priv = SPICE_MAIN_CHANNEL(channel)->priv;
76100f
     int reply_type = SPICE_MSGC_MAIN_MIGRATE_CONNECT_ERROR;
76100f
-    spice_migrate mig = { 0, };
76100f
+    spice_migrate *mig;
76100f
     SpiceMsgOut *out;
76100f
     SpiceSession *session;
76100f
 
76100f
-    mig.src_channel = channel;
76100f
-    mig.info = dst_info;
76100f
-    mig.from = coroutine_self();
76100f
-    mig.do_seamless = do_seamless;
76100f
-    mig.src_mig_version = src_mig_version;
76100f
+    mig = spice_new0(spice_migrate, 1);
76100f
+    mig->ref_count = 1;
76100f
+    mig->src_channel = channel;
76100f
+    mig->info = dst_info;
76100f
+    mig->from = coroutine_self();
76100f
+    mig->do_seamless = do_seamless;
76100f
+    mig->src_mig_version = src_mig_version;
76100f
 
76100f
     CHANNEL_DEBUG(channel, "migrate connect");
76100f
     session = spice_channel_get_session(channel);
76100f
-    mig.session = spice_session_new_from_session(session);
76100f
-    if (mig.session == NULL)
76100f
+    mig->session = spice_session_new_from_session(session);
76100f
+    if (mig->session == NULL) {
76100f
         goto end;
76100f
-    if (!spice_session_set_migration_session(session, mig.session))
76100f
+    }
76100f
+    if (!spice_session_set_migration_session(session, mig->session)) {
76100f
         goto end;
76100f
+    }
76100f
 
76100f
-    main_priv->migrate_data = &mig;
76100f
+    spice_migrate_unref(main_priv->migrate_data);
76100f
+    main_priv->migrate_data = spice_migrate_ref(mig);
76100f
 
76100f
     /* no need to track idle, call is sync for this coroutine */
76100f
-    g_idle_add(migrate_connect, &mig;;
76100f
+    spice_migrate_idle_add(migrate_connect, mig);
76100f
 
76100f
     /* switch to main loop and wait for connections */
76100f
     coroutine_yield(NULL);
76100f
 
76100f
-    if (mig.nchannels != 0) {
76100f
+    if (mig->nchannels != 0) {
76100f
         CHANNEL_DEBUG(channel, "migrate failed: some channels failed to connect");
76100f
         spice_session_abort_migration(session);
76100f
     } else {
76100f
-        if (mig.do_seamless) {
76100f
+        if (mig->do_seamless) {
76100f
             SPICE_DEBUG("migration (seamless): connections all ok");
76100f
             reply_type = SPICE_MSGC_MAIN_MIGRATE_CONNECTED_SEAMLESS;
76100f
         } else {
76100f
             SPICE_DEBUG("migration (semi-seamless): connections all ok");
76100f
             reply_type = SPICE_MSGC_MAIN_MIGRATE_CONNECTED;
76100f
         }
76100f
-        spice_session_start_migrating(session, mig.do_seamless);
76100f
+        spice_session_start_migrating(session, mig->do_seamless);
76100f
     }
76100f
 
76100f
 end:
76100f
     CHANNEL_DEBUG(channel, "migrate connect reply %d", reply_type);
76100f
     out = spice_msg_out_new(channel, reply_type);
76100f
     spice_msg_out_send(out);
76100f
+    spice_migrate_unref(mig);
76100f
 }
76100f
 
76100f
 /* coroutine context */
76100f
@@ -2489,7 +2535,7 @@ static void main_handle_migrate_dst_seamless_ack(SpiceChannel *channel, SpiceMsg
76100f
 
76100f
     g_return_if_fail(c->state == SPICE_CHANNEL_STATE_MIGRATION_HANDSHAKE);
76100f
     main_priv->migrate_data->do_seamless = true;
76100f
-    g_idle_add(main_migrate_handshake_done, main_priv->migrate_data);
76100f
+    spice_migrate_idle_add(main_migrate_handshake_done, main_priv->migrate_data);
76100f
 }
76100f
 
76100f
 static void main_handle_migrate_dst_seamless_nack(SpiceChannel *channel, SpiceMsgIn *in)
76100f
@@ -2501,7 +2547,7 @@ static void main_handle_migrate_dst_seamless_nack(SpiceChannel *channel, SpiceMs
76100f
 
76100f
     g_return_if_fail(c->state == SPICE_CHANNEL_STATE_MIGRATION_HANDSHAKE);
76100f
     main_priv->migrate_data->do_seamless = false;
76100f
-    g_idle_add(main_migrate_handshake_done, main_priv->migrate_data);
76100f
+    spice_migrate_idle_add(main_migrate_handshake_done, main_priv->migrate_data);
76100f
 }
76100f
 
76100f
 /* main context */
76100f
-- 
76100f
2.28.0
76100f