[PATCH] Bluetooth: HCI: fix slab-use-after-free in cmd_sync_work

Sungwoo Kim
2024-04-25T04:12:27Z

Hello, could you review the UAF bug and its fix?
The stack trace is at the bottom.

mgmt sync cmd could be used after freed in this scenario:

set_local_name() ... cmd is allocated, set_name_complete() is
queued in cmd_sync_work.
hci_error_reset() ... hci device reset.
hci_dev_close_sync() ... close hdev, at this point, cmd is freed.
set_name_complete() ... callback from cmd_sync_work. cmd->param causes UAF.

To fix this, this patch makes hci_dev_close_sync() call hci_cmd_sync_clear() to clear the cmd_sync_work.

Thanks,
Sungwoo Kim.

==================================================================
BUG: KASAN: slab-use-after-free in set_name_complete+0x4a/0x330 net/bluetooth/mgmt.c:3815
Read of size 8 at addr ffff888107259098 by task kworker/u3:0/66

CPU: 0 PID: 66 Comm: kworker/u3:0 Not tainted 6.8.0+ #61
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014
Workqueue: hci0 hci_cmd_sync_work
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:88 [inline]
dump_stack_lvl+0x85/0xb0 lib/dump_stack.c:106
print_address_description mm/kasan/report.c:377 [inline]
print_report+0x18f/0x560 mm/kasan/report.c:488
kasan_report+0xd7/0x110 mm/kasan/report.c:601
__asan_report_load8_noabort+0x18/0x20 mm/kasan/report_generic.c:381
set_name_complete+0x4a/0x330 net/bluetooth/mgmt.c:3815
hci_cmd_sync_work+0x269/0x3e0 net/bluetooth/hci_sync.c:308
process_one_work kernel/workqueue.c:2633 [inline]
process_scheduled_works+0x6b9/0xdc0 kernel/workqueue.c:2706
worker_thread+0xb2b/0x13d0 kernel/workqueue.c:2787
kthread+0x2a9/0x340 kernel/kthread.c:388
ret_from_fork+0x5c/0x90 arch/x86/kernel/process.c:147
ret_from_fork_asm+0x1b/0x30 arch/x86/entry/entry_64.S:243
</TASK>

Allocated by task 308:
kasan_save_stack mm/kasan/common.c:47 [inline]
kasan_save_track+0x30/0x70 mm/kasan/common.c:68
kasan_save_alloc_info+0x3c/0x50 mm/kasan/generic.c:575
poison_kmalloc_redzone mm/kasan/common.c:370 [inline]
__kasan_kmalloc+0xa2/0xc0 mm/kasan/common.c:387
kasan_kmalloc include/linux/kasan.h:211 [inline]
kmalloc_trace+0x1c9/0x390 mm/slub.c:4012
kmalloc include/linux/slab.h:590 [inline]
kzalloc include/linux/slab.h:711 [inline]
mgmt_pending_new+0x6f/0x230 net/bluetooth/mgmt_util.c:269
mgmt_pending_add+0x3f/0x120 net/bluetooth/mgmt_util.c:296
set_local_name+0x15a/0x4c0 net/bluetooth/mgmt.c:3892
hci_mgmt_cmd+0xb79/0x1190 net/bluetooth/hci_sock.c:1715
hci_sock_sendmsg+0x63a/0xf00 net/bluetooth/hci_sock.c:1835
sock_sendmsg_nosec net/socket.c:730 [inline]
__sock_sendmsg+0x227/0x270 net/socket.c:745
sock_write_iter+0x28d/0x3d0 net/socket.c:1160
do_iter_readv_writev+0x331/0x4c0
vfs_writev+0x2e6/0xa40 fs/read_write.c:971
do_writev+0xfd/0x250 fs/read_write.c:1018
__do_sys_writev fs/read_write.c:1091 [inline]
__se_sys_writev fs/read_write.c:1088 [inline]
__x64_sys_writev+0x86/0xa0 fs/read_write.c:1088
do_syscall_x64 arch/x86/entry/common.c:52 [inline]
do_syscall_64+0x84/0x120 arch/x86/entry/common.c:83
entry_SYSCALL_64_after_hwframe+0x6e/0x76

