From: Pauli Virtanen Date: Fri, 24 Jul 2026 20:20:32 +0000 (+0300) Subject: Bluetooth: ISO: ensure no dangling hcon references in iso_conn X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=aa9f7cb2bd3a2be998ceb739fc9a2f986eba43eb;p=thirdparty%2Flinux.git 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 Signed-off-by: Luiz Augusto von Dentz --- diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c index 0cc08416fde5..bfd39baa8503 100644 --- a/net/bluetooth/iso.c +++ b/net/bluetooth/iso.c @@ -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 @@ done: } 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)