* [PATCH] Bluetooth: vhci: Serialize packet reception with device creation
@ 2026-10-24 15:28 Cen Zhang
2026-11-10 13:33 ` Chad Aldreda
0 siblings, 1 reply; 2+ messages in thread
From: Cen Zhang @ 2026-10-24 15:28 UTC (permalink / raw)
To: marcel, luiz.dentz
Cc: linux-bluetooth, linux-kernel, baijiaju1990, jjzuming, zzzccc427
The hci_dev passed to hci_recv_frame() must stay alive until the receive
operation finishes. __vhci_create_device() stores data->hdev before
hci_register_dev() and frees the device if registration fails.
vhci_get_user() checks and uses that pointer without taking the
open_mutex held by the creator or a device reference.
An incoming packet write can overlap the delayed default-create work
scheduled by vhci_open(). If registration fails before acquiring the
registration reference, the following order is possible:
Default-create work Packet write
vhci_create_device()
mutex_lock(open_mutex)
data->hdev = hdev
vhci_get_user()
load data->hdev
hci_register_dev() fails
hci_free_dev(hdev)
bt_host_release(): kfree(hdev)
data->hdev = NULL
mutex_unlock(open_mutex)
hci_recv_frame(hdev, skb)
read hdev->flags
The packet retains the pointer before the final put and reads flags
after the allocation is freed. The HCI_UP/HCI_INIT test therefore
accesses freed memory before it can reject the packet.
Hold open_mutex from the packet-side pointer check until
hci_recv_frame() returns. Creation and its error cleanup already hold
this mutex, so the writer waits until they finish and cannot retain a
failed device allocation. Release the mutex on the missing-device error
path too.
KASAN report as below:
BUG: KASAN: use-after-free in hci_recv_frame+0x4e/0x7e0
Read of size 8 at addr ffff888107034138 by task python3/500
Call Trace:
<TASK>
dump_stack_lvl+0x93/0xd0
print_report+0xce/0x630
? hci_recv_frame+0x4e/0x7e0
? srso_alias_return_thunk+0x5/0xfbef5
? __virt_addr_valid+0x20d/0x410
? hci_recv_frame+0x4e/0x7e0
kasan_report+0xe0/0x110
? hci_recv_frame+0x4e/0x7e0
kasan_check_range+0x105/0x1b0
hci_recv_frame+0x4e/0x7e0
vhci_write+0x35a/0x4c0
vfs_write+0x637/0x1010
? __pfx_vhci_write+0x10/0x10
? __might_fault+0xdd/0x190
? __pfx_vfs_write+0x10/0x10
? __pfx_hrtimer_wakeup+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
? srso_alias_return_thunk+0x5/0xfbef5
? common_nsleep_timens+0xa8/0x160
ksys_write+0x111/0x200
? __pfx_ksys_write+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
? restore_fpregs_from_fpstate+0x55/0x100
do_syscall_64+0x115/0x6a0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000
index:0xffff888107036a40 pfn:0x107034
flags: 0x200000000000000(node=0|zone=2)
raw: 0200000000000000 ffffea00041c0308 ffff8881887bf180
0000000000000000
raw: ffff888107036a40 0000000000000000 00000000ffffffff
0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff888107034000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ffff888107034080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>ffff888107034100: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
^
ffff888107034180: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ffff888107034200: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
==================================================================
Fixes: 23424c0d3169 ("Bluetooth: Add support creating virtual AMP controllers")
Assisted-by: LLM
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
---
diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
index 8f7db0102b25f..de7d4d67e46e9 100644
--- a/drivers/bluetooth/hci_vhci.c
+++ b/drivers/bluetooth/hci_vhci.c
@@ -524,7 +524,9 @@ static inline ssize_t vhci_get_user(struct vhci_data *data,
case HCI_ACLDATA_PKT:
case HCI_SCODATA_PKT:
case HCI_ISODATA_PKT:
+ mutex_lock(&data->open_mutex);
if (!data->hdev) {
+ mutex_unlock(&data->open_mutex);
kfree_skb(skb);
return -ENODEV;
}
@@ -532,6 +534,7 @@ static inline ssize_t vhci_get_user(struct vhci_data *data,
hci_skb_pkt_type(skb) = pkt_type;
ret = hci_recv_frame(data->hdev, skb);
+ mutex_unlock(&data->open_mutex);
break;
case HCI_VENDOR_PKT:
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH] Bluetooth: vhci: Serialize packet reception with device creation
2026-10-24 15:28 [PATCH] Bluetooth: vhci: Serialize packet reception with device creation Cen Zhang
@ 2026-11-10 13:33 ` Chad Aldreda
0 siblings, 0 replies; 2+ messages in thread
From: Chad Aldreda @ 2026-11-10 13:33 UTC (permalink / raw)
To: Cen Zhang, Marcel Holtmann, Luiz Augusto von Dentz
Cc: linux-bluetooth, linux-kernel, baijiaju1990, jjzuming
On Sat, 24 Oct 2026, Cen Zhang wrote:
> An incoming packet write can overlap the delayed default-create work
> scheduled by vhci_open(). If registration fails before acquiring the
> registration reference, the following order is possible:
The use-after-free reproduces on mainline without added delays, and
your patch removes it.
Tested on mainline v7.4-rc1-672-gd48723711bae, whose hci_vhci.c
matches bluetooth-next at 983f3fcb1282, on x86_64 in QEMU (4 vCPUs)
with KASAN, lockdep, DEBUG_LIST and kmemleak. A test program opens
/dev/vhci and creates the controller by writing the vendor packet
0xff 0x00, which runs __vhci_create_device() under open_mutex like the
default-create work (fail-nth is per task, so creation was driven from
the test thread rather than the delayed work). Fault injection
(failslab with ignore-gfp-wait=N, and fail-nth on the creating thread)
fails one allocation inside hci_register_dev(), so creation frees the
hci_dev it has already stored in data->hdev and returns -EBUSY.
Meanwhile a second thread keeps writing HCI event packets on the same
fd.
Without your patch, 300 cycles (295 with a failed registration) gave
42 KASAN reports: use-after-free reads at the same four sites in
hci_recv_frame() called from vhci_write(), 10 or 11 at each site. With
your patch, 300 cycles (296 failed registrations) gave none.
With two test-only delays, msleep(50) after "data->hdev = hdev;" and
msleep(100) at the start of hci_recv_frame(), every cycle with a
failed registration hits without the patch (39 cycles, 156 reports at
the same four sites; a verbose run shows each is an 8-byte read), at
both an early and a late allocation failure in hci_register_dev(). The
writer saw exactly 39 writes fail with an error other than -ENODEV, one
per failed registration (the errno itself was not recorded),
consistent with the HCI_UP/HCI_INIT test rejecting them. With the
patch and the same delays, 170 cycles (161 failed registrations) were
clean, and no write failed with anything but -ENODEV. These delayed
runs are the decisive comparison.
No lockdep, DEBUG_LIST, kmemleak or hung-task reports in any run with
the patch, so holding open_mutex across hci_recv_frame() caused no
lock-order report here; open_mutex has no other users in hci_vhci.c.
Not tested: the delayed default-create work itself (creation was
triggered by the vendor packet, which takes the same path under the
same mutex), registration failures other than injected allocation
failures, ACL, SCO or ISO packets (only event packets were written),
real controllers or btvirt, other architectures, and a build of
bluetooth-next itself (compared at source level only).
The test program and this report were produced with an AI assistant
(Claude Opus 5.5), which also did the runs above, including the
unpatched comparison. I ran the final version on the patched kernel
myself and got the same results. The test program is available on
request.
Tested-by: Chad Aldreda <ca@modelmiser.com>
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-11-10 13:33 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-24 15:28 [PATCH] Bluetooth: vhci: Serialize packet reception with device creation Cen Zhang
2026-11-10 13:33 ` Chad Aldreda
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®