From: Myungho Jung <mhjungk@xxxxxxxxx> commit e20a2e9c42c9e4002d9e338d74e7819e88d77162 upstream When releasing socket, it is possible to enter hci_sock_release() and hci_sock_dev_event(HCI_DEV_UNREG) at the same time in different thread. The reference count of hdev should be decremented only once from one of them but if storing hdev to local variable in hci_sock_release() before detached from socket and setting to NULL in hci_sock_dev_event(), hci_dev_put(hdev) is unexpectedly called twice. This is resolved by referencing hdev from socket after bt_sock_unlink() in hci_sock_release(). Reported-by: syzbot+fdc00003f4efff43bc5b@xxxxxxxxxxxxxxxxxxxxxxxxx Signed-off-by: Myungho Jung <mhjungk@xxxxxxxxx> Signed-off-by: Marcel Holtmann <marcel@xxxxxxxxxxxx> Signed-off-by: Zubin Mithra <zsm@xxxxxxxxxxxx> --- Notes: * Syzkaller reported a UAF read with the following call trace when fuzzing a 4.4 kernel. Call Trace: [<ffffffff8198c89a>] __dump_stack lib/dump_stack.c:15 [inline] [<ffffffff8198c89a>] dump_stack+0xbf/0x113 lib/dump_stack.c:51 [<ffffffff8146d0d8>] print_trailer+0x14c/0x155 mm/slub.c:658 [<ffffffff814542cd>] check_bytes_and_report+0xa8/0xe9 mm/slub.c:725 [<ffffffff814546d2>] check_object+0x108/0x1eb mm/slub.c:846 [<ffffffff81454f84>] alloc_debug_processing+0x65/0x103 mm/slub.c:1057 [<ffffffff8145519a>] ___slab_alloc.constprop.68+0x178/0x3c3 mm/slub.c:2421 [<ffffffff8145542d>] __slab_alloc.isra.63.constprop.67+0x48/0x79 mm/slub.c:2450 [<ffffffff814558f4>] slab_alloc_node mm/slub.c:2513 [inline] [<ffffffff814558f4>] slab_alloc mm/slub.c:2555 [inline] [<ffffffff814558f4>] __kmalloc+0xb6/0x170 mm/slub.c:3521 [<ffffffff82f97bf4>] kmalloc include/linux/slab.h:481 [inline] [<ffffffff82f97bf4>] kzalloc.constprop.17+0x1c/0x1e include/linux/slab.h:620 [<ffffffff82f97c15>] hci_alloc_dev+0x1f/0x156c net/bluetooth/hci_core.c:2945 [<ffffffff827ce5ab>] __vhci_create_device+0x8c/0x3f9 drivers/bluetooth/hci_vhci.c:114 [<ffffffff827cebe0>] vhci_create_device drivers/bluetooth/hci_vhci.c:163 [inline] [<ffffffff827cebe0>] vhci_get_user drivers/bluetooth/hci_vhci.c:219 [inline] [<ffffffff827cebe0>] vhci_write+0x2c8/0x317 drivers/bluetooth/hci_vhci.c:299 [<ffffffff81473309>] new_sync_write fs/read_write.c:478 [inline] [<ffffffff81473309>] __vfs_write+0x22c/0x2dd fs/read_write.c:491 [<ffffffff81474724>] vfs_write+0x14c/0x182 fs/read_write.c:538 [<ffffffff814759e1>] SYSC_write fs/read_write.c:585 [inline] [<ffffffff814759e1>] SyS_write+0xdf/0x163 fs/read_write.c:577 [<ffffffff832c56ba>] entry_SYSCALL_64_fastpath+0x31/0xb3 * This commit is present in 4.9.y. * Applying the original upstream commit causes a conflict as there is a change in the surrounding code. * Tests run: Chrome OS tryjobs, Syzkaller reproducer net/bluetooth/hci_sock.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index c842f40c1173..ea1cd8b21708 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -558,13 +558,12 @@ static int hci_sock_release(struct socket *sock) if (!sk) return 0; - hdev = hci_pi(sk)->hdev; - if (hci_pi(sk)->channel == HCI_CHANNEL_MONITOR) atomic_dec(&monitor_promisc); bt_sock_unlink(&hci_sk_list, sk); + hdev = hci_pi(sk)->hdev; if (hdev) { if (hci_pi(sk)->channel == HCI_CHANNEL_USER) { /* When releasing an user channel exclusive access, -- 2.21.0.392.gf8f6787159e-goog