[PATCH] Bluetooth: Fix use-after-free bug caused by hci_cmd_timeout

From: Duoming Zhou
Date: Mon Apr 08 2024 - 10:43:36 EST


If we send a command and the command is timeout, the hci_cmd_timeout()
will run. Then we use hci_sock_ioctl() to inquiry the command, it will
deallocate the req_skb. But the req_skb could be dereferenced in the
hci_cmd_timeout(). As a result, the use-after-free bug will happen.
The detail is shown below:

thread 1 thread2
hci_sock_ioctl() | hci_sock_sendmsg()
hci_inquiry() | queue_work(...,&hdev->cmd_work)
hci_req_sync() | hci_cmd_work()
__hci_req_sync() | queue_delayed_work(...,&hdev->cmd_timer)
kfree_skb(hdev->req_skb) | hci_cmd_timeout()
| hci_skb_opcode(hdev->req_skb)

The KASan report for such a POC is shown below:

==================================================================
BUG: KASAN: slab-use-after-free in hci_cmd_timeout+0x3c/0x110
Read of size 2 at addr ffff8880087a1c78 by task kworker/u21:0/131
...
Workqueue: hci0 hci_cmd_timeout
Call Trace:
<TASK>
dump_stack_lvl+0x84/0xc0
print_address_description+0x78/0x440
print_report+0x11b/0x220
? pfn_valid+0xe4/0x140
? __virt_addr_valid+0x7c/0x90
? hci_cmd_timeout+0x3c/0x110
kasan_report+0xc7/0x100
? hci_cmd_timeout+0x3c/0x110
hci_cmd_timeout+0x3c/0x110
process_one_work+0x2df/0x610
worker_thread+0x72f/0x870
? pr_cont_work+0x280/0x280
kthread+0x18a/0x1b0
? kthread_blkcg+0x50/0x50
ret_from_fork+0x34/0x50
? kthread_blkcg+0x50/0x50
ret_from_fork_asm+0x11/0x20
</TASK>

Allocated by task 131 on cpu 1 at 45.611537s:
kasan_save_track+0x32/0x90
__kasan_slab_alloc+0x4b/0x60
kmem_cache_alloc+0xcb/0x240
skb_clone+0x117/0x170
hci_cmd_work+0x19c/0x2a0
process_one_work+0x2df/0x610
worker_thread+0x72f/0x870
kthread+0x18a/0x1b0
ret_from_fork+0x34/0x50
ret_from_fork_asm+0x11/0x20

Freed by task 135 on cpu 2 at 47.671850s:
kasan_save_track+0x32/0x90
kasan_save_free_info+0x40/0x50
poison_slab_object+0x118/0x180
__kasan_slab_free+0x12/0x30
kmem_cache_free+0x92/0x200
__hci_req_sync+0x2e2/0x350
hci_req_sync+0x73/0x90
hci_inquiry+0x1c1/0x350
sock_do_ioctl+0x50/0x1a0
sock_ioctl+0x2ea/0x3b0
__se_sys_ioctl+0x89/0xd0
do_syscall_64+0xc4/0x1b0
entry_SYSCALL_64_after_hwframe+0x62/0x6a
...

In order to mitigate the bug, add cancel_delayed_work_sync() in
__hci_req_sync() to cancel the cmd_timer before the req_skb is
deallocated.

Fixes: 9afee94939e3 ("Bluetooth: Fix memory leak at end of hci requests")
Signed-off-by: Duoming Zhou <duoming@xxxxxxxxxx>
---
net/bluetooth/hci_request.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c
index 00e02138003..06692c71093 100644
--- a/net/bluetooth/hci_request.c
+++ b/net/bluetooth/hci_request.c
@@ -179,6 +179,7 @@ int __hci_req_sync(struct hci_dev *hdev, int (*func)(struct hci_request *req,
break;
}

+ cancel_delayed_work_sync(&hdev->cmd_timer);
kfree_skb(hdev->req_skb);
hdev->req_skb = NULL;
hdev->req_status = hdev->req_result = 0;
--
2.17.1