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

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