From 32d86e048d8efedb7aa6cbbd3c36c3c435401c92 Mon Sep 17 00:00:00 2001 From: Pauli Virtanen Date: Sat, 29 Aug 2026 17:20:02 +0300 Subject: [PATCH] Bluetooth: L2CAP: hold conn->lock for __l2cap_ecred_conn_rsp_defer __l2cap_ecred_conn_rsp_defer() > __l2cap_chan_list_id() accesses conn->chan_l which is guarded by conn->lock. The lock fails to be held when calling from l2cap_sock.c. Fix by using l2cap_chan_conn_lock(), and taking the locks in required order l2cap_conn::lock > l2cap_chan::lock > sk. Leave fast path with sk->sk_state precheck. Move the L2CAP defer handling to l2cap_sock_defer(). The code should also take l2cap_chan_lock() for sibling channels, but that needs separate fix due to lock nesting. Fixes: ab4eedb790ca ("Bluetooth: L2CAP: Fix corrupted list in hci_chan_del") Signed-off-by: Pauli Virtanen Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/l2cap_sock.c | 74 ++++++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 23 deletions(-) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 0265b6508682..dee3025f0ec2 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1243,6 +1243,54 @@ static void l2cap_publish_rx_avail(struct l2cap_chan *chan) l2cap_chan_rx_avail(chan, -1); } +static int l2cap_sock_defer(struct sock *sk) +{ + struct l2cap_chan *chan = l2cap_pi(sk)->chan; + bool have_conn; + int err = 0; + + /* Fast path check */ + lock_sock(sk); + if (sk->sk_state != BT_CONNECT2) { + release_sock(sk); + return 0; + } + release_sock(sk); + + have_conn = l2cap_chan_lock_conn(chan); + lock_sock(sk); + + if (sk->sk_state == BT_CONNECT2 && test_bit(BT_SK_DEFER_SETUP, + &bt_sk(sk)->flags)) { + err = 1; + + if (!have_conn) { + release_sock(sk); + err = -ENOTCONN; + } else if (chan->mode == L2CAP_MODE_EXT_FLOWCTL) { + sk->sk_state = BT_CONNECTED; + chan->state = BT_CONNECTED; + release_sock(sk); + __l2cap_ecred_conn_rsp_defer(chan); + } else if (bdaddr_type_is_le(chan->src_type)) { + sk->sk_state = BT_CONNECTED; + chan->state = BT_CONNECTED; + release_sock(sk); + __l2cap_le_connect_rsp_defer(chan); + } else { + sk->sk_state = BT_CONFIG; + chan->state = BT_CONFIG; + release_sock(sk); + __l2cap_connect_rsp_defer(chan); + } + } else { + release_sock(sk); + } + + l2cap_chan_unlock_conn(chan, have_conn); + return err; +} + static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, int flags) { @@ -1254,29 +1302,9 @@ static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg, return sock_recv_errqueue(sk, msg, len, SOL_BLUETOOTH, BT_SCM_ERROR); - lock_sock(sk); - - if (sk->sk_state == BT_CONNECT2 && test_bit(BT_SK_DEFER_SETUP, - &bt_sk(sk)->flags)) { - if (pi->chan->mode == L2CAP_MODE_EXT_FLOWCTL) { - sk->sk_state = BT_CONNECTED; - pi->chan->state = BT_CONNECTED; - __l2cap_ecred_conn_rsp_defer(pi->chan); - } else if (bdaddr_type_is_le(pi->chan->src_type)) { - sk->sk_state = BT_CONNECTED; - pi->chan->state = BT_CONNECTED; - __l2cap_le_connect_rsp_defer(pi->chan); - } else { - sk->sk_state = BT_CONFIG; - pi->chan->state = BT_CONFIG; - __l2cap_connect_rsp_defer(pi->chan); - } - - err = 0; - goto done; - } - - release_sock(sk); + err = l2cap_sock_defer(sk); + if (err) + return err < 0 ? err : 0; if (sock->type == SOCK_STREAM) err = bt_sock_stream_recvmsg(sock, msg, len, flags);