diff mbox series

[BlueZ,v3,6/8] shared/bap: Fix possible crash when freeing requests

Message ID 20231204221527.2990674-6-luiz.dentz@gmail.com (mailing list archive)
State Accepted
Commit f10faf387d7ff5ef08a403dec895760996cb55ef
Headers show
Series [BlueZ,v3,1/8] shared/lc3: Add QoS definitions | 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

Luiz Augusto von Dentz Dec. 4, 2023, 10:15 p.m. UTC
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

Requests maybe queued using a stream so when detaching it needs to be
canceled otherwise they can lead crashes like bellow:

 Invalid read of size 8
    at 0x1C3247: stream_stop_complete (bap.c:1230)
    by 0x1BB2A3: bap_req_complete (bap.c:3863)
    by 0x1C7BB3: bap_req_detach (bap.c:4219)
    by 0x1C7BB3: bt_bap_detach (bap.c:4231)
    by 0x1C7BB3: bt_bap_detach (bap.c:4222)
    by 0x1C7E67: bap_free (bap.c:2937)
    by 0x1C7E67: bt_bap_unref (bap.c:3090)
    by 0x1C7E67: bt_bap_unref (bap.c:3082)
    by 0x18CCC2: test_teardown (test-bap.c:513)
    by 0x1D826A: teardown_callback (tester.c:434)
    by 0x491E4FC: g_idle_dispatch (gmain.c:6163)
    by 0x49224FB: UnknownInlinedFun (gmain.c:3460)
    by 0x49224FB: g_main_context_dispatch (gmain.c:4200)
    by 0x49806B7: g_main_context_iterate.isra.0 (gmain.c:4276)
    by 0x4921AFE: g_main_loop_run (gmain.c:4479)
    by 0x1E8EF4: mainloop_run (mainloop-glib.c:66)
    by 0x1E93F7: mainloop_run_with_signal (mainloop-notify.c:188)
  Address 0x57b9ad0 is 0 bytes inside a block of size 120 free'd
    at 0x4845B2C: free (vg_replace_malloc.c:985)
    by 0x1CBAB7: bap_stream_state_changed (bap.c:1290)
    by 0x1D3104: bap_ep_set_status (bap.c:3673)
    by 0x1DC746: queue_foreach (queue.c:207)
    by 0x1A5320: notify_cb (gatt-client.c:2271)
    by 0x19A1EF: handle_notify (att.c:1012)
    by 0x19A1EF: can_read_data (att.c:1096)
    by 0x1D68CF: watch_callback (io-glib.c:157)
    by 0x49224FB: UnknownInlinedFun (gmain.c:3460)
    by 0x49224FB: g_main_context_dispatch (gmain.c:4200)
    by 0x49806B7: g_main_context_iterate.isra.0 (gmain.c:4276)
    by 0x4921AFE: g_main_loop_run (gmain.c:4479)
    by 0x1E8EF4: mainloop_run (mainloop-glib.c:66)
    by 0x1E93F7: mainloop_run_with_signal (mainloop-notify.c:188)
---
 src/shared/bap.c | 91 ++++++++++++++++++++++++++----------------------
 1 file changed, 50 insertions(+), 41 deletions(-)
diff mbox series

Patch

diff --git a/src/shared/bap.c b/src/shared/bap.c
index d8a3adde60ca..a1495ca84bcc 100644
--- a/src/shared/bap.c
+++ b/src/shared/bap.c
@@ -1232,6 +1232,47 @@  static void stream_stop_complete(struct bt_bap_stream *stream, uint8_t code,
 		bap_stream_io_detach(stream);
 }
 
+static void bap_req_free(void *data)
+{
+	struct bt_bap_req *req = data;
+	size_t i;
+
+	queue_destroy(req->group, bap_req_free);
+
+	for (i = 0; i < req->len; i++)
+		free(req->iov[i].iov_base);
+
+	free(req->iov);
+	free(req);
+}
+
+static void bap_req_complete(struct bt_bap_req *req,
+				const struct bt_ascs_ase_rsp *rsp)
+{
+	struct queue *group;
+
+	if (!req->func)
+		goto done;
+
+	if (rsp)
+		req->func(req->stream, rsp->code, rsp->reason, req->user_data);
+	else
+		req->func(req->stream, BT_ASCS_RSP_UNSPECIFIED, 0x00,
+						req->user_data);
+
+done:
+	/* Detach from request so it can be freed separately */
+	group = req->group;
+	req->group = NULL;
+
+	queue_foreach(group, (queue_foreach_func_t)bap_req_complete,
+							(void *)rsp);
+
+	queue_destroy(group, NULL);
+
+	bap_req_free(req);
+}
+
 static void bap_stream_state_changed(struct bt_bap_stream *stream)
 {
 	struct bt_bap *bap = stream->bap;
@@ -1286,6 +1327,10 @@  static void bap_stream_state_changed(struct bt_bap_stream *stream)
 	/* Post notification updates */
 	switch (stream->ep->state) {
 	case BT_ASCS_ASE_STATE_IDLE:
+		if (bap->req && bap->req->stream == stream) {
+			bap_req_complete(bap->req, NULL);
+			bap->req = NULL;
+		}
 		bap_stream_detach(stream);
 		break;
 	case BT_ASCS_ASE_STATE_QOS:
@@ -2905,20 +2950,6 @@  static void bap_state_free(void *data)
 	free(state);
 }
 
-static void bap_req_free(void *data)
-{
-	struct bt_bap_req *req = data;
-	size_t i;
-
-	queue_destroy(req->group, bap_req_free);
-
-	for (i = 0; i < req->len; i++)
-		free(req->iov[i].iov_base);
-
-	free(req->iov);
-	free(req);
-}
-
 static void bap_detached(void *data, void *user_data)
 {
 	struct bt_bap_cb *cb = data;
@@ -3809,6 +3840,11 @@  static bool bap_send(struct bt_bap *bap, struct bt_bap_req *req)
 
 	DBG(bap, "req %p len %u", req, iov.iov_len);
 
+	if (req->stream && !queue_find(bap->streams, NULL, req->stream)) {
+		DBG(bap, "stream %p detached, aborting op 0x%02x", req->op);
+		return false;
+	}
+
 	if (!gatt_db_attribute_get_char_data(ascs->ase_cp, NULL, &handle,
 						NULL, NULL, NULL)) {
 		DBG(bap, "Unable to find Control Point");
@@ -3843,33 +3879,6 @@  static bool bap_send(struct bt_bap *bap, struct bt_bap_req *req)
 	return true;
 }
 
-static void bap_req_complete(struct bt_bap_req *req,
-				const struct bt_ascs_ase_rsp *rsp)
-{
-	struct queue *group;
-
-	if (!req->func)
-		goto done;
-
-	if (rsp)
-		req->func(req->stream, rsp->code, rsp->reason, req->user_data);
-	else
-		req->func(req->stream, BT_ASCS_RSP_UNSPECIFIED, 0x00,
-						req->user_data);
-
-done:
-	/* Detach from request so it can be freed separately */
-	group = req->group;
-	req->group = NULL;
-
-	queue_foreach(group, (queue_foreach_func_t)bap_req_complete,
-							(void *)rsp);
-
-	queue_destroy(group, NULL);
-
-	bap_req_free(req);
-}
-
 static bool bap_process_queue(void *data)
 {
 	struct bt_bap *bap = data;