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

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