Commit 3dcaa192 authored by Pauli Virtanen's avatar Pauli Virtanen Committed by Luiz Augusto von Dentz

Bluetooth: SCO: fix sco_conn related locking and validity issues

Operations that check/update sk_state and access conn should hold
lock_sock, otherwise they can race.

The order of taking locks is hci_dev_lock > lock_sock > sco_conn_lock,
which is how it is in connect/disconnect_cfm -> sco_conn_del ->
sco_chan_del.

Fix locking in sco_connect to take lock_sock around updating sk_state
and conn.

sco_conn_del must not occur during sco_connect, as it frees the
sco_conn. Hold hdev->lock longer to prevent that.

sco_conn_add shall return sco_conn with valid hcon. Make it so also when
reusing an old SCO connection waiting for disconnect timeout (see
__sco_sock_close where conn->hcon is set to NULL).

This should not reintroduce the issue fixed in the earlier
commit 9a8ec9e8 ("Bluetooth: SCO: Fix possible circular locking
dependency on sco_connect_cfm"), the relevant fix of releasing lock_sock
in sco_sock_connect before acquiring hdev->lock is retained.

These changes mirror similar fixes earlier in ISO sockets.

Fixes: 9a8ec9e8 ("Bluetooth: SCO: Fix possible circular locking dependency on sco_connect_cfm")
Signed-off-by: default avatarPauli Virtanen <pav@iki.fi>
Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
parent b4066eb0
...@@ -126,8 +126,11 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon) ...@@ -126,8 +126,11 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon)
struct hci_dev *hdev = hcon->hdev; struct hci_dev *hdev = hcon->hdev;
struct sco_conn *conn = hcon->sco_data; struct sco_conn *conn = hcon->sco_data;
if (conn) if (conn) {
if (!conn->hcon)
conn->hcon = hcon;
return conn; return conn;
}
conn = kzalloc(sizeof(struct sco_conn), GFP_KERNEL); conn = kzalloc(sizeof(struct sco_conn), GFP_KERNEL);
if (!conn) if (!conn)
...@@ -268,21 +271,21 @@ static int sco_connect(struct sock *sk) ...@@ -268,21 +271,21 @@ static int sco_connect(struct sock *sk)
goto unlock; goto unlock;
} }
hci_dev_unlock(hdev);
hci_dev_put(hdev);
conn = sco_conn_add(hcon); conn = sco_conn_add(hcon);
if (!conn) { if (!conn) {
hci_conn_drop(hcon); hci_conn_drop(hcon);
return -ENOMEM; err = -ENOMEM;
goto unlock;
} }
err = sco_chan_add(conn, sk, NULL);
if (err)
return err;
lock_sock(sk); lock_sock(sk);
err = sco_chan_add(conn, sk, NULL);
if (err) {
release_sock(sk);
goto unlock;
}
/* Update source addr of the socket */ /* Update source addr of the socket */
bacpy(&sco_pi(sk)->src, &hcon->src); bacpy(&sco_pi(sk)->src, &hcon->src);
...@@ -296,8 +299,6 @@ static int sco_connect(struct sock *sk) ...@@ -296,8 +299,6 @@ static int sco_connect(struct sock *sk)
release_sock(sk); release_sock(sk);
return err;
unlock: unlock:
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
hci_dev_put(hdev); hci_dev_put(hdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment