summaryrefslogtreecommitdiff
path: root/android/avctp.c
diff options
context:
space:
mode:
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2015-03-26 16:14:38 +0200
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2015-03-26 21:57:56 +0200
commit06a543ceceeda7ece3246d338b2b95727a116979 (patch)
tree8c27baf480730ee13ade7575611afe3eed9f779c /android/avctp.c
parent54baf9adb66b42735df992943364d8220caaef88 (diff)
downloadbluez-06a543ceceeda7ece3246d338b2b95727a116979.tar.gz
android/avctp: Fix crashes caused by re-entrant calls
This make sure that while processing a PDU the session callbacks are not able to destroy the session causing crashes.
Diffstat (limited to 'android/avctp.c')
-rw-r--r--android/avctp.c74
1 files changed, 50 insertions, 24 deletions
diff --git a/android/avctp.c b/android/avctp.c
index 758dbd4ed..d1d2f9596 100644
--- a/android/avctp.c
+++ b/android/avctp.c
@@ -162,6 +162,7 @@ struct key_pressed {
};
struct avctp {
+ unsigned int ref;
int uinput;
unsigned int passthrough_id;
@@ -708,6 +709,47 @@ static gboolean process_queue(void *user_data)
}
+static struct avctp *avctp_ref(struct avctp *session)
+{
+ __sync_fetch_and_add(&session->ref, 1);
+
+ DBG("%p: ref=%d", session, session->ref);
+
+ return session;
+}
+
+static void avctp_unref(struct avctp *session)
+{
+ DBG("%p: ref=%d", session, session->ref);
+
+ if (__sync_sub_and_fetch(&session->ref, 1))
+ return;
+
+ if (session->browsing)
+ avctp_channel_destroy(session->browsing);
+
+ if (session->control)
+ avctp_channel_destroy(session->control);
+
+ if (session->destroy)
+ session->destroy(session->data);
+
+ g_free(session->handler);
+
+ if (session->key.timer > 0)
+ g_source_remove(session->key.timer);
+
+ if (session->uinput >= 0) {
+ DBG("AVCTP: closing uinput");
+
+ ioctl(session->uinput, UI_DEV_DESTROY);
+ close(session->uinput);
+ session->uinput = -1;
+ }
+
+ g_free(session);
+}
+
static void control_response(struct avctp_channel *control,
struct avctp_header *avctp,
struct avc_header *avc,
@@ -740,6 +782,8 @@ static void control_response(struct avctp_channel *control,
if (p->transaction != avctp->transaction)
continue;
+ avctp_ref(control->session);
+
if (req->func && req->func(control->session, avc->code,
avc->subunit_type,
operands, operand_count,
@@ -749,6 +793,8 @@ static void control_response(struct avctp_channel *control,
control->processed = g_slist_remove(control->processed, p);
pending_destroy(p, NULL);
+ avctp_unref(control->session);
+
return;
}
}
@@ -784,6 +830,8 @@ static void browsing_response(struct avctp_channel *browsing,
if (p->transaction != avctp->transaction)
continue;
+ avctp_ref(browsing->session);
+
if (req->func && req->func(browsing->session, operands,
operand_count, req->user_data))
return;
@@ -1563,7 +1611,7 @@ struct avctp *avctp_new(int fd, size_t imtu, size_t omtu, uint16_t version)
control->watch = g_io_add_watch(session->control->io, cond,
(GIOFunc) session_cb, session);
- return session;
+ return avctp_ref(session);
}
int avctp_connect_browsing(struct avctp *session, int fd, size_t imtu,
@@ -1599,27 +1647,5 @@ void avctp_shutdown(struct avctp *session)
if (!session)
return;
- if (session->browsing)
- avctp_channel_destroy(session->browsing);
-
- if (session->control)
- avctp_channel_destroy(session->control);
-
- if (session->destroy)
- session->destroy(session->data);
-
- g_free(session->handler);
-
- if (session->key.timer > 0)
- g_source_remove(session->key.timer);
-
- if (session->uinput >= 0) {
- DBG("AVCTP: closing uinput");
-
- ioctl(session->uinput, UI_DEV_DESTROY);
- close(session->uinput);
- session->uinput = -1;
- }
-
- g_free(session);
+ avctp_unref(session);
}