diff options
author | Archie Pusaka <apusaka@chromium.org> | 2021-02-05 11:47:46 +0800 |
---|---|---|
committer | Luiz Augusto von Dentz <luiz.von.dentz@intel.com> | 2021-02-08 13:53:21 -0800 |
commit | 1ecf167cec1696e266de58db6cd904f43c4b532e (patch) | |
tree | d6044ea97d3e5765164864aefa221b3a23b3b0a6 /profiles | |
parent | 15fcbf2b61af0ce1bbe08c03d39c1eca44925ef7 (diff) | |
download | bluez-1ecf167cec1696e266de58db6cd904f43c4b532e.tar.gz |
a2dp: set session to NULL when freeing channel
There is a possibility that avdtp_channel is freed when avdtp_setup
is not yet freed. This could cause crashes because setup->chan will
then point to an invalid address.
Diffstat (limited to 'profiles')
-rw-r--r-- | profiles/audio/a2dp.c | 34 | ||||
-rw-r--r-- | profiles/audio/a2dp.h | 4 | ||||
-rw-r--r-- | profiles/audio/avdtp.c | 6 | ||||
-rw-r--r-- | profiles/audio/sink.c | 5 | ||||
-rw-r--r-- | profiles/audio/source.c | 5 |
5 files changed, 44 insertions, 10 deletions
diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c index 624d0d42d..98cae97b9 100644 --- a/profiles/audio/a2dp.c +++ b/profiles/audio/a2dp.c @@ -379,7 +379,8 @@ static void finalize_select(struct a2dp_setup *s) if (!cb->select_cb) continue; - cb->select_cb(s->session, s->sep, s->caps, cb->user_data); + cb->select_cb(s->session, s->sep, s->caps, + error_to_errno(s->err), cb->user_data); setup_cb_free(cb); } } @@ -457,7 +458,7 @@ static void stream_state_changed(struct avdtp_stream *stream, int err; setup = find_setup_by_stream(stream); - if (!setup || !setup->start) + if (!setup || !setup->start || setup->err) return; setup->start = FALSE; @@ -606,7 +607,7 @@ static gboolean endpoint_setconf_ind(struct avdtp *session, DBG("Source %p: Set_Configuration_Ind", sep); setup = a2dp_setup_get(session); - if (!session) + if (!setup) return FALSE; a2dp_sep->stream = stream; @@ -715,7 +716,7 @@ static gboolean endpoint_getcap_ind(struct avdtp *session, static void endpoint_open_cb(struct a2dp_setup *setup, gboolean ret) { - int err; + int err = error_to_errno(setup->err); if (ret == FALSE) { setup->stream = NULL; @@ -723,7 +724,9 @@ static void endpoint_open_cb(struct a2dp_setup *setup, gboolean ret) goto done; } - err = avdtp_open(setup->session, setup->stream); + if (err == 0) + err = avdtp_open(setup->session, setup->stream); + if (err == 0) goto done; @@ -1172,6 +1175,11 @@ static gboolean a2dp_reconfigure(gpointer data) setup->id = 0; + if (setup->err) { + posix_err = error_to_errno(setup->err); + goto failed; + } + if (!sep->lsep) { error("no valid local SEP"); posix_err = -EINVAL; @@ -1510,6 +1518,7 @@ static void remove_remote_sep(void *data) static void channel_free(void *data) { struct a2dp_channel *chan = data; + struct a2dp_setup *setup; if (chan->auth_id > 0) btd_cancel_authorization(chan->auth_id); @@ -1526,6 +1535,15 @@ static void channel_free(void *data) queue_destroy(chan->seps, remove_remote_sep); free(chan->last_used); + + setup = find_setup_by_session(chan->session); + if (setup) { + setup->chan = NULL; + avdtp_unref(setup->session); + setup->session = NULL; + finalize_setup_errno(setup, -ENOTCONN, NULL); + } + g_free(chan); } @@ -2561,6 +2579,9 @@ static void select_cb(struct a2dp_setup *setup, void *ret, int size) struct avdtp_media_codec_capability *codec; int err; + if (setup->err) + goto done; + if (size >= 0) { caps_add_codec(&setup->caps, setup->sep->codec, ret, size); goto done; @@ -2727,7 +2748,8 @@ static void discover_cb(struct avdtp *session, GSList *seps, DBG("version 0x%04x err %p", version, err); setup->seps = seps; - setup->err = err; + if (err) + setup->err = err; if (!err) { g_slist_foreach(seps, register_remote_sep, setup->chan); diff --git a/profiles/audio/a2dp.h b/profiles/audio/a2dp.h index b40bd4736..615b641c9 100644 --- a/profiles/audio/a2dp.h +++ b/profiles/audio/a2dp.h @@ -42,8 +42,8 @@ struct a2dp_endpoint { typedef void (*a2dp_discover_cb_t) (struct avdtp *session, GSList *seps, int err, void *user_data); -typedef void (*a2dp_select_cb_t) (struct avdtp *session, - struct a2dp_sep *sep, GSList *caps, +typedef void (*a2dp_select_cb_t) (struct avdtp *session, struct a2dp_sep *sep, + GSList *caps, int err, void *user_data); typedef void (*a2dp_config_cb_t) (struct avdtp *session, struct a2dp_sep *sep, struct avdtp_stream *stream, int err, diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c index b8ef5f682..fa72ef66a 100644 --- a/profiles/audio/avdtp.c +++ b/profiles/audio/avdtp.c @@ -3847,11 +3847,17 @@ uint8_t avdtp_sep_get_seid(struct avdtp_local_sep *sep) struct btd_adapter *avdtp_get_adapter(struct avdtp *session) { + if (!session) + return NULL; + return device_get_adapter(session->device); } struct btd_device *avdtp_get_device(struct avdtp *session) { + if (!session) + return NULL; + return session->device; } diff --git a/profiles/audio/sink.c b/profiles/audio/sink.c index d672670e2..56c491778 100644 --- a/profiles/audio/sink.c +++ b/profiles/audio/sink.c @@ -183,13 +183,16 @@ static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep, } static void select_complete(struct avdtp *session, struct a2dp_sep *sep, - GSList *caps, void *user_data) + GSList *caps, int err, void *user_data) { struct sink *sink = user_data; int id; sink->connect_id = 0; + if (err) + goto failed; + id = a2dp_config(session, sep, stream_setup_complete, caps, sink); if (id == 0) goto failed; diff --git a/profiles/audio/source.c b/profiles/audio/source.c index c706c928a..c6009d0ea 100644 --- a/profiles/audio/source.c +++ b/profiles/audio/source.c @@ -180,13 +180,16 @@ static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep, } static void select_complete(struct avdtp *session, struct a2dp_sep *sep, - GSList *caps, void *user_data) + GSList *caps, int err, void *user_data) { struct source *source = user_data; int id; source->connect_id = 0; + if (err) + goto failed; + if (caps == NULL) goto failed; |