Blame SOURCES/0001-shared-att-Fix-possible-crash-on-disconnect.patch

33e1a3
From b61877eb3e05b9b9dff36b4eccc46c539634cf15 Mon Sep 17 00:00:00 2001
33e1a3
From: Gopal Tiwari <gtiwari@redhat.com>
33e1a3
Date: Thu, 22 Oct 2020 11:23:00 +0530
33e1a3
Subject: [PATCH BlueZ]     shared/att: Fix possible crash on disconnect
33e1a3
33e1a3
commit 1cd644db8c23a2f530ddb93cebed7dacc5f5721a
33e1a3
Author: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
33e1a3
Date:   Wed Jul 15 18:25:37 2020 -0700
33e1a3
33e1a3
    shared/att: Fix possible crash on disconnect
33e1a3
33e1a3
    If there are pending request while disconnecting they would be notified
33e1a3
    but clients may endup being freed in the proccess which will then be
33e1a3
    calling bt_att_cancel to cancal its requests causing the following
33e1a3
    trace:
33e1a3
33e1a3
    Invalid read of size 4
33e1a3
       at 0x1D894C: enable_ccc_callback (gatt-client.c:1627)
33e1a3
       by 0x1D247B: disc_att_send_op (att.c:417)
33e1a3
       by 0x1CCC17: queue_remove_all (queue.c:354)
33e1a3
       by 0x1D47B7: disconnect_cb (att.c:635)
33e1a3
       by 0x1E0707: watch_callback (io-glib.c:170)
33e1a3
       by 0x48E963B: g_main_context_dispatch (in /usr/lib/libglib-2.0.so.0.6400.4)
33e1a3
       by 0x48E9AC7: ??? (in /usr/lib/libglib-2.0.so.0.6400.4)
33e1a3
       by 0x48E9ECF: g_main_loop_run (in /usr/lib/libglib-2.0.so.0.6400.4)
33e1a3
       by 0x1E0E97: mainloop_run (mainloop-glib.c:79)
33e1a3
       by 0x1E13B3: mainloop_run_with_signal (mainloop-notify.c:201)
33e1a3
       by 0x12BC3B: main (main.c:770)
33e1a3
     Address 0x7d40a28 is 24 bytes inside a block of size 32 free'd
33e1a3
       at 0x484A2E0: free (vg_replace_malloc.c:540)
33e1a3
       by 0x1CCC17: queue_remove_all (queue.c:354)
33e1a3
       by 0x1CCC83: queue_destroy (queue.c:73)
33e1a3
       by 0x1D7DD7: bt_gatt_client_free (gatt-client.c:2209)
33e1a3
       by 0x16497B: batt_free (battery.c:77)
33e1a3
       by 0x16497B: batt_remove (battery.c:286)
33e1a3
       by 0x1A0013: service_remove (service.c:176)
33e1a3
     by 0x1A9B7B: device_remove_gatt_service (device.c:3691)
33e1a3
       by 0x1A9B7B: gatt_service_removed (device.c:3805)
33e1a3
       by 0x1CC90B: queue_foreach (queue.c:220)
33e1a3
       by 0x1DE27B: notify_service_changed.isra.0.part.0 (gatt-db.c:369)
33e1a3
       by 0x1DE387: notify_service_changed (gatt-db.c:361)
33e1a3
       by 0x1DE387: gatt_db_service_destroy (gatt-db.c:385)
33e1a3
       by 0x1DE3EF: gatt_db_remove_service (gatt-db.c:519)
33e1a3
       by 0x1D674F: discovery_op_complete (gatt-client.c:388)
33e1a3
       by 0x1D6877: discover_primary_cb (gatt-client.c:1260)
33e1a3
       by 0x1E220B: discovery_op_complete (gatt-helpers.c:628)
33e1a3
       by 0x1E249B: read_by_grp_type_cb (gatt-helpers.c:730)
33e1a3
       by 0x1D247B: disc_att_send_op (att.c:417)
33e1a3
       by 0x1CCC17: queue_remove_all (queue.c:354)
33e1a3
       by 0x1D47B7: disconnect_cb (att.c:635)
33e1a3
---
33e1a3
 src/shared/att.c | 46 ++++++++++++++++++++++++++++++++++++++++------
33e1a3
 1 file changed, 40 insertions(+), 6 deletions(-)
