aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorPauli Virtanen <pav@iki.fi>2024-04-12 22:55:55 +0300
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2024-04-16 11:29:58 -0400
commitf78e639f810cb9b7469ad55af0af1dc930ac8502 (patch)
treee12807c58fc043b78939151f6db3b41327c8d60a
parentb94f1be656f34ea1363f5566ef63b847234c6dea (diff)
shared/bap: clean up requests for a stream before freeing it
Cancel stream's queued requests before freeing the stream. As the callbacks may do some cleanup on error, be sure to call them before removing the requests. Fixes: ======================================================================= ERROR: AddressSanitizer: heap-use-after-free on address 0x60d000013430 READ of size 8 at 0x60d000013430 thread T0 #0 0x89cb9f in stream_stop_complete src/shared/bap.c:1211 #1 0x89c997 in bap_req_complete src/shared/bap.c:1192 #2 0x8a105f in bap_process_queue src/shared/bap.c:1474 #3 0x93c93f in timeout_callback src/shared/timeout-glib.c:25 ... freed by thread T0 here: #1 0x89b744 in bap_stream_free src/shared/bap.c:1105 #2 0x89bac8 in bap_stream_detach src/shared/bap.c:1122 #3 0x89dbfc in bap_stream_state_changed src/shared/bap.c:1261 #4 0x8a2169 in bap_ucast_set_state src/shared/bap.c:1554 #5 0x89e0d5 in stream_set_state src/shared/bap.c:1291 #6 0x8a78b6 in bap_ucast_release src/shared/bap.c:1927 #7 0x8d45bb in bt_bap_stream_release src/shared/bap.c:5516 #8 0x8ba63f in remove_streams src/shared/bap.c:3538 #9 0x7f23d0 in queue_foreach src/shared/queue.c:207 #10 0x8bb875 in bt_bap_remove_pac src/shared/bap.c:3593 #11 0x47416c in media_endpoint_destroy profiles/audio/media.c:185 =======================================================================
-rw-r--r--src/shared/bap.c106
1 files changed, 65 insertions, 41 deletions
diff --git a/src/shared/bap.c b/src/shared/bap.c
index 5fee7b4c54..71eadbdb68 100644
--- a/src/shared/bap.c
+++ b/src/shared/bap.c
@@ -1105,6 +1105,69 @@ static void bap_stream_free(void *data)
free(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 bool match_req_stream(const void *data, const void *match_data)
+{
+ const struct bt_bap_req *req = data;
+
+ return req->stream == match_data;
+}
+
+static void bap_req_abort(void *data)
+{
+ struct bt_bap_req *req = data;
+ struct bt_bap *bap = req->stream->bap;
+
+ DBG(bap, "req %p", req);
+ bap_req_complete(req, NULL);
+}
+
+static void bap_abort_stream_req(struct bt_bap *bap,
+ struct bt_bap_stream *stream)
+{
+ queue_remove_all(bap->reqs, match_req_stream, stream, bap_req_abort);
+}
+
static void bap_stream_detach(struct bt_bap_stream *stream)
{
struct bt_bap_endpoint *ep = stream->ep;
@@ -1114,6 +1177,8 @@ static void bap_stream_detach(struct bt_bap_stream *stream)
DBG(stream->bap, "stream %p ep %p", stream, ep);
+ bap_abort_stream_req(stream->bap, stream);
+
queue_remove(stream->bap->streams, stream);
bap_stream_clear_cfm(stream);
@@ -1164,47 +1229,6 @@ static bool bap_stream_io_detach(struct bt_bap_stream *stream)
return true;
}
-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 stream_stop_complete(struct bt_bap_stream *stream, uint8_t code,
uint8_t reason, void *user_data)
{