From: Pauli Virtanen <pav@iki.fi> stable inclusion from stable-v6.18.44 commit e941799c31f68e67ce0976efb38a79101f921b64 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18470 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- [ Upstream commit aa9f7cb2bd3a2be998ceb739fc9a2f986eba43eb ] 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> Stable-dep-of: fdfde532ab1c ("Bluetooth: ISO: fix refcounting of iso_conn") Signed-off-by: Sasha Levin <sashal@kernel.org> Conflicts: net/bluetooth/iso.c [Context conflicts] Signed-off-by: Yao Yiqi <yaoyiqi3@huawei.com> --- net/bluetooth/iso.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c index 97649e371f28..cbe670247ddd 100644 --- a/net/bluetooth/iso.c +++ b/net/bluetooth/iso.c @@ -270,6 +270,7 @@ static bool iso_match_conn_sync_handle(struct sock *sk, void *data) } 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; @@ -285,11 +286,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); @@ -318,6 +318,14 @@ static void iso_conn_del(struct hci_conn *hcon, int err) 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, @@ -333,6 +341,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); @@ -2061,6 +2074,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) { if (hcon->type != LE_LINK) @@ -2071,8 +2085,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; } @@ -2102,6 +2118,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) return; -- 2.34.1