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

From: Duoming Zhou
Date: Tue Apr 09 2024 - 23:53:35 EST


When the kernel send a command to the hci device, the hdev->cmd_timer
will be scheduled to judge whether is command is timeout.

Meanwhile, the user space program uses ioctl(..., HCI_INQUIRY) to inquiry
the status of the command, it will wait the reply of the command until
the command is timeout. If it is timeout, the req_skb will be deallocated,
but req_skb could be dereferenced in hci_cmd_timeout() as well.

As a result, the use-after-free bug will happen. One of the scenarios
that could trigger the bug 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 when the command is timeout.

Fixes: 9afee94939e3 ("Bluetooth: Fix memory leak at end of hci requests")
Signed-off-by: Duoming Zhou <duoming@xxxxxxxxxx>
---
Changes in v2:
- Call cancel_delayed_work_sync() only if the command is timeout.

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..0b002f01816 100644
--- a/net/bluetooth/hci_request.c
+++ b/net/bluetooth/hci_request.c
@@ -174,6 +174,7 @@ int __hci_req_sync(struct hci_dev *hdev, int (*func)(struct hci_request *req,

default:
err = -ETIMEDOUT;
+ cancel_delayed_work_sync(&hdev->cmd_timer);
if (hci_status)
*hci_status = HCI_ERROR_UNSPECIFIED;
break;
--
2.17.1