Freed by task 66:
kasan_save_stack mm/kasan/common.c:47 [inline]
kasan_save_track+0x30/0x70 mm/kasan/common.c:68
kasan_save_free_info+0x44/0x50 mm/kasan/generic.c:589
poison_slab_object+0x11a/0x190 mm/kasan/common.c:240
__kasan_slab_free+0x3b/0x60 mm/kasan/common.c:256
kasan_slab_free include/linux/kasan.h:184 [inline]
slab_free_hook mm/slub.c:2121 [inline]
slab_free mm/slub.c:4299 [inline]
kfree+0x106/0x2e0 mm/slub.c:4409
mgmt_pending_free net/bluetooth/mgmt_util.c:309 [inline]
mgmt_pending_remove+0x19e/0x1d0 net/bluetooth/mgmt_util.c:315
cmd_complete_rsp+0x104/0x1a0
mgmt_pending_foreach+0xc7/0x120 net/bluetooth/mgmt_util.c:259
__mgmt_power_off+0x137/0x370 net/bluetooth/mgmt.c:9496
hci_dev_close_sync+0x4ab/0xe80 net/bluetooth/hci_sync.c:4953
hci_dev_do_close net/bluetooth/hci_core.c:554 [inline]
hci_error_reset+0x150/0x410 net/bluetooth/hci_core.c:1060
process_one_work kernel/workqueue.c:2633 [inline]
process_scheduled_works+0x6b9/0xdc0 kernel/workqueue.c:2706
worker_thread+0xb2b/0x13d0 kernel/workqueue.c:2787
kthread+0x2a9/0x340 kernel/kthread.c:388
ret_from_fork+0x5c/0x90 arch/x86/kernel/process.c:147
ret_from_fork_asm+0x1b/0x30 arch/x86/entry/entry_64.S:243

The buggy address belongs to the object at ffff888107259080
which belongs to the cache kmalloc-96 of size 96
The buggy address is located 24 bytes inside of
freed 96-byte region [ffff888107259080, ffff8881072590e0)

The buggy address belongs to the physical page:
page:000000006bdb81a5 refcount:1 mapcount:0 mapping:0000000000000000 index:0xffff888107259280 pfn:0x107259
flags: 0x17ffffc0000a00(workingset|slab|node=0|zone=2|lastcpupid=0x1fffff)
page_type: 0xffffffff()
raw: 0017ffffc0000a00 ffff888100041780 ffffea0004145510 ffffea0004240190
raw: ffff888107259280 000000000020000f 00000001ffffffff 0000000000000000
page dumped because: kasan: bad access detected

Memory state around the buggy address:
ffff888107258f80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff888107259000: 00 00 00 00 00 00 00 00 00 00 00 fc fc fc fc fc
>ffff888107259080: fa fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
^
ffff888107259100: fa fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
ffff888107259180: 00 00 00 00 00 00 00 00 00 00 00 00 fc fc fc fc
==================================================================

Signed-off-by: Sungwoo Kim <iam@sung-woo.kim>
---
net/bluetooth/hci_core.c | 2 --
net/bluetooth/hci_sync.c | 5 ++++-
2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index a7028d38c..c347efc4f 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2764,8 +2764,6 @@ void hci_unregister_dev(struct hci_dev *hdev)

cancel_work_sync(&hdev->power_on);

- hci_cmd_sync_clear(hdev);
-
hci_unregister_suspend_notifier(hdev);

msft_unregister(hdev);
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index c5d879904..aa8e0c33c 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -5181,9 +5181,12 @@ int hci_dev_close_sync(struct hci_dev *hdev)
clear_bit(HCI_INIT, &hdev->flags);
}

- /* flush cmd work */
+ /* flush cmd work */
flush_work(&hdev->cmd_work);

+ /* flush cmd sync work */
+ hci_cmd_sync_clear(hdev);
+
/* Drop queues */
skb_queue_purge(&hdev->rx_q);
skb_queue_purge(&hdev->cmd_q);
--
2.34.1