a2dp: Fix crash if setup is freed while reconfiguring
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Mon, 30 Nov 2020 19:16:11 +0000 (11:16 -0800)
committerAyush Garg <ayush.garg@samsung.com>
Fri, 11 Mar 2022 13:38:34 +0000 (19:08 +0530)
This fixes the crash reported on:

https://github.com/bluez/bluez/issues/60
Signed-off-by: Anuj Jain <anuj01.jain@samsung.com>
Signed-off-by: Ayush Garg <ayush.garg@samsung.com>
profiles/audio/a2dp.c

index e05e939..d952f7c 100644 (file)
@@ -113,6 +113,7 @@ struct a2dp_setup {
        gboolean start;
        GSList *cb;
        GIOChannel *io;
+       guint id;
        int ref;
 };
 
@@ -215,6 +216,9 @@ static void setup_free(struct a2dp_setup *s)
                g_io_channel_unref(s->io);
        }
 
+       if (s->id)
+               g_source_remove(s->id);
+
        queue_destroy(s->eps, NULL);
 
        setups = g_slist_remove(setups, s);
@@ -1244,6 +1248,8 @@ static gboolean a2dp_reconfigure(gpointer data)
        struct avdtp_media_codec_capability *rsep_codec;
        struct avdtp_service_capability *cap;
 
+       setup->id = 0;
+
        if (!sep->lsep) {
                error("no valid local SEP");
                posix_err = -EINVAL;
@@ -1280,6 +1286,20 @@ failed:
        return FALSE;
 }
 
+static bool setup_reconfigure(struct a2dp_setup *setup)
+{
+       if (!setup->reconfigure || setup->id)
+               return false;
+
+       DBG("%p", setup);
+
+       setup->id = g_timeout_add(RECONFIGURE_TIMEOUT, a2dp_reconfigure, setup);
+
+       setup->reconfigure = FALSE;
+
+       return true;
+}
+
 static struct a2dp_remote_sep *get_remote_sep(struct a2dp_channel *chan,
                                                struct avdtp_stream *stream)
 {
@@ -1323,8 +1343,7 @@ static void close_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
        if (!setup->rsep)
                setup->rsep = get_remote_sep(setup->chan, stream);
 
-       if (setup->reconfigure)
-               g_timeout_add(RECONFIGURE_TIMEOUT, a2dp_reconfigure, setup);
+       setup_reconfigure(setup);
 }
 
 static void abort_ind(struct avdtp *session, struct avdtp_local_sep *sep,
@@ -1368,10 +1387,8 @@ static void abort_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
        if (!setup)
                return;
 
-       if (setup->reconfigure) {
-               g_timeout_add(RECONFIGURE_TIMEOUT, a2dp_reconfigure, setup);
+       if (setup_reconfigure(setup))
                return;
-       }
 
        setup_unref(setup);
 }