aboutsummaryrefslogtreecommitdiff
path: root/net/bluetooth
AgeCommit message (Collapse)AuthorFilesLines
4 daysBluetooth: ISO: Serialize concurrent connect callsChengfeng Ye1-10/+37
iso_sock_connect() checks the socket state before taking the socket lock and drops the lock again before setting up a connection. Two callers can both pass the admission check while the socket is open or bound. Caller A can copy its destination for route selection, then caller B can replace the socket destination before A binds or connects the CIS. A then uses B's destination with the route selected for its own request. B can also proceed after A attaches a connection and sets BT_CONNECT. For deferred BIS setup, B can bind a second BIS and overwrite iso_pi(sk)->conn, leaving the first connection's reference and conn->sk back-pointer stranded. Concurrent CIS connects can likewise replace the socket's connection. Later teardown only detaches the current connection, so a callback on the old connection can race with socket release and access a freed socket. KASAN reported: BUG: KASAN: slab-use-after-free in iso_sock_hold+0xf7/0x1b0 Call Trace: iso_sock_hold+0xf7/0x1b0 iso_conn_del+0x7b/0x1d0 iso_connect_cfm+0x186/0x16a0 hci_conn_failed+0x154/0x280 hci_abort_conn_sync+0x3dc/0x7d0 hci_cmd_sync_work+0x173/0x300 Allocated by task 121: sk_alloc+0x2b/0x6d0 bt_sock_alloc+0x29/0x370 iso_sock_alloc.constprop.0+0x19/0x300 iso_sock_create+0x94/0x100 Freed by task 121: kfree+0x121/0x3c0 __sk_destruct+0x42b/0x540 iso_sock_release+0x29d/0x340 __sock_release+0xa1/0x260 Check admission under the socket lock and mark the connect operation in progress before publishing its destination. Keep that flag set across route lookup and connection setup, rejecting another connect with -EBADFD before it can change the destination or attach a connection. Clear the flag after either helper returns, including on failure, so a failed setup can be retried. A separate flag is needed because the socket lock must be released before acquiring the HCI device lock, while BT_CONNECT requires an attached connection. Keep the existing state transitions and the deferred CIS completion through iso_sock_recvmsg(). Reject an existing socket attachment in __iso_chan_add() before taking a new reference or publishing either pointer, so every caller preserves the connection association. Keep the same-socket, same-connection success case for deferred CIS setup. Reject an attached socket before BIS setup so a reusable BIS is not claimed before the attachment is rejected. In CIS setup, reject a different HCI connection before iso_conn_add() and drop the per-attempt HCI hold directly. An unowned iso_conn may still carry another reference after detachment, so its destruction cannot be relied on to release that hold. iso_listen_bis() creates a fresh PA HCI/ISO pair under the device lock, so the temporary iso_conn_put() frees the ISO candidate and drops its HCI hold on rejection. iso_conn_ready() uses a freshly allocated, unpublished child with no connection, making the socket-side rejection unreachable. Fixes: ccf74f2390d6 ("Bluetooth: Add BTPROTO_ISO socket type") Cc: stable@vger.kernel.org Suggested-by: Pauli Virtanen <pav@iki.fi> Assisted-by: GPT-6 Astra Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
4 daysBluetooth: ISO: Reject concurrent BIS listener setupChengfeng Ye1-0/+5
iso_sock_listen() drops the socket lock before calling iso_listen_bis() to preserve the hdev->lock ordering. Two concurrent listen() calls on the same broadcast socket can therefore both observe BT_BOUND. Caller A can attach connA and release the locks, then caller B can acquire them and attach connB before A publishes BT_LISTEN. __iso_chan_add() checks whether connB already has a socket, but not whether the socket already has a connection. The second attachment overwrites iso_pi(sk)->conn, leaking the connA reference and leaving connA->sk intact. Socket teardown follows connB, so later events on connA can cause a stale socket access. Recheck BT_BOUND and require iso_pi(sk)->conn to be NULL after taking both the HCI device and socket locks in iso_listen_bis(). The connection check also covers the interval between attachment and publication of BT_LISTEN. Reject a competing setup with -EBADFD through the existing unlock path before allocating another connection. A recorded KASAN report from an instrumented kernel shows: BUG: KASAN: slab-use-after-free in iso_sock_hold+0x119/0x1f0 Call Trace: iso_sock_hold+0x119/0x1f0 iso_conn_del+0xe4/0x270 hci_disconn_complete_evt+0x351/0x8c0 hci_event_packet+0x71b/0xb20 hci_rx_work+0x293/0x730 Allocated by task 93: sk_prot_alloc+0x113/0x220 sk_alloc+0x2b/0x6d0 bt_sock_alloc+0x29/0x370 iso_sock_alloc.constprop.0+0x19/0x300 iso_sock_create+0x94/0x100 Freed by task 93: kfree+0x121/0x3c0 __sk_destruct+0x42b/0x540 iso_sock_release+0x29d/0x340 __sock_release+0xa1/0x260 sock_close+0x10/0x20 Fixes: 168e28305b87 ("Bluetooth: iso: Fix circular lock in iso_listen_bis") Cc: stable@vger.kernel.org Assisted-by: GPT-6 Astra Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
4 daysBluetooth: hci_sync: Fix command skb lifetime during scan setupChengfeng Ye2-1/+13
During PA sync scan setup, hci_le_set_ext_scan_param_sync() gets the address used for the PA_LINK lookup from hci_sent_cmd_data(). The returned pointer borrows storage from sent_cmd or req_skb, without holding a reference to either skb. The scan worker runs on req_workqueue while hci_cmd_work() runs on the separate device workqueue. After the scan worker loads sent_cmd, the command worker can free and replace it before hci_sent_cmd_data() dereferences the skb. The command payload can also be freed between returning from the helper and comparing the address. The connection lookup's RCU critical section does not protect the command skb. KASAN reported: BUG: KASAN: slab-use-after-free in hci_sent_cmd_data+0x27c/0x2f0 Workqueue: hci0 hci_cmd_sync_work Call Trace: hci_sent_cmd_data+0x27c/0x2f0 hci_le_set_scan_param_sync+0x43a/0x850 hci_passive_scan_sync+0xb09/0x1460 hci_update_passive_scan_sync+0x47c/0x6e0 hci_le_pa_create_sync+0x200/0xa70 hci_cmd_sync_work+0x13c/0x290 Allocated by task 95: skb_clone+0x13f/0x340 hci_cmd_work+0x2a9/0x7e0 Freed by task 95: kmem_cache_free+0xba/0x3a0 hci_cmd_work+0x29c/0x7e0 Use hdev->lock to serialize the address snapshot with sent_cmd replacement. Protect req_skb replacement and completion cleanup with the same lock because the helper falls back to that skb. Copy the address before releasing the lock and use the copy for the existing RCU-protected connection lookup. Release the mutex before sending or waiting for commands, preserving the lookup and completion ordering. Fixes: 22cbf4f84c00 ("Bluetooth: hci_sync: Use QoS to determine which PHY to scan") Cc: stable@vger.kernel.org Assisted-by: GPT-6 Astra Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
4 daysBluetooth: hci_sock: Serialize dead-device detachmentChengfeng Ye1-0/+2
Rebinding an HCI socket after its controller is unregistered can race monitor control replay and crash the kernel. hci_sock_bind() clears hci_pi(sk)->hdev and drops the device reference under only the socket lock, whereas send_monitor_control_replay() holds hci_sk_list.lock for reading. Replay can observe a non-NULL hdev, then bind can clear it and drop the last reference before create_monitor_ctrl_open() reads hdev->id. This can cause a NULL pointer dereference if the pointer is reloaded, or a use-after-free if the old pointer is retained. The kernel reported: KASAN: null-ptr-deref in range [0x0000000000000068-0x000000000000006f] RIP: 0010:create_monitor_ctrl_open+0x579/0x800 Call Trace: hci_sock_bind+0xd96/0x1190 __sys_bind+0x166/0x200 __x64_sys_bind+0x6d/0xb0 do_syscall_64+0xdd/0x4a0 entry_SYSCALL_64_after_hwframe+0x77/0x7f The same missing serialization lets hci_send_to_sock() select a socket for the old device and queue its frame after bind has detached the socket or installed a new binding. Take hci_sk_list.lock for writing when clearing the device pointer and resetting the socket state. This waits for existing replay and delivery readers to finish before detachment and prevents later readers from using the old binding. Keep hci_dev_put() outside the critical section because the final device release can sleep. Fixes: e04480920d1e ("Bluetooth: defer cleanup of resources in hci_unregister_dev()") Cc: stable@vger.kernel.org Assisted-by: GPT-6 Astra Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
7 daysBluetooth: RFCOMM: Fix NULL tty_dev dereference in rfcomm_dev_shutdownPalla Raghunath1-1/+1
syzbot hit a NULL pointer dereference in rfcomm_dev_shutdown() when an RFCOMM tty is closed. rfcomm_dev_add() puts the new device on rfcomm_dev_list first and only then registers the tty device and saves it in dev->tty_dev. If that registration fails, dev->tty_dev is never set at all. The device can be looked up in the meantime, so an open() of /dev/rfcommN gets through rfcomm_tty_install() and attaches to it. When that tty is closed again, rfcomm_dev_shutdown() uses dev->tty_dev without checking it: Oops: general protection fault, probably for non-canonical address KASAN: null-ptr-deref in range [0x0000000000000040-0x0000000000000047] RIP: 0010:rfcomm_dev_shutdown+0x48/0xb0 net/bluetooth/rfcomm/tty.c:131 Call Trace: tty_port_shutdown+0x1bf/0x220 drivers/tty/tty_port.c:372 tty_port_close+0x4e/0x150 drivers/tty/tty_port.c:705 tty_release+0x359/0x1670 drivers/tty/tty_io.c:1718 __fput+0x418/0xa50 fs/file_table.c:512 rfcomm_dev_destruct() already copes with a NULL dev->tty_dev. Add the same check to rfcomm_dev_shutdown(), so the tty device is only moved when it was actually registered. Fixes: cad348a17e17 ("Bluetooth: Implement .activate, .shutdown and .carrier_raised methods") Reported-by: syzbot+4a807caf7680652d53b6@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=4a807caf7680652d53b6 Cc: stable@vger.kernel.org Signed-off-by: Palla Raghunath <raghunathpalla.0209@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
10 daysBluetooth: MGMT: Fix status of pending commands flushed on power offIaroslav Voitovych1-1/+1
cmd_complete_rsp() receives a struct cmd_lookup and, for a pending command that has no cmd_complete callback, falls through to cmd_status_rsp(cmd, data). cmd_status_rsp() reads data as a u8 *, so the status sent comes from the first byte of match->sk's representation, not from match->mgmt_status. commit f53e1c9c726d ("Bluetooth: MGMT: Fix possible crash on mgmt_index_removed") changed the callers' data from &status to &match and updated the cmd_complete branch to match->mgmt_status, but left the fall-through passing data unchanged. In mgmt_index_removed() match->sk is NULL, so every such command is answered with status 0x00 (Success) instead of MGMT_STATUS_INVALID_INDEX. In __mgmt_power_off() it is NULL too, unless a Set Powered command was pending: then settings_rsp() has stored that command's socket in match->sk, and the byte sent comes from the socket pointer. Either way the status the caller set, MGMT_STATUS_NOT_POWERED (or MGMT_STATUS_INVALID_INDEX when the device is being unregistered), is lost. Pass the status the callers set. This was seen on a QCA9377 laptop: bluetoothd's Start Discovery, pending when the adapter was powered off, was answered with Command Status 0x00 and no parameters, and bluetoothd 5.72 crashed on the zero-length success. BlueZ master has since added the length check on that path ("adapter: Fix crash on short start discovery reply", BlueZ a734b06059cb), but userspace should still be told Not Powered, not Success. Tested on Ubuntu 7.0.0-31 with a virtual controller (hci_vhci): power off is held in HCI Write Scan Enable while a Start Discovery is submitted, and the flush answers it with status 0x00 before this change and 0x0f (Not Powered) after. Fixes: f53e1c9c726d ("Bluetooth: MGMT: Fix possible crash on mgmt_index_removed") Cc: stable@vger.kernel.org Signed-off-by: Iaroslav Voitovych <yaroslav.voytovych@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
10 daysBluetooth: RFCOMM: connect the session socket without rfcomm_mutexMikhail Gavrilov1-39/+95
An RFCOMM connect() issued while a BR/EDR link is being authenticated makes lockdep report a circular dependency, and the reported cycle is a real AB/BA between rfcomm_mutex and hdev->lock. rfcomm_security_cfm() is called from the HCI event path, which already holds hdev->lock: hci_rx_work() hci_event_packet() hci_cc_read_enc_key_size() [hdev->lock] hci_encrypt_cfm() [hci_cb_list_lock] rfcomm_security_cfm() [rfcomm_mutex] while an RFCOMM connect() from userspace takes the same two locks the other way round: rfcomm_sock_connect() rfcomm_dlc_open() [rfcomm_mutex] __rfcomm_dlc_open() rfcomm_session_create() kernel_connect() l2cap_sock_connect() l2cap_chan_connect() [hdev->lock] WARNING: possible circular locking dependency detected kworker/u131:1/1128 is trying to acquire lock: rfcomm_mutex, at: rfcomm_security_cfm+0x31/0x3e0 [rfcomm] but task is already holding lock: hci_cb_list_lock, at: hci_cc_read_enc_key_size+0x1d2/0xcc0 Chain exists of: rfcomm_mutex --> &hdev->lock --> hci_cb_list_lock hci_auth_complete_evt() and hci_encrypt_change_evt() reach the callback the same way. Both orders have to be seen in the same boot, which is why a BR/EDR connection alone is not enough to show it: a session set up by the remote side is created by rfcomm_accept_connection() in krfcommd, which calls kernel_accept() and never takes hdev->lock under rfcomm_mutex. Connecting a device that authenticates and encrypts the link and then calling connect() on an RFCOMM socket towards any address - the connect does not have to succeed, the order is recorded before the page timeout - reports it every time. Only the session socket has to be connected with the lock held, and it does not: nothing else can see the socket before it is put on the session list. So connect it first and take rfcomm_mutex afterwards, which removes the rfcomm_mutex -> hdev->lock order for good, rather than keeping the HCI event path out of rfcomm_mutex. rfcomm_session_create() becomes rfcomm_session_connect(), which returns the connected socket without touching the session list, and rfcomm_dlc_open() adds the session once it holds the lock again. If another opener added a session for the same pair while this socket was connecting, that session is used and this socket is dropped. __rfcomm_dlc_open() now takes the session it should use, and its state check runs after the lock is re-acquired, so a DLC that was opened or closed in the meantime is still handled. Over an existing ACL link the connection can complete before the session reaches the list, and the wakeup from the socket callback is then lost, so krfcommd is woken once the session is visible. Connecting without the lock opens a window in which the socket can be closed. The DLC is not on a session yet, so rfcomm_dlc_close() finds nothing to do and returns without touching it, and rfcomm_dlc_open() would then attach a DLC whose owner is gone. rfcomm_dlc_close() now marks such a DLC with RFCOMM_CLOSED, and rfcomm_dlc_open() checks the mark once it holds rfcomm_mutex again and drops the socket instead of attaching the DLC. The mark is cleared when an open starts, so a DLC that is reused is not affected. This covers both callers of rfcomm_dlc_open(), the socket and the tty layer. Fixes: 759c185d0bbd ("Bluetooth: RFCOMM: serialize security confirmation handling") Suggested-by: Pauli Virtanen <pav@iki.fi> Reported-by: Pauli Virtanen <pav@iki.fi> Closes: https://lore.kernel.org/linux-bluetooth/5e76a95e934e451e7006db28827c2d64af5a88be.camel@iki.fi/ Reported-by: syzbot+74071deb72339c215b2e@syzkaller.appspotmail.com Closes: https://lore.kernel.org/linux-bluetooth/6a92fadc.08e933ee.dbf97.008f.GAE@google.com/ Reported-by: Jiaming Zhang <r772577952@gmail.com> Closes: https://lore.kernel.org/all/CANypQFabseTuRiyz2pGkc_Qj0moGDnY7KEp1qdTOqkw6gAL3hw@mail.gmail.com/ Cc: stable@vger.kernel.org Signed-off-by: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com> Tested-by: syzbot+74071deb72339c215b2e@syzkaller.appspotmail.com Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
11 daysBluetooth: SCO: serialise sco_conn lifetime against sco_recv_scodata()Aldo Ariel Panzardo1-22/+65
sco_recv_scodata() upgrades the weak hcon->sco_data back-pointer to a strong reference under hdev->lock: hci_dev_lock(hdev); hcon = hci_conn_hash_lookup_handle(hdev, handle); ... conn = sco_conn_hold_unless_zero(hcon->sco_data); hci_dev_unlock(hdev); but the pointer is cleared from the other side without that lock. When the last sco_conn reference is dropped, sco_conn_free() ran conn->hcon->sco_data = NULL; with no hdev->lock held, so the RX path could read hcon->sco_data and call kref_get_unless_zero() on an sco_conn that was concurrently freed: BUG: KASAN: slab-use-after-free in sco_conn_hold_unless_zero+0xbe/0x160 Write of size 4 by task kworker/u17:0 Workqueue: hci0 hci_rx_work Call Trace: sco_conn_hold_unless_zero+0xbe/0x160 sco_recv_scodata+0x13f/0x490 hci_rx_work+0x3af/0x730 kref_get_unless_zero() only guards against a zero refcount, not against the backing memory already being freed. Give hcon->sco_data an actual reference on the sco_conn it points to, so the object cannot be freed while the pointer is still installed, and only clear and drop it from sco_conn_del(), which runs under hdev->lock (its callers, sco_connect_cfm() and sco_disconn_cfm(), hold it). The reader in sco_recv_scodata() also takes hdev->lock, so the store and the read are now serialised: the RX path either observes NULL or a reference that is guaranteed to stay valid until it drops its own. sco_conn_add() no longer hands its kref_init() reference to the caller as the connection's only reference; that initial reference is the one owned by hcon->sco_data, and callers get their own via sco_conn_hold(). Because the sco_conn can now outlive the socket (the association keeps it alive until the link goes down), the hci_conn can no longer be dropped from sco_conn_free() without regressing socket close: closing a connected SCO socket must still tear the link down. Move hci_conn ownership to the socket instead: __sco_chan_add() takes an hci_conn reference and it is released from sco_chan_del() and sco_sock_destruct(), exactly once. The sco_conn no longer owns an hci_conn reference, so sco_conn_add() stops consuming one and sco_connect() drops the hci_connect_sco() reference on every path; sco_connect_cfm() no longer needs its hci_conn_hold() dance. Fixes: e6720779ae61 ("Bluetooth: SCO: Use kref to track lifetime of sco_conn") Cc: stable@vger.kernel.org Suggested-by: Pauli Virtanen <pav@iki.fi> Signed-off-by: Aldo Ariel Panzardo <qwe.aldo@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
11 daysBluetooth: RFCOMM: free the skb when the DLC has no ownerMaxim Skokov1-1/+4
rfcomm_recv_data() hands the skb to d->data_ready() and returns 0 without freeing it, so the callback owns the skb from that point on. The tty implementation frees it when the DLC has been detached from its device: static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb) { struct rfcomm_dev *dev = dlc->owner; if (!dev) { kfree_skb(skb); return; } The socket implementation returns without freeing it, and the skb is leaked. A connected DLC can have no owner: rfcomm_sock_destruct() clears d->owner, while the DLC itself stays on the session until it is closed. Data frames that arrive in that window still find d->state == BT_CONNECTED in rfcomm_recv_data() and are handed to the callback, one leaked skb each. The leak does not stop on its own either. The remote runs out of credits only once RFCOMM_RX_THROTTLED is set, and for a socket the only place that sets it is rfcomm_sk_data_ready() itself, below the return. rfcomm_process_dlcs() keeps granting credits, so the remote keeps sending and the leak keeps growing. Free the skb, as the tty side does. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reported-by: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com> Closes: https://lore.kernel.org/linux-bluetooth/CABXGCsPe5wykd8Aj-hm+SJ7SGQyb8yoGNnx3XDpPmBathj+EGg@mail.gmail.com/ Cc: stable@vger.kernel.org Signed-off-by: Maxim Skokov <skokovmaksimevg@gmail.com> Assisted-by: Claude:claude-opus-5 Reviewed-by: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
11 daysBluetooth: hci_core: Serialize SCO and ISO scheduling with teardownChengfeng Ye1-8/+18
hci_low_sent() selects a connection under RCU but drops the read lock before calculating its quota and returning it to the scheduler. The connection is then used without lifetime protection by hci_sched_iso() and hci_sched_sco(). After the TX worker drops the RCU read lock, hci_abort_conn_sync() on hdev->req_workqueue can remove the connection from the hash, complete synchronize_rcu(), purge its queues and release it. The TX worker on hdev->workqueue can then access the freed connection in hci_quote_sent() or while dequeuing packets and updating conn->sent. KASAN reported: BUG: KASAN: slab-use-after-free in hci_low_sent+0x730/0x840 Workqueue: hci0 hci_tx_work Call Trace: hci_low_sent+0x730/0x840 hci_sched_iso+0x25e/0x4d0 hci_tx_work+0x239/0xcb0 Allocated by task 93: __hci_conn_add+0x16f/0x1b40 hci_bind_bis+0x782/0x17b0 hci_connect_bis+0xa0/0x510 iso_sock_connect+0x589/0x1050 Freed by task 88: kfree+0x131/0x3c0 device_release+0xc8/0x240 kobject_put+0x14d/0x280 hci_conn_del+0x55a/0xe80 hci_disconnect_sync+0x156/0x180 hci_abort_conn_sync+0x3e7/0x940 hci_cmd_sync_work+0x13c/0x290 Hold hci_dev_lock() across connection selection and transmission in both SCO and ISO scheduling, serializing them with connection teardown. This also prevents queuing completion timestamps after the connection queues have been purged. Extending RCU across transmission would be unsafe because the transmit path can sleep. Keep the ISO timeout check outside the mutex since hci_link_tx_to() takes it itself. The preceding channel fix already holds this mutex in the ACL and LE schedulers, which call the SCO scheduler between packets. Move the SCO body to __hci_sched_sco(), assert that its caller holds the mutex, and use it directly from these locked paths. Keep a locking hci_sched_sco() wrapper for the direct calls from hci_tx_work(). This avoids recursively acquiring the device mutex while preserving the scheduling order. Remove the obsolete claim that connection removal disables TX. Fixes: bf4c63252490 ("Bluetooth: convert conn hash to RCU") Cc: stable@vger.kernel.org Assisted-by: LLM Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
11 daysBluetooth: hci_core: Serialize ACL scheduling with channel deletionChengfeng Ye1-0/+8
hci_chan_sent() selects a channel under RCU but drops the read lock before accessing chan->conn and returning the channel. The ACL and LE schedulers then use its packet queue and update its transmit counters without any protection against channel deletion. After TX selects a channel and releases RCU, a disconnect command timeout on the separate request workqueue can run hci_conn_failed() and l2cap_conn_del(). hci_chan_del() can then unlink the channel, complete synchronize_rcu(), purge its queue and free it before TX resumes. This causes use-after-free both in hci_chan_sent() and in its callers. KASAN reported: BUG: KASAN: slab-use-after-free in hci_chan_sent+0x892/0x9b0 Workqueue: hci0 hci_tx_work Call Trace: hci_chan_sent+0x892/0x9b0 hci_tx_work+0x5e6/0xb70 Allocated by task 91: hci_chan_create+0xe3/0x350 l2cap_conn_add.part.0+0x12/0xa30 l2cap_chan_connect+0x110d/0x1b60 l2cap_sock_connect+0x310/0x530 Freed by task 99: hci_chan_del+0x11f/0x170 l2cap_conn_del+0x4f1/0x800 l2cap_connect_cfm+0x88c/0xd30 hci_conn_failed+0x150/0x250 hci_abort_conn_sync+0x3e3/0x800 hci_cmd_sync_run+0x7e/0xc0 hci_abort_conn+0x105/0x1f0 disconnect_sync+0x157/0x290 hci_cmd_sync_work+0x13c/0x290 Hold the existing device mutex across channel selection and transmission in both schedulers to serialize them with channel teardown. Keep timeout handling outside the critical sections because hci_link_tx_to() acquires the same mutex. This also permits the transmit path to sleep, unlike extending the RCU read-side critical section across packet submission. Fixes: 3eff45eaf817 ("Bluetooth: convert tx_task to workqueue") Cc: stable@vger.kernel.org Assisted-by: LLM Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
11 daysBluetooth: Serialize SMP remote OOB data accessChengfeng Ye2-1/+13
build_pairing_cmd() looks up remote OOB data and copies its contents without holding hdev->lock, which serializes the list's writers. After SMP finds an entry, a concurrent management Remove Remote OOB Data command can unlink and free it before SMP reads its present flag or copies its random and confirmation values. Removal can also invalidate an entry while the lookup is still traversing the list. KASAN reported: BUG: KASAN: slab-use-after-free in build_pairing_cmd+0x948/0x9b0 Call Trace: build_pairing_cmd+0x948/0x9b0 smp_recv_cb+0x459f/0x8110 l2cap_recv_frame+0xf14/0x9190 l2cap_recv_acldata+0xa64/0xd40 hci_rx_work+0x4ca/0x730 Allocated by task 87: hci_add_remote_oob_data+0x11d/0x530 add_remote_oob_data+0x282/0x400 hci_sock_sendmsg+0x1033/0x1ea0 Freed by task 93: hci_remote_oob_data_clear+0x108/0x1c0 remove_remote_oob_data+0x198/0x220 hci_sock_sendmsg+0x1033/0x1ea0 Taking hdev->lock in build_pairing_cmd() would recurse for callers that already hold it and invert the device-to-L2CAP lock order on the receive path. Add a per-device remote_oob_lock instead, held across the SMP lookup and copies and by the add, remove and clear helpers. Cover initialization and in-place updates as well, so SMP cannot read partially initialized or updated OOB values. Release the mutex on allocation failure, preserving the existing error return. The new critical sections acquire no device, connection or channel locks. Writers retain their existing hdev->lock protection, which continues to serialize the other readers without changing their locking or behavior. Link: https://lore.kernel.org/r/00660cd3-7d71-13a4-f617-229e6defb701@gmail.com Fixes: 02b05bd8b0a6 ("Bluetooth: Set SMP OOB flag if OOB data is available") Cc: stable@vger.kernel.org Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
11 daysBluetooth: RFCOMM: Fix initial port reference raceChengfeng Ye1-4/+3
For RFCOMM_RELEASE_ONHUP devices, rfcomm_tty_install() and __rfcomm_release_dev() both use RFCOMM_TTY_OWNED to decide who drops the initial tty_port reference. The release path tests the bit separately from the install path setting it, so both can drop that reference. The synchronous hangup does not prevent this race: port->tty is not assigned until tty_port_open(), after installation. The following interleaving is possible: 1. Install and release each obtain a reference with rfcomm_dev_get(). 2. Release observes RFCOMM_TTY_OWNED clear. 3. Install sets RFCOMM_TTY_OWNED and drops the initial reference. 4. Release drops the same initial reference again. 5. TTY cleanup drops its reference and frees the device. 6. Release performs its final tty_port_put() on the freed port. KASAN reported: BUG: KASAN: slab-use-after-free in tty_port_put+0x22/0x190 Write of size 4 at addr ffff8881001d3d5c by task poc/92 Call Trace: tty_port_put+0x22/0x190 rfcomm_dev_ioctl+0x1d4/0x1930 sock_do_ioctl+0x110/0x260 sock_ioctl+0x380/0x590 __x64_sys_ioctl+0x134/0x1c0 Allocated by task 88: rfcomm_dev_ioctl+0x8f6/0x1930 sock_do_ioctl+0x110/0x260 sock_ioctl+0x380/0x590 __x64_sys_ioctl+0x134/0x1c0 Freed by task 65: kfree+0x131/0x3c0 rfcomm_dev_destruct+0x23b/0x2f0 release_one_tty+0xc1/0x370 process_one_work+0x661/0x1090 Use test_and_set_bit() in both paths so that only the caller that changes RFCOMM_TTY_OWNED from clear to set drops the initial reference. Each path keeps its own lookup reference until release or TTY cleanup, preserving the existing callback ordering and error handling. Fixes: 80ea73378af4 ("Bluetooth: Fix unreleased rfcomm_dev reference") Cc: stable@vger.kernel.org Assisted-by: LLM Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
11 daysBluetooth: hci_sync: Fix inquiry cache use-after-freeChengfeng Ye1-2/+11
The sync command worker holds hdev->req_lock, but inquiry-cache updates and flushes use hdev->lock. Both hci_acl_create_conn_sync() and hci_stop_discovery_sync() look up entries and read their fields without taking hdev->lock. After either lookup returns, a concurrent HCIINQUIRY ioctl can acquire hdev->lock and flush the cache, freeing the entry. The worker then reads the freed entry while preparing a create-connection or remote-name-cancel command. The list traversal also races with cache updates and removal. KASAN reported these accesses: BUG: KASAN: slab-use-after-free in hci_acl_create_conn_sync+0x5f1/0x650 Workqueue: hci0 hci_cmd_sync_work Call Trace: hci_acl_create_conn_sync+0x5f1/0x650 hci_cmd_sync_work+0x13c/0x290 Allocated by task 90: hci_inquiry_cache_update+0x3e6/0x7d0 hci_inquiry_result_evt+0x3cb/0x560 Freed by task 93: hci_inquiry_cache_flush+0x111/0x2b0 hci_inquiry+0x2f2/0x780 hci_sock_ioctl+0x269/0x5f0 BUG: KASAN: slab-use-after-free in hci_stop_discovery_sync+0x3b1/0x3c0 Workqueue: hci0 hci_cmd_sync_work Call Trace: hci_stop_discovery_sync+0x3b1/0x3c0 hci_cmd_sync_work+0x173/0x300 Allocated by task 86: hci_inquiry_cache_update+0x483/0x940 hci_inquiry_result_evt+0x3cb/0x560 Freed by task 91: hci_inquiry_cache_flush+0x13e/0x2f0 hci_inquiry+0x2f2/0x780 hci_sock_ioctl+0x269/0x5f0 Hold hdev->lock across each lookup and all reads from its result. Copy the remote address before unlocking so discovery cancellation does not retain a cache entry pointer. Release the lock before sending synchronous HCI commands, since their completion handlers may need the same lock. Fixes: cf75ad8b41d2 ("Bluetooth: hci_sync: Convert MGMT_SET_POWERED") Fixes: 45340097ce6e ("Bluetooth: hci_conn: Only do ACL connections sequentially") Cc: stable@vger.kernel.org Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
11 daysBluetooth: hci_sync: don't drain cmd_sync backlog on unregisterNguyen Ngoc Thang1-0/+6
hci_unregister_dev() disables cmd_work and cmd_timer, then calls hci_cmd_sync_clear(), whose cancel_work_sync() waits for hci_cmd_sync_work() to return. That worker dequeues and runs every entry on cmd_sync_work_list. With cmd_work disabled nothing reaches the controller, so each queued HCI command waits the full HCI_CMD_TIMEOUT (2s). The backlog has no bound. Userspace can keep queuing MGMT commands such as MGMT_OP_GET_CLOCK_INFO against a controller that doesn't answer. Closing /dev/vhci then blocks in vhci_release() for backlog * 2s: INFO: task syz-executor:5749 blocked for more than 143 seconds. cancel_work_sync hci_cmd_sync_clear hci_unregister_dev vhci_release In a local reproduction the backlog held more than 5000 entries, which comes to hours of hang. Stop the worker from taking new entries once HCI_UNREGISTER is set, and wake any request still waiting with -ENODEV before cancelling the work. The entries left over are destroyed with -ECANCELED by the existing sweep in hci_cmd_sync_clear(). They stay on the list until the work has stopped, so hci_cmd_sync_dequeue() and friends still see them. A callback already running may still issue another command, which delays unregister by at most one timeout per remaining command, not by the whole backlog. Fixes: 008ee9eb8a11 ("Bluetooth: hci_sync: Fix not processing all entries on cmd_sync_work") Reported-by: syzbot+217e3f1283cafe80586e@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=217e3f1283cafe80586e Signed-off-by: Nguyen Ngoc Thang <ngocthang2710.1999@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
11 daysBluetooth: hci_core: Serialize fragmented ISO packet queueingChengfeng Ye1-0/+4
The fragmented path in hci_queue_iso() calls __skb_queue_tail() without holding conn->data_q.lock. The socket lock serializes senders, but the transmit worker can concurrently remove packets from this queue using skb_dequeue(). After an insertion saves the old tail pointer, hci_sched_iso() can dequeue that packet and pass it to the driver. The driver can free the packet before the insertion resumes and writes to the old tail's next pointer, causing a use-after-free. Concurrent updates can also corrupt the queue. KASAN reported: BUG: KASAN: slab-use-after-free in hci_send_iso+0xc7d/0xe10 Call Trace: hci_send_iso+0xc7d/0xe10 iso_sock_sendmsg+0x710/0x900 __sys_sendto+0x34a/0x3a0 Allocated by task 86: __alloc_skb+0xdd/0x820 alloc_skb_with_frags+0x7e/0x770 sock_alloc_send_pskb+0x67a/0x820 bt_skb_sendmsg.constprop.0+0xc0/0x6c0 iso_sock_sendmsg+0x44e/0x900 Freed by task 90: kmem_cache_free+0xcb/0x3d0 vhci_read+0x33f/0x4d0 vfs_read+0x177/0xa20 Hold the queue lock across the entire fragment batch, as hci_queue_acl() does, to serialize insertion against dequeue while preserving fragment ordering. Fixes: 26afbd826ee3 ("Bluetooth: Add initial implementation of CIS connections") Cc: stable@vger.kernel.org Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
11 daysBluetooth: hci_conn: Lock parent access during enhanced SCO setupChengfeng Ye1-5/+13
Bluetooth: hci_conn: Lock parent access during enhanced SCO setup hci_enhanced_setup_sync() runs on the request workqueue without the hci_dev_lock held by its caller when setup was queued. Its CVSD capability check and find_next_esco_param() dereference conn->parent while the receive workqueue can unlink and release that parent. The following interleaving can cause a use-after-free: hci_enhanced_setup_sync() hci_disconn_complete_evt() load conn->parent hci_dev_lock() hci_conn_del(ACL parent) unlink SCO child drop link's parent reference clear child->parent release ACL parent bt_link_release() kfree(parent) hci_dev_unlock() read parent->features[0][3] The reference held for the queued SCO child does not keep its ACL parent alive after unlinking. Commit 42de40abe25d ("Bluetooth: hci_conn: fix the SCO setup context lifetime") protects the child stored in the queued context, but leaves these parent accesses unprotected. With a 40 ms diagnostic delay after loading conn->parent, an instrumented kernel based on fd179f8a05be, which already contains 42de40abe25d, reported: BUG: KASAN: slab-use-after-free in hci_enhanced_setup_sync+0xda5/0xdf0 Read of size 1 at addr ffff888102204047 by task kworker/u17:0/93 Call Trace: hci_enhanced_setup_sync+0xda5/0xdf0 hci_cmd_sync_work+0x13c/0x290 process_one_work+0x6b4/0x10e0 Allocated by task 92: __hci_conn_add+0x304/0x1df0 hci_connect_acl+0x349/0x3e0 hci_connect_sco+0x3b/0x9a0 sco_sock_connect+0x475/0xca0 Freed by task 94: kfree+0x121/0x3c0 bt_link_release+0x79/0xa0 device_release+0xc8/0x240 kobject_put+0x14d/0x280 hci_conn_del+0x524/0xe30 hci_disconn_complete_evt+0x403/0x8c0 hci_event_packet+0x71b/0xb20 hci_rx_work+0x293/0x730 The accessed address is 71 bytes into the freed ACL parent, at its features[0][3] byte; the queued SCO child is a different object. The diagnostic preserves the loaded parent across the delay, matching the unmodified compiled capability check, and does not change the parent references or teardown path. Hold hci_dev_lock() across the codec switch, including every call to find_next_esco_param(), and release it on all selection errors. Keep configure_datapath_sync() outside the critical section because it waits for HCI events. Preserve parameter selection and existing return values. Fixes: e07a06b4eb41 ("Bluetooth: Convert SCO configure_datapath to hci_sync") Cc: stable@vger.kernel.org Assisted-by: GPT-6-Astra Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-09-23Bluetooth: hci_core: free the HCI ID if naming failsSang-Hoon Choi1-1/+3
hci_register_dev() allocates an ID before calling dev_set_name(). If naming fails, it returns without releasing that ID. The device has not been registered and hdev->id has not been assigned, so the normal unregister path cannot release it. Free the allocated ID before returning the naming error. Fixes: dcda165706b9 ("Bluetooth: hci_core: Fix build warnings") Reported-by: Changyul Lee <lcy8047@gmail.com> Assisted-by: LLM Signed-off-by: Sang-Hoon Choi <csh0052@gmail.com> Reported-by: Changyul Lee <lcy8047@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-09-23Bluetooth: hci_core: Fix inquiry cache timestamps on 64-bit systemsLinmao Li1-1/+1
On 64-bit systems, outgoing BR/EDR connections always fall back to page scan repetition mode R2 with no clock offset once the system has been up for more than five minutes, even when inquiry found the peer only seconds earlier. This lengthens paging and can increase the risk of a Page Timeout. The inquiry cache stores jiffies in __u32 timestamps, but its age helpers subtract them from unsigned long jiffies. INITIAL_JIFFIES casts -300 * HZ through unsigned int, so jiffies crosses 2^32 five minutes after boot on 64-bit systems. Assigning it to __u32 then drops the upper 32 bits. In one trace, a 7.6-second-old entry (HZ=1000) was reported as 2^32 + 7620 ticks old and rejected by hci_acl_create_conn_sync(). hci_inquiry() is affected by the same truncation when checking the whole cache. 32-bit systems are unaffected because unsigned long is 32 bits wide there. Use unsigned long for both timestamps so they have the same width as jiffies on 32-bit and 64-bit systems, and update the debugfs format specifier accordingly. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Signed-off-by: Linmao Li <lilinmao@kylinos.cn> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-09-21Bluetooth: RFCOMM: Reject short EA=0 frames in rfcomm_recv_frame()Hui Peng1-1/+2
While rfcomm_recv_frame() verifies that skb->len is at least sizeof(*hdr) + 1 (4 bytes: 3-byte header + 1-byte FCS), an RFCOMM frame with an extended 2-byte length field (!__test_ea(hdr->len)) has a 4-byte header plus a 1-byte FCS (5 bytes minimum, sizeof(*hdr) + 2). When a 4-byte RFCOMM frame with EA == 0 arrives: 1. The initial skb->len < sizeof(*hdr) + 1 check passes (4 < 4 is false). 2. Trimming the FCS byte decrements skb->len to 3. 3. If __check_fcs() succeeds, skb_pull(skb, 4) fails (4 > 3) and returns NULL without advancing skb->data. 4. Because the return value of skb_pull() is ignored, the un-pulled 3-byte struct rfcomm_hdr remains at skb->data and is either queued as application payload via rfcomm_recv_data() or parsed as a multiplexer control command via rfcomm_recv_mcc() on DLCI 0. Fix this by extending the length check in rfcomm_recv_frame() to also require skb->len >= sizeof(*hdr) + 2 when !__test_ea(hdr->len). Fixes: b230e5bf501c ("Bluetooth: RFCOMM: validate skb length in rfcomm_recv_frame") Assisted-by: LLM Signed-off-by: Hui Peng <benquike@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-09-21Bluetooth: RFCOMM: fix NULL dereference of dlc->session in RFCOMM_CONNINFOHui Peng1-2/+4
The RFCOMM_CONNINFO getsockopt handler accepts a socket that is not connected as long as deferred setup is enabled: if (sk->sk_state != BT_CONNECTED && !rfcomm_pi(sk)->dlc->defer_setup) { err = -ENOTCONN; break; } l2cap_sk = rfcomm_pi(sk)->dlc->session->sock->sk; dlc->defer_setup is set in rfcomm_sock_init() when rfcomm_connect_ind() creates a child socket for an incoming connection on a listening socket that has BT_DEFER_SETUP enabled. It is never cleared afterwards. The session, however, can go away underneath it. rfcomm_recv_disc() forces the dlc state before tearing it down: d->state = BT_CLOSED; __rfcomm_dlc_close(d, err); The RFCOMM_DEFER_SETUP early return in __rfcomm_dlc_close() only covers BT_CONNECT, BT_CONFIG, BT_OPEN and BT_CONNECT2, so with the state already BT_CLOSED that switch does not match and the function falls through to rfcomm_dlc_unlink(), which sets d->session = NULL, while d->defer_setup stays 1. A getsockopt(SOL_RFCOMM, RFCOMM_CONNINFO) on the accepted socket after that point therefore skips the -ENOTCONN path -- sk->sk_state is BT_CLOSED, but dlc->defer_setup is still set -- and dereferences the NULL session. No race is needed: once the DISC has been processed, the dereference is unconditional. Reproduced on a KASAN kernel under QEMU with a BR/EDR peer emulated over /dev/vhci: the peer brings up an ACL link, opens L2CAP on the RFCOMM PSM, starts a session and sends SABM for a channel bound with BT_DEFER_SETUP, and sends DISC for that dlci after the socket has been accepted. getsockopt(SOL_RFCOMM, RFCOMM_CONNINFO) on the accepted socket then hits: Oops: general protection fault, probably for non-canonical address 0xdffffc0000000002: 0000 [#1] SMP KASAN PTI KASAN: null-ptr-deref in range [0x0000000000000010-0x0000000000000017] CPU: 1 UID: 0 PID: 150 Comm: init Tainted: G B 7.3.0-rc3-g5dd1818b15d9 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996) RIP: 0010:rfcomm_sock_getsockopt+0x529/0x780 Call Trace: <TASK> do_sock_getsockopt+0x3ad/0x7d0 __sys_getsockopt+0x10e/0x1b0 __x64_sys_getsockopt+0xc2/0x160 do_syscall_64+0xda/0x4b0 entry_SYSCALL_64_after_hwframe+0x77/0x7f </TASK> 0x10 is the offset of sock in struct rfcomm_session; rfcomm_sock_getsockopt_old() is inlined into rfcomm_sock_getsockopt(). Commit 43a556b2fd43 ("Bluetooth: RFCOMM: take rfcomm_mutex for the deferred setup accept") fixed the same "a remote DISC clears the session while deferred setup is still flagged" problem in rfcomm_dlc_accept(); this is the remaining instance of it, in the getsockopt path. Deferred setup only leaves a socket usable here once it has reached BT_CONNECT2, so restrict the exception to that state and check that a session is actually present before following it. Fixes: bb23c0ab8246 ("Bluetooth: Add support for deferring RFCOMM connection setup") Cc: stable@vger.kernel.org Assisted-by: LLM Signed-off-by: Hui Peng <benquike@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-09-21Bluetooth: bnep: fix out-of-bounds reads on short RX/TX frames and control ↵Hui Peng2-2/+23
fallthrough Fix multiple out-of-bounds reads in Bluetooth BNEP frame processing: 1. In bnep_rx_frame() and bnep_ctrl_frame() (net/bluetooth/bnep/core.c), use pskb_may_pull() to verify the BNEP header, control type byte, filter count, and extension headers exist before reading them, and return 0 after handling BNEP_CONTROL instead of falling through to Ethernet frame submission when no extension headers follow. 2. In bnep_net_xmit() (net/bluetooth/bnep/netdev.c), verify skb->len >= ETH_HLEN with pskb_may_pull() before reading the 14-byte Ethernet header to prevent an out-of-bounds heap read and infoleak on short AF_PACKET TX frames. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Assisted-by: LLM Signed-off-by: Hui Peng <benquike@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-09-16Bluetooth: mgmt: fix race in read_unconf_index_list()Aldo Ariel Panzardo1-6/+2
read_unconf_index_list() counts unconfigured controllers before allocating its response, then checks the device flags again while filling it. hci_dev_list_lock stabilizes list membership, but it does not serialize the per-device flags. During asynchronous controller setup, the worker can set HCI_UNCONFIGURED and clear HCI_SETUP between the two passes. A controller omitted from the allocation count can then become eligible for the fill pass, causing an out-of-bounds write to rp->index[]. Allocate space for every device on hci_dev_list. Since list membership cannot change while hci_dev_list_lock is held, the response remains large enough regardless of flag transitions. The reported count and response length still include only eligible unconfigured controllers. Fixes: 73d1df2a7a10 ("Bluetooth: Add support for Read Unconfigured Index List command") Cc: stable@vger.kernel.org Signed-off-by: Aldo Ariel Panzardo <qwe.aldo@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-09-16Bluetooth: L2CAP: validate frame length before control and FCS accessAldo Ariel Panzardo1-1/+9
l2cap_data_rcv() unpacks either a two-byte or four-byte control field without first ensuring that it is present. A short ERTM or streaming-mode frame can therefore cause an out-of-bounds read. There is a second short-frame case when CRC16 is enabled. After the control field is pulled, l2cap_check_fcs() subtracts two from skb->len without checking it. If fewer than two bytes remain, the subtraction wraps; skb_trim() leaves the buffer unchanged and the subsequent FCS load reads past the logical end of the frame. Validate that the frame contains both its control field and, when enabled, its FCS before either field is accessed. Fixes: 1c2acffb76d4 ("Bluetooth: Add initial support for ERTM packets transfers") Fixes: fcc203c30d72 ("Bluetooth: Add support for FCS option to L2CAP") Cc: stable@vger.kernel.org Signed-off-by: Aldo Ariel Panzardo <qwe.aldo@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-09-16Bluetooth: ISO: balance the parent hold in hci_bind_bis()Aldo Ariel Panzardo1-1/+4
hci_conn_link() takes a lifetime reference to its parent with hci_conn_get(), but only takes an operational hold on the child. hci_conn_unlink() later balances both a hold and a reference on the parent. The SCO and CIS paths pass a parent acquired from a connect helper, so it already has a hold. For an additional BIS, hci_bind_bis() obtains the parent from hci_conn_hash_lookup_big(), which returns a bare pointer. Unlinking the child then drops the parent's existing hold and can schedule it for disconnection while its socket is still using it. Take a hold on the parent before linking it and drop that hold if linking fails. A successful link transfers the hold to hci_conn_unlink(). Fixes: fa224d0c094a ("Bluetooth: ISO: Reassociate a socket with an active BIS") Cc: stable@vger.kernel.org Signed-off-by: Aldo Ariel Panzardo <qwe.aldo@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-09-16Bluetooth: hci_sock: validate event length before filteringAldo Ariel Panzardo1-3/+14
is_filtered_packet() reads the event code from skb->data[0] without first checking that the skb is nonempty. When an opcode filter is configured, it also reads the command opcode at offsets 3 or 4 without checking that a Command Complete or Command Status event is long enough. hci_send_to_sock() invokes the filter before hci_event_packet() validates the event header. A malformed event supplied by a controller or a vhci device can therefore cause an out-of-bounds read. Keep the unmasked event code for the opcode checks. The masked value is needed for the 64-bit event bitmap, but using it to identify command events aliases event codes above 0x3f. In particular, Synchronous Train Complete (0x4f) was treated as Command Status (0x0f) even though its payload has no opcode. Reject actual command events that are too short for the field being inspected. A truncated command event cannot match a configured opcode. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Signed-off-by: Aldo Ariel Panzardo <qwe.aldo@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-09-16Bluetooth: hci_sock: reject out-of-range OCF valuesAldo Ariel Panzardo1-1/+2
The raw HCI socket security filter has 128 OCF bits per supported OGF, but masks the 10-bit OCF with 127 before looking up the command. An unprivileged socket can therefore submit a reserved OCF that aliases an allowlisted command modulo 128. A conforming controller should reject reserved opcodes. Nevertheless, the security decision must apply to the opcode that will actually be sent, especially since controller-specific behavior is outside the host stack's control. Reject OCF values that cannot be represented by the security filter instead of aliasing them onto an unrelated command. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Signed-off-by: Aldo Ariel Panzardo <qwe.aldo@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-09-16Bluetooth: ISO: release unused CIS holds after c