mirror of
https://github.com/torvalds/linux.git
synced 2026-10-23 23:51:02 +02:00
Bluetooth: hci_conn: Lock parent access during enhanced SCO setup
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 42de40abe2 ("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 fd179f8a05, which already contains 42de40abe2,
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: e07a06b4eb ("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>
This commit is contained in:
parent
c9c15d4d89
commit
024e05f73a
|
|
@ -302,11 +302,13 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data)
|
|||
cp.tx_bandwidth = cpu_to_le32(0x00001f40);
|
||||
cp.rx_bandwidth = cpu_to_le32(0x00001f40);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
switch (conn->codec.id) {
|
||||
case BT_CODEC_MSBC:
|
||||
if (!find_next_esco_param(conn, esco_param_msbc,
|
||||
ARRAY_SIZE(esco_param_msbc)))
|
||||
return -EINVAL;
|
||||
goto unlock;
|
||||
|
||||
param = &esco_param_msbc[conn->attempt - 1];
|
||||
cp.tx_coding_format.id = 0x05;
|
||||
|
|
@ -332,7 +334,7 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data)
|
|||
case BT_CODEC_TRANSPARENT:
|
||||
if (!find_next_esco_param(conn, esco_param_msbc,
|
||||
ARRAY_SIZE(esco_param_msbc)))
|
||||
return -EINVAL;
|
||||
goto unlock;
|
||||
|
||||
param = &esco_param_msbc[conn->attempt - 1];
|
||||
cp.tx_coding_format.id = 0x03;
|
||||
|
|
@ -359,11 +361,11 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data)
|
|||
if (conn->parent && lmp_esco_capable(conn->parent)) {
|
||||
if (!find_next_esco_param(conn, esco_param_cvsd,
|
||||
ARRAY_SIZE(esco_param_cvsd)))
|
||||
return -EINVAL;
|
||||
goto unlock;
|
||||
param = &esco_param_cvsd[conn->attempt - 1];
|
||||
} else {
|
||||
if (conn->attempt > ARRAY_SIZE(sco_param_cvsd))
|
||||
return -EINVAL;
|
||||
goto unlock;
|
||||
param = &sco_param_cvsd[conn->attempt - 1];
|
||||
}
|
||||
cp.tx_coding_format.id = 2;
|
||||
|
|
@ -386,9 +388,11 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data)
|
|||
cp.out_transport_unit_size = 16;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
cp.retrans_effort = param->retrans_effort;
|
||||
cp.pkt_type = __cpu_to_le16(param->pkt_type);
|
||||
cp.max_latency = __cpu_to_le16(param->max_latency);
|
||||
|
|
@ -397,6 +401,10 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data)
|
|||
return -EIO;
|
||||
|
||||
return 0;
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static bool hci_setup_sync_conn(struct hci_conn *conn, __u16 handle)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user