33e1a3
33e1a3
diff --git a/src/shared/att.c b/src/shared/att.c
33e1a3
index 0ea6d55bd..b0fdb8e9f 100644
33e1a3
--- a/src/shared/att.c
33e1a3
+++ b/src/shared/att.c
33e1a3
@@ -62,6 +62,7 @@ struct bt_att {
33e1a3
 	struct queue *ind_queue;	/* Queued ATT protocol indications */
33e1a3
 	struct att_send_op *pending_ind;
33e1a3
 	struct queue *write_queue;	/* Queue of PDUs ready to send */
33e1a3
+	bool in_disc;			/* Cleanup queues on disconnect_cb */
33e1a3
 	bool writer_active;
33e1a3
 
33e1a3
 	struct queue *notify_list;	/* List of registered callbacks */
33e1a3
@@ -211,8 +212,10 @@ static void destroy_att_send_op(void *data)
33e1a3
 	free(op);
33e1a3
 }
33e1a3
 
33e1a3
-static void cancel_att_send_op(struct att_send_op *op)
33e1a3
+static void cancel_att_send_op(void *data)
33e1a3
 {
33e1a3
+	struct att_send_op *op = data;
33e1a3
+
33e1a3
 	if (op->destroy)
33e1a3
 		op->destroy(op->user_data);
33e1a3
 
33e1a3
@@ -572,11 +575,6 @@ static bool disconnect_cb(struct io *io, void *user_data)
33e1a3
 	att->io = NULL;
33e1a3
 	att->fd = -1;
33e1a3
 
33e1a3
-	/* Notify request callbacks */
33e1a3
-	queue_remove_all(att->req_queue, NULL, NULL, disc_att_send_op);
33e1a3
-	queue_remove_all(att->ind_queue, NULL, NULL, disc_att_send_op);
33e1a3
-	queue_remove_all(att->write_queue, NULL, NULL, disc_att_send_op);
33e1a3
-
33e1a3
 	if (att->pending_req) {
33e1a3
 		disc_att_send_op(att->pending_req);
33e1a3
 		att->pending_req = NULL;
33e1a3
@@ -589,6 +587,15 @@ static bool disconnect_cb(struct io *io, void *user_data)
33e1a3
 
33e1a3
 	bt_att_ref(att);
33e1a3
 
33e1a3
+	att->in_disc = true;
33e1a3
+
33e1a3
+	/* Notify request callbacks */
33e1a3
+	queue_remove_all(att->req_queue, NULL, NULL, disc_att_send_op);
33e1a3
+	queue_remove_all(att->ind_queue, NULL, NULL, disc_att_send_op);
33e1a3
+	queue_remove_all(att->write_queue, NULL, NULL, disc_att_send_op);
33e1a3
+
33e1a3
+	att->in_disc = false;
33e1a3
+
33e1a3
 	queue_foreach(att->disconn_list, disconn_handler, INT_TO_PTR(err));
33e1a3
 
33e1a3
 	bt_att_unregister_all(att);
33e1a3
@@ -1306,6 +1313,30 @@ static bool match_op_id(const void *a, const void *b)
33e1a3
 	return op->id == id;
33e1a3
 }
33e1a3
 
33e1a3
+static bool bt_att_disc_cancel(struct bt_att *att, unsigned int id)
33e1a3
+{
33e1a3
+	struct att_send_op *op;
33e1a3
+
33e1a3
+	op = queue_find(att->req_queue, match_op_id, UINT_TO_PTR(id));
33e1a3
+	if (op)
33e1a3
+		goto done;
33e1a3
+
33e1a3
+	op = queue_find(att->ind_queue, match_op_id, UINT_TO_PTR(id));
33e1a3
+	if (op)
33e1a3
+		goto done;
33e1a3
+
33e1a3
+	op = queue_find(att->write_queue, match_op_id, UINT_TO_PTR(id));
33e1a3
+
33e1a3
+done:
33e1a3
+	if (!op)
33e1a3
+		return false;
33e1a3
+
33e1a3
+	/* Just cancel since disconnect_cb will be cleaning up */
33e1a3
+	cancel_att_send_op(op);
33e1a3
+
33e1a3
+	return true;
33e1a3
+}
33e1a3
+
33e1a3
 bool bt_att_cancel(struct bt_att *att, unsigned int id)
33e1a3
 {
33e1a3
 	struct att_send_op *op;
33e1a3
@@ -1325,6 +1356,9 @@ bool bt_att_cancel(struct bt_att *att, unsigned int id)
33e1a3
 		return true;
33e1a3
 	}
33e1a3
 
33e1a3
+	if (att->in_disc)
33e1a3
+		return bt_att_disc_cancel(att, id);
33e1a3
+
33e1a3
 	op = queue_remove_if(att->req_queue, match_op_id, UINT_TO_PTR(id));
33e1a3
 	if (op)
33e1a3
 		goto done;
33e1a3
-- 
33e1a3
2.21.1
33e1a3