In hci_connect_le_sync, the hci_conn may be deleted before the hci_sync event runs. Hold a reference to the conn while the hci_sync command is queued, so we at least avoid the use-after-free. Add some checks to catch a race while the hci_sync command is queued, but this is still not quite right because the conn may be deleted during hci_le_create_conn_sync (but now we hold ref, so UAF less likely). The problem: ================================================================== BUG: KASAN: slab-use-after-free in hci_le_create_conn_sync (net/bluetooth/hci_sync.c:6167) bluetooth Read of size 1 at addr ffff88804c3ec03a by task kworker/u5:0/110 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.2-1.fc38 04/01/2014 Workqueue: hci0 hci_cmd_sync_work [bluetooth] Call Trace: <TASK> dump_stack_lvl (lib/dump_stack.c:108) print_report (mm/kasan/report.c:352 mm/kasan/report.c:462) ? __virt_addr_valid (./include/linux/mmzone.h:1901 ./include/linux/mmzone.h:1997 arch/x86/mm/physaddr.c:65) ? hci_le_create_conn_sync (net/bluetooth/hci_sync.c:6167) bluetooth kasan_report (mm/kasan/report.c:574) ? hci_le_create_conn_sync (net/bluetooth/hci_sync.c:6167) bluetooth hci_le_create_conn_sync (net/bluetooth/hci_sync.c:6167) bluetooth ? __pfx_hci_le_create_conn_sync (net/bluetooth/hci_sync.c:6160) bluetooth ? vsnprintf (lib/vsprintf.c:2890) ? vsnprintf (lib/vsprintf.c:2890) ? __dynamic_pr_debug (lib/dynamic_debug.c:858) ? __pfx___dynamic_pr_debug (lib/dynamic_debug.c:858) ? hci_cmd_sync_work (net/bluetooth/hci_sync.c:305) bluetooth ? __pfx_hci_connect_le_sync (net/bluetooth/hci_conn.c:1311) bluetooth hci_cmd_sync_work (net/bluetooth/hci_sync.c:306) bluetooth process_one_work (kernel/workqueue.c:2410) ? __pfx_process_one_work (kernel/workqueue.c:2300) ? __pfx_do_raw_spin_lock (kernel/locking/spinlock_debug.c:113) ? mark_held_locks (kernel/locking/lockdep.c:4240) worker_thread (./include/linux/list.h:292 kernel/workqueue.c:2553) ? __pfx_worker_thread (kernel/workqueue.c:2495) kthread (kernel/kthread.c:379) ? __pfx_kthread (kernel/kthread.c:332) ret_from_fork (arch/x86/entry/entry_64.S:314) </TASK> Allocated by task 1321: kasan_save_stack (mm/kasan/common.c:46) kasan_set_track (mm/kasan/common.c:52) __kasan_kmalloc (mm/kasan/common.c:374 mm/kasan/common.c:383) hci_conn_add (./include/linux/slab.h:559 ./include/linux/slab.h:680 net/bluetooth/hci_conn.c:1002) bluetooth hci_connect_le (net/bluetooth/hci_conn.c:1374) bluetooth process_adv_report.constprop.0 (net/bluetooth/hci_event.c:6172 net/bluetooth/hci_event.c:6293) bluetooth hci_le_ext_adv_report_evt (net/bluetooth/hci_event.c:6527) bluetooth hci_event_packet (net/bluetooth/hci_event.c:7515 net/bluetooth/hci_event.c:7570) bluetooth hci_rx_work (net/bluetooth/hci_core.c:4085) bluetooth process_one_work (kernel/workqueue.c:2410) worker_thread (./include/linux/list.h:292 kernel/workqueue.c:2553) kthread (kernel/kthread.c:379) ret_from_fork (arch/x86/entry/entry_64.S:314) Freed by task 110: kasan_save_stack (mm/kasan/common.c:46) kasan_set_track (mm/kasan/common.c:52) kasan_save_free_info (mm/kasan/generic.c:523) __kasan_slab_free (mm/kasan/common.c:238 mm/kasan/common.c:200 mm/kasan/common.c:244) __kmem_cache_free (mm/slub.c:1807 mm/slub.c:3786 mm/slub.c:3799) device_release (drivers/base/core.c:2489) kobject_put (lib/kobject.c:683 lib/kobject.c:714 ./include/linux/kref.h:65 lib/kobject.c:731) hci_conn_hash_flush (net/bluetooth/hci_conn.c:2560) bluetooth hci_dev_close_sync (net/bluetooth/hci_sync.c:5021) bluetooth hci_dev_do_close (net/bluetooth/hci_core.c:556) bluetooth process_one_work (kernel/workqueue.c:2410) worker_thread (./include/linux/list.h:292 kernel/workqueue.c:2553) kthread (kernel/kthread.c:379) ret_from_fork (arch/x86/entry/entry_64.S:314) ================================================================== Signed-off-by: Pauli Virtanen <pav@xxxxxx> --- net/bluetooth/hci_conn.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index d489a4829be7..d6fd00ba243f 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -1280,6 +1280,9 @@ static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err) hci_dev_lock(hdev); + if (!hci_conn_is_alive(hdev, conn)) + goto done; + if (!err) { hci_connect_le_scan_cleanup(conn, 0x00); goto done; @@ -1295,6 +1298,7 @@ static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err) done: hci_dev_unlock(hdev); + hci_conn_put(conn); } static int hci_connect_le_sync(struct hci_dev *hdev, void *data) @@ -1303,6 +1307,14 @@ static int hci_connect_le_sync(struct hci_dev *hdev, void *data) bt_dev_dbg(hdev, "conn %p", conn); + /* TODO: fix conn race conditions in hci_sync, this is not enough */ + hci_dev_lock(hdev); + if (!hci_conn_is_alive(hdev, conn)) { + hci_dev_unlock(hdev); + return -ECANCELED; + } + hci_dev_unlock(hdev); + return hci_le_create_conn_sync(hdev, conn); } @@ -1375,9 +1387,11 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, conn->state = BT_CONNECT; clear_bit(HCI_CONN_SCANNING, &conn->flags); + hci_conn_get(conn); err = hci_cmd_sync_queue(hdev, hci_connect_le_sync, conn, create_le_conn_complete); if (err) { + hci_conn_put(conn); hci_conn_del(conn); return ERR_PTR(err); } -- 2.41.0