shared/bap: Fix crash detaching streams
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Mon, 24 Apr 2023 23:05:06 +0000 (16:05 -0700)
committerAyush Garg <ayush.garg@samsung.com>
Fri, 5 Jan 2024 10:41:34 +0000 (16:11 +0530)
If a stream is being detached but bt_bap reference is already 0 don't
attempt to detach the stream as they would be freed anyway:

Invalid read of size 8
   at 0x19A360: bap_free (bap.c:2576)
   by 0x19A360: bt_bap_unref (bap.c:2735)
   by 0x19A360: bt_bap_unref (bap.c:2727)
   by 0x160E9A: test_teardown (test-bap.c:412)
   by 0x1A8BCA: teardown_callback (tester.c:434)
 Address 0x55e05e0 is 16 bytes inside a block of size 160 free'd
   at 0x48480E4: free (vg_replace_malloc.c:872)
   by 0x1AD5F6: queue_foreach (queue.c:207)
   by 0x19A1C5: bt_bap_detach (bap.c:3879)
   by 0x19A1C5: bt_bap_detach (bap.c:3855)
   by 0x19A33F: bap_free (bap.c:2574)

src/shared/bap.c

index 5a12a64..bc6177a 100644 (file)
@@ -1168,6 +1168,14 @@ static void bap_stream_set_io(void *data, void *user_data)
        }
 }
 
+static struct bt_bap *bt_bap_ref_safe(struct bt_bap *bap)
+{
+       if (!bap || !bap->ref_count)
+               return NULL;
+
+       return bt_bap_ref(bap);
+}
+
 static void bap_stream_state_changed(struct bt_bap_stream *stream)
 {
        struct bt_bap *bap = stream->bap;
@@ -1178,7 +1186,14 @@ static void bap_stream_state_changed(struct bt_bap_stream *stream)
                        bt_bap_stream_statestr(stream->ep->old_state),
                        bt_bap_stream_statestr(stream->ep->state));
 
-       bt_bap_ref(bap);
+       /* Check if ref_count is already 0 which means detaching is in
+        * progress.
+        */
+       bap = bt_bap_ref_safe(bap);
+       if (!bap) {
+               bap_stream_detach(stream);
+               return;
+       }
 
        /* Pre notification updates */
        switch (stream->ep->state) {
@@ -2730,14 +2745,6 @@ struct bt_bap *bt_bap_ref(struct bt_bap *bap)
        return bap;
 }
 
-static struct bt_bap *bt_bap_ref_safe(struct bt_bap *bap)
-{
-       if (!bap || !bap->ref_count)
-               return NULL;
-
-       return bt_bap_ref(bap);
-}
-
 void bt_bap_unref(struct bt_bap *bap)
 {
        if (!bap)