gatt-server: Fix crash while disconnecting
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Thu, 19 May 2022 21:36:06 +0000 (14:36 -0700)
committerAyush Garg <ayush.garg@samsung.com>
Mon, 15 May 2023 09:25:54 +0000 (14:55 +0530)
If there is a pending notify multiple the code was not removing before
freeing the object causing the following crash:

Invalid read of size 8
   at 0x4A3D10: notify_multiple (gatt-server.c:1703)
   by 0x4D05F0: timeout_callback (timeout-glib.c:25)
   by 0x4956900: ??? (in /usr/lib64/libglib-2.0.so.0.7000.5)
   by 0x49560AE: g_main_context_dispatch
   (in /usr/lib64/libglib-2.0.so.0.7000.5)
   by 0x49AB307: ??? (in /usr/lib64/libglib-2.0.so.0.7000.5)
   by 0x49557C2: g_main_loop_run
   (in /usr/lib64/libglib-2.0.so.0.7000.5)
   by 0x4D0A34: mainloop_run (mainloop-glib.c:66)
   by 0x4D0F2B: mainloop_run_with_signal (mainloop-notify.c:188)
   by 0x2B0CD1: main (main.c:1276)
 Address 0x6ca35c8 is 136 bytes inside a block of size 144 free'd
   at 0x48470E4: free (vg_replace_malloc.c:872)
   by 0x415E73: gatt_server_cleanup (device.c:698)
   by 0x415E73: attio_cleanup (device.c:715)
   by 0x47745B: queue_foreach (queue.c:207)
   by 0x490C54: disconnect_cb (att.c:701)
   by 0x4CF4AF: watch_callback (io-glib.c:157)
   by 0x49560AE: g_main_context_dispatch
   (in /usr/lib64/libglib-2.0.so.0.7000.5)
   by 0x49AB307: ??? (in /usr/lib64/libglib-2.0.so.0.7000.5)
   by 0x49557C2: g_main_loop_run
   (in /usr/lib64/libglib-2.0.so.0.7000.5)
   by 0x4D0A34: mainloop_run (mainloop-glib.c:66)
   by 0x4D0F2B: mainloop_run_with_signal (mainloop-notify.c:188)
   by 0x2B0CD1: main (main.c:1276)

Signed-off-by: Manika Shrivastava <manika.sh@samsung.com>
Signed-off-by: Ayush Garg <ayush.garg@samsung.com>
src/shared/gatt-server.c

index 270461f..c885c74 100644 (file)
@@ -131,11 +131,26 @@ struct bt_gatt_server {
 #endif
 };
 
+static void notify_multiple_free(struct bt_gatt_server *server)
+{
+       if (!server->nfy_mult)
+               return;
+
+       if (server->nfy_mult->id)
+               timeout_remove(server->nfy_mult->id);
+
+       free(server->nfy_mult->pdu);
+       free(server->nfy_mult);
+       server->nfy_mult = NULL;
+}
+
 static void bt_gatt_server_free(struct bt_gatt_server *server)
 {
        if (server->debug_destroy)
                server->debug_destroy(server->debug_data);
 
+       notify_multiple_free(server);
+
        bt_att_unregister(server->att, server->mtu_id);
        bt_att_unregister(server->att, server->read_by_grp_type_id);
        bt_att_unregister(server->att, server->read_by_type_id);
@@ -1862,17 +1877,26 @@ bool bt_gatt_server_set_debug(struct bt_gatt_server *server,
        return true;
 }
 
+static void notify_multiple_timeout_remove(struct bt_gatt_server *server)
+{
+       if (!server->nfy_mult->id)
+               return;
+
+       timeout_remove(server->nfy_mult->id);
+       server->nfy_mult->id = 0;
+}
+
 static bool notify_multiple(void *user_data)
 {
        struct bt_gatt_server *server = user_data;
 
+       server->nfy_mult->id = 0;
+
        bt_att_send(server->att, BT_ATT_OP_HANDLE_NFY_MULT,
                        server->nfy_mult->pdu, server->nfy_mult->offset, NULL,
                        NULL, NULL);
 
-       free(server->nfy_mult->pdu);
-       free(server->nfy_mult);
-       server->nfy_mult = NULL;
+       notify_multiple_free(server);
 
        return false;
 }
@@ -1904,8 +1928,7 @@ bool bt_gatt_server_send_notification(struct bt_gatt_server *server,
                /* flush buffered data if this request hits buffer size limit */
                if (data && data->offset > 0 &&
                                data->len - data->offset < 4 + length) {
-                       if (server->nfy_mult->id)
-                               timeout_remove(server->nfy_mult->id);
+                       notify_multiple_timeout_remove(server);
                        notify_multiple(server);
                        /* data has been freed by notify_multiple */
                        data = NULL;