mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 08:15:07 -04:00
Bluetooth: hci_conn: fix the SCO setup context lifetime
hci_setup_sync() queues a conn_handle_t with a NULL destroy callback, so the context is only freed if hci_enhanced_setup_sync() actually runs. An entry that is cancelled instead is leaked, as _hci_cmd_sync_cancel_entry() does not release entry->data when there is no destroy callback, and hci_cmd_sync_clear() cancels every pending entry when the controller is unregistered. The context also stores a bare hci_conn pointer, so the connection can be freed while the work is queued. The dequeue in hci_conn_del() does not cover it either, as it matches on entry->data == conn and entry->data is the wrapper here. Same problem as commit2f5d635ad5("Bluetooth: hci_sync: hold conn in hci_connect_acl/le_sync() callbacks"). Hold the connection and release both from a destroy callback. The submission failure path drops both, since hci_cmd_sync_submit() does not call the destroy callback when it fails to queue. Fixes:e07a06b4eb("Bluetooth: Convert SCO configure_datapath to hci_sync") Signed-off-by: Linmao Li <lilinmao@kylinos.cn> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
committed by
Luiz Augusto von Dentz
parent
f57b399c4f
commit
42de40abe2
@@ -283,8 +283,6 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data)
|
||||
struct hci_cp_enhanced_setup_sync_conn cp;
|
||||
const struct sco_param *param;
|
||||
|
||||
kfree(conn_handle);
|
||||
|
||||
if (!hci_conn_valid(hdev, conn))
|
||||
return -ECANCELED;
|
||||
|
||||
@@ -453,6 +451,15 @@ static bool hci_setup_sync_conn(struct hci_conn *conn, __u16 handle)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void hci_enhanced_setup_sync_destroy(struct hci_dev *hdev, void *data,
|
||||
int err)
|
||||
{
|
||||
struct conn_handle_t *conn_handle = data;
|
||||
|
||||
hci_conn_put(conn_handle->conn);
|
||||
kfree(conn_handle);
|
||||
}
|
||||
|
||||
bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
|
||||
{
|
||||
int result;
|
||||
@@ -464,12 +471,15 @@ bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
|
||||
if (!conn_handle)
|
||||
return false;
|
||||
|
||||
conn_handle->conn = conn;
|
||||
conn_handle->conn = hci_conn_get(conn);
|
||||
conn_handle->handle = handle;
|
||||
result = hci_cmd_sync_queue(conn->hdev, hci_enhanced_setup_sync,
|
||||
conn_handle, NULL);
|
||||
if (result < 0)
|
||||
conn_handle,
|
||||
hci_enhanced_setup_sync_destroy);
|
||||
if (result < 0) {
|
||||
hci_conn_put(conn);
|
||||
kfree(conn_handle);
|
||||
}
|
||||
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user