2024-04-24 14:12:23

by Vlad Pruteanu

[permalink] [raw]
Subject: [PATCH BlueZ v2 4/4] bap: Remove deleted devices from pa_req queue

The bap_bcast_remove function has been updated to remove from the
pa_req queue entries of devices that were freed. pa_req that are already
in progress are treated by the bap_data_free function.

The lookup in bap_bcast_remove was necessary. The entry corresponding to
the calling service must be removed from the pa_req queue. There is no
other way to get a refference to this entry other than to search in the
queue.

This patch fixes a crash that occurs when a device is freed before the
pa_idle_timer handles it's entry in the pa_req queue. The following log
was obtained while running an Unicast setup:

==105052==ERROR: AddressSanitizer: heap-use-after-free on address
0x60400001c418 at pc 0x55775caf1846 bp 0x7ffc83d9fb90 sp 0x7ffc83d9fb80
READ of size 8 at 0x60400001c418 thread T0
0 0x55775caf1845 in btd_service_get_device src/service.c:325
1 0x55775ca03da2 in short_lived_pa_sync profiles/audio/bap.c:2693
2 0x55775ca03da2 in pa_idle_timer profiles/audio/bap.c:1996
---
profiles/audio/bap.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)

diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c
index ab0b96222..2b1ed501b 100644
--- a/profiles/audio/bap.c
+++ b/profiles/audio/bap.c
@@ -2981,10 +2981,20 @@ static int bap_bcast_probe(struct btd_service *service)
return 0;
}

+static bool match_service(const void *data, const void *match_data)
+{
+ struct bap_bcast_pa_req *pa_req = (struct bap_bcast_pa_req *)data;
+
+ if (pa_req->data.service == match_data)
+ return true;
+ return false;
+}
+
static void bap_bcast_remove(struct btd_service *service)
{
struct btd_device *device = btd_service_get_device(service);
struct bap_data *data;
+ struct bap_bcast_pa_req *pa_req;
char addr[18];

ba2str(device_get_address(device), addr);
@@ -2995,6 +3005,14 @@ static void bap_bcast_remove(struct btd_service *service)
error("BAP service not handled by profile");
return;
}
+ /* Remove the corresponding entry from the pa_req queue. Any pa_req that
+ * are in progress will be stopped by bap_data_remove which calls
+ * bap_data_free.
+ */
+ pa_req = queue_remove_if(data->bap_adapter->bcast_pa_requests,
+ match_service, service);
+ if (pa_req)
+ free(pa_req);

bap_data_remove(data);
}
--
2.40.1