mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 04:34:03 +02:00
Bluetooth: ISO: fix CONNECTED -> CLOSED transition on shutdown/release
Commitd57e506f6a("Bluetooth: ISO: clear iso_data always when detaching conn from hcon") merged a version of the UAF fix that breaks releasing connected ISO sockets. Since hci_conn::iso_data is set to NULL, iso_chan_del() won't be called when the hci_conn disconnects, and the ISO socket does not emit POLLHUP correctly. Fix by retaining full hci_conn <-> iso_conn association while in BT_DISCONNECT state, so that local disconnect via shutdown() follows similar ISO socket code path as remote disconnect. Use a separate flag to track whether hci_conn_drop() is needed, instead of setting iso_conn::hcon = NULL In iso_sock_ready(), disallow disconnecting socket going BT_CONNECTED, in case hcon connects while its drop is pending. Fixes:d57e506f6a("Bluetooth: ISO: clear iso_data always when detaching conn from hcon") Fixes:fbdc4bc472("Bluetooth: ISO: Use defer setup to separate PA sync and BIG sync") 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:
parent
cdc36db204
commit
0786469ee2
|
|
@ -24,8 +24,14 @@ static struct bt_sock_list iso_sk_list = {
|
|||
};
|
||||
|
||||
/* ---- ISO connections ---- */
|
||||
enum {
|
||||
ISO_CONN_DROPPED,
|
||||
__ISO_CONN_NUM_FLAGS
|
||||
};
|
||||
|
||||
struct iso_conn {
|
||||
struct hci_conn *hcon;
|
||||
DECLARE_BITMAP(flags, __ISO_CONN_NUM_FLAGS);
|
||||
|
||||
/* @lock: spinlock protecting changes to iso_conn fields */
|
||||
spinlock_t lock;
|
||||
|
|
@ -107,7 +113,8 @@ static void iso_conn_free(struct kref *ref)
|
|||
|
||||
if (conn->hcon) {
|
||||
conn->hcon->iso_data = NULL;
|
||||
hci_conn_drop(conn->hcon);
|
||||
if (!test_and_set_bit(ISO_CONN_DROPPED, conn->flags))
|
||||
hci_conn_drop(conn->hcon);
|
||||
}
|
||||
|
||||
/* Ensure no more work items will run since hci_conn has been dropped */
|
||||
|
|
@ -306,6 +313,7 @@ static int __iso_chan_add(struct iso_conn *conn, struct sock *sk,
|
|||
|
||||
iso_pi(sk)->conn = conn;
|
||||
conn->sk = sk;
|
||||
clear_bit(ISO_CONN_DROPPED, conn->flags);
|
||||
|
||||
if (parent)
|
||||
bt_accept_enqueue(parent, sk, true);
|
||||
|
|
@ -835,11 +843,8 @@ static void iso_sock_disconn(struct sock *sk)
|
|||
}
|
||||
|
||||
sk->sk_state = BT_DISCONN;
|
||||
iso_conn_lock(iso_pi(sk)->conn);
|
||||
hci_conn_drop(iso_pi(sk)->conn->hcon);
|
||||
iso_pi(sk)->conn->hcon->iso_data = NULL;
|
||||
iso_pi(sk)->conn->hcon = NULL;
|
||||
iso_conn_unlock(iso_pi(sk)->conn);
|
||||
if (!test_and_set_bit(ISO_CONN_DROPPED, iso_pi(sk)->conn->flags))
|
||||
hci_conn_drop(iso_pi(sk)->conn->hcon);
|
||||
}
|
||||
|
||||
static void __iso_sock_close(struct sock *sk)
|
||||
|
|
@ -2042,9 +2047,18 @@ static void iso_sock_ready(struct sock *sk)
|
|||
return;
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
switch (sk->sk_state) {
|
||||
case BT_DISCONN:
|
||||
case BT_CLOSED:
|
||||
release_sock(sk);
|
||||
return;
|
||||
}
|
||||
|
||||
iso_sock_clear_timer(sk);
|
||||
sk->sk_state = BT_CONNECTED;
|
||||
sk->sk_state_change(sk);
|
||||
|
||||
release_sock(sk);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user