Skip to content

Commit bb5f541

Browse files
Ychamegregkh
authored andcommitted
Bluetooth: hci_sync: Fix accept list UAF during suspend
[ Upstream commit f57b399 ] hci_update_event_filter_sync() walks hdev->accept_list while sending a synchronous HCI command for each remote-wakeup device. The suspend path holds hdev->req_lock, but accept-list updates are serialized by hdev->lock. Consequently, remove_device() can free the current list entry during the controller wait. The following interleaving causes the use-after-free: hci_update_event_filter_sync() remove_device() fetch accept-list entry hci_set_event_filter_sync() wait for controller response hci_dev_lock() list_del() kfree() hci_dev_unlock() read the freed list.next KASAN reported: BUG: KASAN: slab-use-after-free in hci_suspend_sync+0x835/0x910 Read of size 8 at addr ffff88810bec8440 by task kworker/0:1/10 Workqueue: events vhci_suspend_work Call Trace: hci_suspend_sync+0x835/0x910 hci_suspend_dev+0x182/0x450 process_one_work+0x661/0x1090 worker_thread+0x45b/0xd10 Allocated by task 86: hci_bdaddr_list_add_with_flags+0x1a8/0x400 add_device+0x381/0x820 hci_sock_sendmsg+0x1033/0x1ea0 Freed by task 91: kfree+0x131/0x3c0 remove_device+0x429/0xb70 hci_sock_sendmsg+0x1033/0x1ea0 Snapshot the remote-wakeup addresses under hdev->lock. Release the lock before sending HCI commands. Clear the controller event filter before building the snapshot, and skip allocation and the second list traversal when there are no matching entries. This preserves the original filter and scan-state updates without retaining an accept-list node across a controller wait. Fixes: 182ee45 ("Bluetooth: hci_sync: Rework hci_suspend_notifier") Cc: stable@vger.kernel.org Link: https://lore.kernel.org/linux-bluetooth/20260730092331.2069741-1-nicoyip.dev@gmail.com/ Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 163a91e commit bb5f541

1 file changed

Lines changed: 37 additions & 9 deletions

File tree

net/bluetooth/hci_sync.c

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6011,6 +6011,8 @@ static int hci_pause_discovery_sync(struct hci_dev *hdev)
60116011
static int hci_update_event_filter_sync(struct hci_dev *hdev)
60126012
{
60136013
struct bdaddr_list_with_flags *b;
6014+
bdaddr_t *accept_list;
6015+
size_t i, num_entries = 0;
60146016
u8 scan = SCAN_DISABLED;
60156017
bool scanning = test_bit(HCI_PSCAN, &hdev->flags);
60166018
int err;
@@ -6027,23 +6029,49 @@ static int hci_update_event_filter_sync(struct hci_dev *hdev)
60276029
/* Always clear event filter when starting */
60286030
hci_clear_event_filter_sync(hdev);
60296031

6030-
list_for_each_entry(b, &hdev->accept_list, list) {
6031-
if (!(b->flags & HCI_CONN_FLAG_REMOTE_WAKEUP))
6032-
continue;
6032+
hci_dev_lock(hdev);
6033+
6034+
list_for_each_entry(b, &hdev->accept_list, list)
6035+
if (b->flags & HCI_CONN_FLAG_REMOTE_WAKEUP)
6036+
num_entries++;
60336037

6034-
bt_dev_dbg(hdev, "Adding event filters for %pMR", &b->bdaddr);
6038+
if (!num_entries) {
6039+
hci_dev_unlock(hdev);
6040+
goto update_scan;
6041+
}
60356042

6036-
err = hci_set_event_filter_sync(hdev, HCI_FLT_CONN_SETUP,
6037-
HCI_CONN_SETUP_ALLOW_BDADDR,
6038-
&b->bdaddr,
6039-
HCI_CONN_SETUP_AUTO_ON);
6043+
accept_list = kmalloc_array(num_entries, sizeof(*accept_list),
6044+
GFP_KERNEL);
6045+
if (!accept_list) {
6046+
hci_dev_unlock(hdev);
6047+
return -ENOMEM;
6048+
}
6049+
6050+
i = 0;
6051+
list_for_each_entry(b, &hdev->accept_list, list)
6052+
if (b->flags & HCI_CONN_FLAG_REMOTE_WAKEUP)
6053+
bacpy(&accept_list[i++], &b->bdaddr);
6054+
6055+
hci_dev_unlock(hdev);
6056+
6057+
for (i = 0; i < num_entries; i++) {
6058+
bt_dev_dbg(hdev, "Adding event filters for %pMR",
6059+
&accept_list[i]);
6060+
6061+
err = hci_set_event_filter_sync(hdev, HCI_FLT_CONN_SETUP,
6062+
HCI_CONN_SETUP_ALLOW_BDADDR,
6063+
&accept_list[i],
6064+
HCI_CONN_SETUP_AUTO_ON);
60406065
if (err)
60416066
bt_dev_err(hdev, "Failed to set event filter for %pMR",
6042-
&b->bdaddr);
6067+
&accept_list[i]);
60436068
else
60446069
scan = SCAN_PAGE;
60456070
}
60466071

6072+
kfree(accept_list);
6073+
6074+
update_scan:
60476075
if (scan && !scanning)
60486076
hci_write_scan_enable_sync(hdev, scan);
60496077
else if (!scan && scanning)

0 commit comments

Comments
 (0)