shared/hci: Fix crash when bt_hci_unref is used from callback
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Thu, 4 Jun 2020 21:04:39 +0000 (14:04 -0700)
committerAyush Garg <ayush.garg@samsung.com>
Mon, 12 Apr 2021 09:00:49 +0000 (14:30 +0530)
If application unref its reference on the command callback it can lead
to crashes like the following:

 Invalid read of size 1
    at 0x254270: wakeup_writer (hci.c:187)
    by 0x254321: process_response (hci.c:229)
    by 0x254590: process_event (hci.c:263)
    by 0x254590: io_read_callback (hci.c:305)
    by 0x269258: watch_callback (io-glib.c:170)
    by 0x496756F: g_main_context_dispatch (in /usr/lib64/libglib-2.0.so.0.6200.6)
    by 0x49678FF: ??? (in /usr/lib64/libglib-2.0.so.0.6200.6)
    by 0x4967BF2: g_main_loop_run (in /usr/lib64/libglib-2.0.so.0.6200.6)
    by 0x269C6C: mainloop_run (mainloop-glib.c:79)
    by 0x26A219: mainloop_run_with_signal (mainloop-notify.c:201)
    by 0x171A35: main (main.c:770)
  Address 0x53b7e81 is 17 bytes inside a block of size 64 free'd
    at 0x483AA0C: free (vg_replace_malloc.c:540)
    by 0x254A70: bt_hci_unref (hci.c:461)

Signed-off-by: Anuj Jain <anuj01.jain@samsung.com>
Signed-off-by: Ayush Garg <ayush.garg@samsung.com>
src/shared/hci.c

index bfee4ab..262e93d 100755 (executable)
@@ -185,21 +185,29 @@ static void process_response(struct bt_hci *hci, uint16_t opcode,
 {
        struct cmd *cmd;
 
-       if (opcode == BT_HCI_CMD_NOP)
-               goto done;
+       if (opcode == BT_HCI_CMD_NOP) {
+               wakeup_writer(hci);
+               return;
+       }
 
        cmd = queue_remove_if(hci->rsp_queue, match_cmd_opcode,
                                                UINT_TO_PTR(opcode));
        if (!cmd)
                return;
 
+       /* Take a reference before calling the callback since that can unref
+        * its reference destroying the instance.
+        */
+       bt_hci_ref(hci);
+
        if (cmd->callback)
                cmd->callback(data, size, cmd->user_data);
 
        cmd_free(cmd);
 
-done:
        wakeup_writer(hci);
+
+       bt_hci_unref(hci);
 }
 
 static void process_notify(void *data, void *user_data)