avdtp: Fix possible unbalance ref count
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Mon, 22 Jun 2020 16:21:27 +0000 (09:21 -0700)
committerAyush Garg <ayush.garg@samsung.com>
Mon, 12 Apr 2021 09:00:49 +0000 (14:30 +0530)
It has been reported that under some unknown circuntances the reference
number of AVDTP sessions can go bellow 0 (loop around) causing a crash:

bluetoothd[5633]: profiles/audio/avdtp.c:avdtp_ref() 0x56a882b8a500: ref=-2101995743
bluetoothd[5633]: profiles/audio/a2dp.c:discover_cb() err (nil)
WARNING crash_reporter[10707]: [user] Received crash notification for bluetoothd[5633]

Signed-off-by: Anuj Jain <anuj01.jain@samsung.com>
Signed-off-by: Ayush Garg <ayush.garg@samsung.com>
profiles/audio/avdtp.c

index 23fa047..9cfe5a1 100644 (file)
@@ -1383,9 +1383,15 @@ static void sep_free(gpointer data)
 
 static void remove_disconnect_timer(struct avdtp *session)
 {
+       if (!session->dc_timer)
+               return;
+
        g_source_remove(session->dc_timer);
        session->dc_timer = 0;
        session->stream_setup = FALSE;
+
+       /* Release disconnect timer reference */
+       avdtp_unref(session);
 }
 
 static void avdtp_free(void *data)
@@ -1406,9 +1412,6 @@ static void avdtp_free(void *data)
                session->io_id = 0;
        }
 
-       if (session->dc_timer)
-               remove_disconnect_timer(session);
-
        if (session->req)
                pending_req_free(session->req);
 
@@ -1493,13 +1496,13 @@ static gboolean disconnect_timeout(gpointer user_data)
        service = btd_device_get_service(session->device, A2DP_SINK_UUID);
        if (service && stream_setup) {
                sink_setup_stream(service, session);
-               return FALSE;
+               goto done;
        }
 
        service = btd_device_get_service(session->device, A2DP_SOURCE_UUID);
        if (service && stream_setup) {
                source_setup_stream(service, session);
-               return FALSE;
+               goto done;
        }
 
 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
@@ -1515,6 +1518,10 @@ static gboolean disconnect_timeout(gpointer user_data)
 
        connection_lost(session, ETIMEDOUT);
 
+done:
+       /* Release disconnect timer reference */
+       avdtp_unref(session);
+
 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
        if (device)
                g_timeout_add(100,
@@ -1560,8 +1567,8 @@ static void set_disconnect_timer(struct avdtp *session)
 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
        char name[6];
 #endif
-       if (session->dc_timer)
-               remove_disconnect_timer(session);
+       /* Take a ref while disconnect timer is active */
+       avdtp_ref(session);
 
 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
        device_get_name(session->device, name, sizeof(name));
@@ -1630,8 +1637,7 @@ struct avdtp *avdtp_ref(struct avdtp *session)
 {
        session->ref++;
        DBG("%p: ref=%d", session, session->ref);
-       if (session->dc_timer)
-               remove_disconnect_timer(session);
+       remove_disconnect_timer(session);
        return session;
 }