diff mbox series

[BlueZ,v2,4/4] bap: Remove deleted devices from pa_req queue

Message ID 20240424140741.73899-5-vlad.pruteanu@nxp.com (mailing list archive)
State Accepted
Commit c7071911d57aa684f86f9458e33dfd9abb809c50
Headers show
Series bap: Replace the global bcast_pa_requests with a per adapter queue | expand

Checks

Context Check Description
tedd_an/pre-ci_am success Success
tedd_an/CheckPatch success CheckPatch PASS
tedd_an/GitLint success Gitlint PASS
tedd_an/IncrementalBuild success Incremental Build PASS

Commit Message

Vlad Pruteanu April 24, 2024, 2:07 p.m. UTC
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 mbox series

Patch

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);
 }