mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 06:29:06 -04:00
Bluetooth: ISO: ensure no dangling hcon references in iso_conn
After iso_conn_del(), ISO sockets should not dereference the hcon any more. Currently, clearing iso_conn::hcon relies on iso_conn_del() releasing the last reference to the iso_conn. Simplify this by explicitly clearing conn->hcon in iso_conn_del(), to avoid more complex reasoning on races about who holds the last reference. Signed-off-by: Pauli Virtanen <pav@iki.fi> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
committed by
Luiz Augusto von Dentz
parent
200fa1629c
commit
aa9f7cb2bd
@@ -263,6 +263,7 @@ static void iso_chan_del(struct sock *sk, int err)
|
||||
}
|
||||
|
||||
static void iso_conn_del(struct hci_conn *hcon, int err)
|
||||
__must_hold(&hcon->hdev->lock)
|
||||
{
|
||||
struct iso_conn *conn = hcon->iso_data;
|
||||
struct sock *sk;
|
||||
@@ -277,11 +278,10 @@ static void iso_conn_del(struct hci_conn *hcon, int err)
|
||||
iso_conn_lock(conn);
|
||||
sk = iso_sock_hold(conn);
|
||||
iso_conn_unlock(conn);
|
||||
iso_conn_put(conn);
|
||||
|
||||
if (!sk) {
|
||||
iso_conn_put(conn);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
iso_sock_disable_timer(sk);
|
||||
@@ -291,6 +291,15 @@ static void iso_conn_del(struct hci_conn *hcon, int err)
|
||||
release_sock(sk);
|
||||
iso_sock_kill(sk);
|
||||
sock_put(sk);
|
||||
|
||||
done:
|
||||
/* No sk access to conn->hcon any more (lock_sock + hdev->lock) */
|
||||
iso_conn_lock(conn);
|
||||
conn->hcon = NULL;
|
||||
hcon->iso_data = NULL;
|
||||
iso_conn_unlock(conn);
|
||||
|
||||
iso_conn_put(conn);
|
||||
}
|
||||
|
||||
static int __iso_chan_add(struct iso_conn *conn, struct sock *sk,
|
||||
@@ -306,6 +315,11 @@ static int __iso_chan_add(struct iso_conn *conn, struct sock *sk,
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (!conn->hcon) {
|
||||
BT_ERR("conn->hcon missing");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
iso_pi(sk)->conn = conn;
|
||||
conn->sk = sk;
|
||||
clear_bit(ISO_CONN_DROPPED, conn->flags);
|
||||
@@ -2500,6 +2514,7 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
|
||||
}
|
||||
|
||||
static void iso_connect_cfm(struct hci_conn *hcon, __u8 status)
|
||||
__must_hold(&hcon->hdev->lock)
|
||||
{
|
||||
if (hcon->type != CIS_LINK && hcon->type != BIS_LINK &&
|
||||
hcon->type != PA_LINK) {
|
||||
@@ -2511,8 +2526,10 @@ static void iso_connect_cfm(struct hci_conn *hcon, __u8 status)
|
||||
struct hci_link *link, *t;
|
||||
|
||||
list_for_each_entry_safe(link, t, &hcon->link_list,
|
||||
list)
|
||||
list) {
|
||||
lockdep_assert_held(&link->conn->hdev->lock);
|
||||
iso_conn_del(link->conn, bt_to_errno(status));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -2542,6 +2559,7 @@ static void iso_connect_cfm(struct hci_conn *hcon, __u8 status)
|
||||
}
|
||||
|
||||
static void iso_disconn_cfm(struct hci_conn *hcon, __u8 reason)
|
||||
__must_hold(&hcon->hdev->lock)
|
||||
{
|
||||
if (hcon->type != CIS_LINK && hcon->type != BIS_LINK &&
|
||||
hcon->type != PA_LINK)
|
||||
|
||||
Reference in New Issue
Block a user