From 2579cb5aeee1ea4572d17672d80afe8ba6a7bd47 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Mon, 22 Jun 2020 09:21:27 -0700 Subject: [PATCH] avdtp: Fix possible unbalance ref count 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] --- profiles/audio/avdtp.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c index e5193f79b..782268c08 100644 --- a/profiles/audio/avdtp.c +++ b/profiles/audio/avdtp.c @@ -1064,9 +1064,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) @@ -1087,9 +1093,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); @@ -1136,24 +1139,28 @@ 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; } connection_lost(session, ETIMEDOUT); +done: + /* Release disconnect timer reference */ + avdtp_unref(session); + return FALSE; } static void set_disconnect_timer(struct avdtp *session) { - if (session->dc_timer) - remove_disconnect_timer(session); + /* Take a ref while disconnect timer is active */ + avdtp_ref(session); DBG("timeout %d", session->dc_timeout); @@ -1195,8 +1202,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; } -- 2.47.3