From f89d64b98e12bb71b6aa94fcef31eafc060f9759 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Fr=C3=A9d=C3=A9ric=20Danis?= Date: Wed, 19 Jun 2019 11:09:11 +0200 Subject: [PATCH] bluetooth: Fix crash when disabling Bluetooth adapter This crash occurs when PA is connected to a phone through the oFono backend. When disabling the Bluetooth adapter, pa_bluetooth_device is removed before hf_audio_card. Both keep refs on pa_bluetooth_transport. Those removal will call pa_bluetooth_transport_free() from device_free() (bluez5-util.c) and hf_audio_card_free() (backend-ofono.c). In the end, the call to pa_bluetooth_transport_free() calls pa_hasmap_remove() through pa_bluetooth_transport_unlink(), but since memory has already been freed, the second try results in a segfault. Triggering hf_audio_card removal during pa_bluetooth_device removal allows hf_audio_card to be freed at the right time. --- src/modules/bluetooth/backend-ofono.c | 18 ++++++++++++++++++ src/modules/bluetooth/bluez5-util.c | 2 ++ src/modules/bluetooth/bluez5-util.h | 1 + 3 files changed, 21 insertions(+) diff --git a/src/modules/bluetooth/backend-ofono.c b/src/modules/bluetooth/backend-ofono.c index 1f0efe9..0e5bbe8 100644 --- a/src/modules/bluetooth/backend-ofono.c +++ b/src/modules/bluetooth/backend-ofono.c @@ -70,6 +70,7 @@ struct hf_audio_card { int (*acquire)(struct hf_audio_card *card); pa_bluetooth_transport *transport; + pa_hook_slot *device_unlink_slot; }; struct pa_bluetooth_backend { @@ -181,6 +182,17 @@ static int card_acquire(struct hf_audio_card *card) { return -1; } +static void hf_audio_agent_card_removed(pa_bluetooth_backend *backend, const char *path); + +static pa_hook_result_t device_unlink_cb(pa_bluetooth_discovery *y, const pa_bluetooth_device *d, struct hf_audio_card *card) { + pa_assert(d); + pa_assert(card); + + hf_audio_agent_card_removed(card->backend, card->path); + + return PA_HOOK_OK; +} + static struct hf_audio_card *hf_audio_card_new(pa_bluetooth_backend *backend, const char *path) { struct hf_audio_card *card = pa_xnew0(struct hf_audio_card, 1); @@ -189,12 +201,18 @@ static struct hf_audio_card *hf_audio_card_new(pa_bluetooth_backend *backend, co card->fd = -1; card->acquire = card_acquire; + card->device_unlink_slot = pa_hook_connect(pa_bluetooth_discovery_hook(backend->discovery, PA_BLUETOOTH_HOOK_DEVICE_UNLINK), + PA_HOOK_NORMAL, (pa_hook_cb_t) device_unlink_cb, card); + return card; } static void hf_audio_card_free(struct hf_audio_card *card) { pa_assert(card); + if (card->device_unlink_slot) + pa_hook_slot_free(card->device_unlink_slot); + if (card->transport) pa_bluetooth_transport_free(card->transport); diff --git a/src/modules/bluetooth/bluez5-util.c b/src/modules/bluetooth/bluez5-util.c index 3c5a000..d95c9c1 100644 --- a/src/modules/bluetooth/bluez5-util.c +++ b/src/modules/bluetooth/bluez5-util.c @@ -562,6 +562,8 @@ static void device_free(pa_bluetooth_device *d) { device_stop_waiting_for_profiles(d); + pa_hook_fire(&d->discovery->hooks[PA_BLUETOOTH_HOOK_DEVICE_UNLINK], d); + for (i = 0; i < PA_BLUETOOTH_PROFILE_COUNT; i++) { pa_bluetooth_transport *t; diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h index 82739bf..ff172e0 100644 --- a/src/modules/bluetooth/bluez5-util.h +++ b/src/modules/bluetooth/bluez5-util.h @@ -47,6 +47,7 @@ typedef struct pa_bluetooth_backend pa_bluetooth_backend; typedef enum pa_bluetooth_hook { PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED, /* Call data: pa_bluetooth_device */ + PA_BLUETOOTH_HOOK_DEVICE_UNLINK, /* Call data: pa_bluetooth_device */ PA_BLUETOOTH_HOOK_TRANSPORT_STATE_CHANGED, /* Call data: pa_bluetooth_transport */ PA_BLUETOOTH_HOOK_TRANSPORT_MICROPHONE_GAIN_CHANGED, /* Call data: pa_bluetooth_transport */ PA_BLUETOOTH_HOOK_TRANSPORT_SPEAKER_GAIN_CHANGED, /* Call data: pa_bluetooth_transport */ -- 2.7.4