From nobody Sat Sep 26 11:46:37 2026 Received: from meesny.iki.fi (meesny.iki.fi [195.140.195.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B27F93ABD80; Tue, 1 Sep 2026 21:04:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=195.140.195.201 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788296699; cv=pass; b=i49Vo/9CAcZtbYGvql7ZSl1HcXkB8lbXTSZifqiOOPc2tcKgPueZFlZMNEWQ/s2epOH8lV3WSik/V5SIq3CGbh9nM7QcPxMcWxo2GfR+d5EGYnsN2YRkQI+XWrPH7iKeerewhu3K/fsWDXBswiVUxvPvNUcnOlZ1a813FujNJt8= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788296699; c=relaxed/simple; bh=3s9ZPhc55/duEREoxPchCpuMYgIEAWBsjxd0ONqCIlw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=dQqHqxOTsm+0JurdnQqr/jtZVSYhUGFMUfrqQastbV53nyTAS7oGn3G+F+K/4zQqb6NEDKsLAsp5N8dmImoHJel9LIpfiwWIqmCnLL2ZBoKfBab2FgNiyV4O/6Z0SNNs7nDBlinWReTt2u+giLmmRUohtUao2Y8h9x3DYvzQpZc= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi; spf=pass smtp.mailfrom=iki.fi; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b=azUd0b7f; arc=pass smtp.client-ip=195.140.195.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iki.fi Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b="azUd0b7f" Received: from monolith.lan (unknown [IPv6:2a03:1b20:4:f011::dd01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: pav) by meesny.iki.fi (Postfix) with ESMTPSA id 4hZJJs75WvzyfV; Wed, 02 Sep 2026 00:04:45 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788296686; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=VKCj5gbsSO9eIn0e0ZDUMGMEaXRZhNCzZmvhhpmDLHU=; b=azUd0b7fJNupUPolcxrpWnK9GGH2Q8leOYPrTjATnFjshnnd4uLn8fpyMuIXjn9H3km1sC mGV18IJ+xTQz7dcpYLRmDFSx34UNXn2+ow+UkA9u/+KHhJl9wr/iBLHRTzFXIlSUqzOD+y lqIcxzLLP7faXhyH28ExFT2rZQVKb28= ARC-Seal: i=1; a=rsa-sha256; d=iki.fi; s=meesny; cv=none; t=1788296686; b=I6Kis1eVuRn+/wPscm+Ohsa28fW19MBQPLyygfK1MHyI/qzWfKdvMca9UYo3u1CRaem3Yy yvNOWMfapV9vsaukXLVYt+ibfoIia8crklM3Hiy9NseIkCFjKXF799q7ABhV3HBEK0JTzp Hc/9MTocGKm9+qjhJ5vXYAiWOmnE8GE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788296686; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=VKCj5gbsSO9eIn0e0ZDUMGMEaXRZhNCzZmvhhpmDLHU=; b=mppzkUBCkSEUcT7Nrklsn+WGkMemwqGPDlZc8zky4KgFI7DIzslZq/qHd55ZMWAeCvs1ll CYsu0XAUBvwQ8rPX+2a5ztGMwGiVhq7a0rSHiO0RSEA8BZ3D0n+LILIAVlT+0fK9y2rfzz fH2lHGy5OmRrFlXagVot2oV4hY019RM= ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pav smtp.mailfrom=pav@iki.fi From: Pauli Virtanen To: linux-bluetooth@vger.kernel.org Cc: Pauli Virtanen , marcel@holtmann.org, luiz.dentz@gmail.com, elver@google.com, linux-kernel@vger.kernel.org Subject: [PATCH 1/4] Bluetooth: L2CAP: take lock for l2cap_chan_del in l2cap_ecred_rsp_defer Date: Wed, 2 Sep 2026 00:04:33 +0300 Message-ID: <24ff07854c80a2813fe7050d1dbb40586391b162.1788296635.git.pav@iki.fi> X-Mailer: git-send-email 2.55.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" l2cap_ecred_rsp_defer() calls l2cap_chan_del without holding chan->lock, which ends up calling ops->teardown() with wrong lock context. Fix by taking chan->lock in l2cap_ecred_rsp_defer(). AB-BA deadlocks between sibling l2cap_chan are avoided here via requiring l2cap_conn::lock to serialize all nested l2cap_chan locking on same nesting level. In current code, there is no nested l2cap_chan locking on same nesting level, so we can add this new requirement. Also return early from __l2cap_ecred_conn_rsp_defer() if chan did not have FLAG_DEFER_SETUP, as then no RSP shall be sent for it, to make sure SMP channels are excluded. Also hold chan reference over l2cap_chan_del(), in case chan_l reference was the last. Signed-off-by: Pauli Virtanen --- include/net/bluetooth/l2cap.h | 4 +++ net/bluetooth/l2cap_core.c | 60 +++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 2315a3993c7b..c7e642abe404 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -758,6 +758,10 @@ enum { * otherwise considers all channels equal and will e.g. complain about a * connection oriented channel triggering SMP procedures or a listening * channel creating and locking a child channel. + * + * Lock nesting of channels at the same nesting level is allowed if the ch= annels + * have the same l2cap_chan::conn and l2cap_chan::conn.lock is taken befor= e the + * nested locks. l2cap_chan_try_sibling_lock() must be used. */ enum { L2CAP_NESTING_SMP, diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 9da689f0a50a..805623a48bae 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -848,6 +848,8 @@ static void __l2cap_chan_close(struct l2cap_chan *chan,= int reason) =20 BT_DBG("chan %p state %s", chan, state_to_string(chan->state)); =20 + lockdep_assert_held(&chan->lock); + switch (chan->state) { case BT_LISTEN: chan->ops->teardown(chan, 0); @@ -3950,6 +3952,7 @@ static void l2cap_ecred_list_defer(struct l2cap_chan = *chan, void *data) } =20 struct l2cap_ecred_rsp_data { + struct l2cap_chan *locked_chan; struct { struct l2cap_ecred_conn_rsp_hdr rsp; __le16 scid[L2CAP_ECRED_MAX_CID]; @@ -3957,11 +3960,42 @@ struct l2cap_ecred_rsp_data { int count; }; =20 +/* Lock @chan if it is not @locked_chan, and has same or lower nesting lev= el. + * + * They must have the same chan->conn, and conn->lock must be held. + * + * Caller must ensure @chan has lock nesting level <=3D that of @locked_ch= an, as + * nested locking of l2cap_chan of different levels is allowed also without + * holding conn->lock. + * + * See l2cap.h for the global l2cap_chan locking rules. + */ +static bool l2cap_chan_try_sibling_lock(struct l2cap_chan *chan, + struct l2cap_chan *locked_chan) + __must_hold(&locked_chan->lock) + __must_hold(&locked_chan->conn->lock) + __cond_acquires(true, &chan->lock) +{ + if (chan =3D=3D locked_chan) + return false; + + if (WARN_ON_ONCE(locked_chan->conn !=3D chan->conn)) + return false; + + if (WARN_ON_ONCE(atomic_read(&locked_chan->nesting) + < atomic_read(&chan->nesting))) + return false; + + mutex_lock_nest_lock(&chan->lock, &locked_chan->conn->lock); + return true; +} + static void l2cap_ecred_rsp_defer(struct l2cap_chan *chan, void *data) { struct l2cap_ecred_rsp_data *rsp =3D data; struct l2cap_ecred_conn_rsp *rsp_flex =3D container_of(&rsp->pdu.rsp, struct l2cap_ecred_conn_rsp, hdr); + bool locked; =20 if (chan->mode !=3D L2CAP_MODE_EXT_FLOWCTL) return; @@ -3973,6 +4007,22 @@ static void l2cap_ecred_rsp_defer(struct l2cap_chan = *chan, void *data) !test_and_clear_bit(FLAG_DEFER_SETUP, &chan->flags)) return; =20 + lockdep_assert_held(&rsp->locked_chan->lock); + lockdep_assert_held(&rsp->locked_chan->conn->lock); + + l2cap_chan_hold(chan); + + locked =3D l2cap_chan_try_sibling_lock(chan, rsp->locked_chan); + + /* Cannot occur: PARENT channels do not appear in chan_l, and SMP + * channels never have FLAG_DEFER_SETUP. + */ + if (context_unsafe(!locked && chan !=3D rsp->locked_chan)) + goto done; + + lockdep_assert_held(&chan->lock); + lockdep_assert_held(&chan->conn->lock); + /* Reset ident so only one response is sent */ chan->ident =3D 0; =20 @@ -3985,6 +4035,12 @@ static void l2cap_ecred_rsp_defer(struct l2cap_chan = *chan, void *data) rsp_flex->dcid[rsp->count++] =3D cpu_to_le16(chan->scid); else l2cap_chan_del(chan, ECONNRESET); + +done: + if (locked) + l2cap_chan_unlock(chan); + + l2cap_chan_put(chan); } =20 void __l2cap_ecred_conn_rsp_defer(struct l2cap_chan *chan) @@ -3996,11 +4052,15 @@ void __l2cap_ecred_conn_rsp_defer(struct l2cap_chan= *chan) =20 if (!id) return; + if (!test_bit(FLAG_DEFER_SETUP, &chan->flags)) + return; =20 BT_DBG("chan %p id %d", chan, id); =20 memset(&data, 0, sizeof(data)); =20 + data.locked_chan =3D chan; + data.pdu.rsp.mtu =3D cpu_to_le16(chan->imtu); data.pdu.rsp.mps =3D cpu_to_le16(chan->mps); data.pdu.rsp.credits =3D cpu_to_le16(chan->rx_credits); --=20 2.55.0 From nobody Sat Sep 26 11:46:37 2026 Received: from meesny.iki.fi (meesny.iki.fi [195.140.195.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 74E7C391E52; Tue, 1 Sep 2026 21:04:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=195.140.195.201 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788296698; cv=pass; b=F8zffNPVm/hg/ZvK5/+r69JEjO2U2BCtZHWO3NUCk6A41FnowtR8KBUrZmFsFQZENm7zMLAyg8N3RyUIC3QyPsxhWtIGQhkeVKfcJVQ6HRfrXilEw1tcX325DwQpXPi2/4gm1us8wiG/F71NK0+uAXgZ9d+0OdbqMeSMW7fspQc= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788296698; c=relaxed/simple; bh=5zibq57D/j/jK/mPVGQ1sOwhhWnQ3QcU0GgC7ICYfeg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=mSBXgGfsA5lqBO8bkeSWbvGmgV3fX8az2ORqqGyy7b8JjV3qUTvCG7RpOMH92jTxsv86Bfqc6WCqIMfU2In6SpgUW1DrV/UrF8l0rTo4BLQd0mbbrivZLeZvCFyUZc7rTxJhImFaPcPROW9eSOxpE/CmLboOME63PTT80AcGoHM= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi; spf=pass smtp.mailfrom=iki.fi; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b=DVmD5dnX; arc=pass smtp.client-ip=195.140.195.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iki.fi Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b="DVmD5dnX" Received: from monolith.lan (unknown [IPv6:2a03:1b20:4:f011::dd01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: pav) by meesny.iki.fi (Postfix) with ESMTPSA id 4hZJJy2k5LzywJ; Wed, 02 Sep 2026 00:04:50 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788296690; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=sPvEKoTtP7yiNM3rOQJTmK+baCfbSTa8KD7bYAKS+Ig=; b=DVmD5dnXajWshfGatGIZMvjG7duMOeKhGxUZ7rRaJE2Kh9ElMcJOjr93X6QGTBRLmhDUG8 aoU6RMQVLDpeay3uweBgjIhnSzTPGOqt/iqmFTXkHUzdpdY4Z34RgW3Q+C+uvU0tcbL9Nb 2W9PqbrOjeCAFSmoU2a7jv7xJSATv2E= ARC-Seal: i=1; a=rsa-sha256; d=iki.fi; s=meesny; cv=none; t=1788296690; b=LRrtCzbAZVD5KINExUZpl0hJ1Kk4G+kKpiFx93FFwxz3ryDTYPCIQW3Dnq1Xap8MSahBP7 hA7LYlZVD/avOypcDw4WITyddh6RQaVdux68Sp8kU/HdE/OQy5bHrsVLxaHgkBmlTH/bs6 1MmZjDNlELrC/6/VG7yVPO926614PXM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788296690; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=sPvEKoTtP7yiNM3rOQJTmK+baCfbSTa8KD7bYAKS+Ig=; b=kwSA+JU8ABWJrcV29dHFBU6yfydfFgnqMOijuTYZsNhn841uWoc0Ghhq46jSkIiMYMKqDw YwCW3apYfaRonTqMiIBolXmiM5lueyqo9pdN/tOxnVKo4IqiAvGcNAZ/5clrsi8GvxhiVJ 5jovkRzIcBJVZ61hO3QMi/pT/9qP88U= ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pav smtp.mailfrom=pav@iki.fi From: Pauli Virtanen To: linux-bluetooth@vger.kernel.org Cc: Pauli Virtanen , marcel@holtmann.org, luiz.dentz@gmail.com, elver@google.com, linux-kernel@vger.kernel.org Subject: [PATCH 2/4] Bluetooth: L2CAP: annotate locking for l2cap_chan_del() Date: Wed, 2 Sep 2026 00:04:34 +0300 Message-ID: <16a30a04f28b2b93023b6e32b361543384af499b.1788296635.git.pav@iki.fi> X-Mailer: git-send-email 2.55.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add context analysis annotations for chan->lock and chan->conn->lock involving l2cap_chan_del() usage. Add necessary annotations and related lockdep_assert_held to callers. Move struct l2cap_ops definition after struct l2cap_conn, so that the callbacks can be annotated. In l2cap_chan_close_unlocked() we consider chan->conn->lock as locked even if chan->conn =3D=3D NULL, to avoid needing to define separate __l2cap_chan_close/del for this NULL case. Signed-off-by: Pauli Virtanen --- include/net/bluetooth/l2cap.h | 56 +++++++++++++++++++---------------- net/bluetooth/6lowpan.c | 2 ++ net/bluetooth/l2cap_core.c | 49 +++++++++++++++++++++++++----- 3 files changed, 74 insertions(+), 33 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index c7e642abe404..3e1e2b36d7b6 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -614,31 +614,6 @@ struct l2cap_chan { struct mutex lock; }; =20 -struct l2cap_ops { - char *name; - - int (*new_connection)(struct l2cap_chan *chan, - struct l2cap_chan *new_chan); - int (*recv) (struct l2cap_chan * chan, - struct sk_buff *skb); - void (*teardown) (struct l2cap_chan *chan, int err); - void (*close) (struct l2cap_chan *chan); - void (*state_change) (struct l2cap_chan *chan, - int state, int err); - void (*ready) (struct l2cap_chan *chan); - void (*defer) (struct l2cap_chan *chan); - void (*resume) (struct l2cap_chan *chan); - void (*suspend) (struct l2cap_chan *chan); - void (*set_shutdown) (struct l2cap_chan *chan); - long (*get_sndtimeo) (struct l2cap_chan *chan); - struct pid *(*get_peer_pid) (struct l2cap_chan *chan); - struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan, - unsigned long hdr_len, - unsigned long len, int nb); - int (*filter) (struct l2cap_chan * chan, - struct sk_buff *skb); -}; - struct l2cap_conn { struct hci_conn *hcon; struct hci_chan *hchan; @@ -674,6 +649,34 @@ struct l2cap_conn { struct list_head users; }; =20 +struct l2cap_ops { + char *name; + + int (*new_connection)(struct l2cap_chan *chan, + struct l2cap_chan *new_chan); + int (*recv) (struct l2cap_chan * chan, + struct sk_buff *skb); + void (*teardown) (struct l2cap_chan *chan, int err) + __must_hold(&chan->lock); + void (*close) (struct l2cap_chan *chan); + void (*state_change) (struct l2cap_chan *chan, + int state, int err); + void (*ready) (struct l2cap_chan *chan) + __must_hold(&chan->lock) + __must_hold(&chan->conn->lock); + void (*defer) (struct l2cap_chan *chan); + void (*resume) (struct l2cap_chan *chan); + void (*suspend) (struct l2cap_chan *chan); + void (*set_shutdown) (struct l2cap_chan *chan); + long (*get_sndtimeo) (struct l2cap_chan *chan); + struct pid *(*get_peer_pid) (struct l2cap_chan *chan); + struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan, + unsigned long hdr_len, + unsigned long len, int nb); + int (*filter) (struct l2cap_chan * chan, + struct sk_buff *skb); +}; + struct l2cap_user { struct list_head list; int (*probe) (struct l2cap_conn *conn, struct l2cap_user *user); @@ -983,7 +986,8 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l= 2cap_chan *chan) typedef void (*l2cap_chan_func_t)(struct l2cap_chan *chan, void *data); void l2cap_chan_list(struct l2cap_conn *conn, l2cap_chan_func_t func, void *data); -void l2cap_chan_del(struct l2cap_chan *chan, int err); +void l2cap_chan_del(struct l2cap_chan *chan, int err) + __must_hold(&chan->lock) __must_hold(&chan->conn->lock); void l2cap_send_conn_req(struct l2cap_chan *chan); =20 struct l2cap_conn *l2cap_conn_get(struct l2cap_conn *conn); diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index ddcdd2aff91f..836add41f5d1 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -722,6 +722,8 @@ static int setup_netdev(struct l2cap_chan *chan, struct= lowpan_btle_dev **dev) } =20 static inline void chan_ready_cb(struct l2cap_chan *chan) + __must_hold(&chan->lock) + __must_hold(&chan->conn->lock) { struct lowpan_btle_dev *dev; bool new_netdev =3D false; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 805623a48bae..219d92431be0 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -59,7 +59,8 @@ static void l2cap_tx(struct l2cap_chan *chan, struct l2ca= p_ctrl *control, static void l2cap_retrans_timeout(struct work_struct *work); static void l2cap_monitor_timeout(struct work_struct *work); static void l2cap_ack_timeout(struct work_struct *work); -static void __l2cap_chan_close(struct l2cap_chan *chan, int reason); +static void __l2cap_chan_close(struct l2cap_chan *chan, int reason) + __must_hold(&chan->lock) __must_hold(&chan->conn->lock); =20 static inline u8 bdaddr_type(u8 link_type, u8 bdaddr_type) { @@ -681,6 +682,8 @@ void l2cap_chan_add(struct l2cap_conn *conn, struct l2c= ap_chan *chan) =20 void l2cap_chan_del(struct l2cap_chan *chan, int err) { + lockdep_assert(!chan->conn || lockdep_is_held(&chan->conn->lock)); + __clear_chan_timer(chan); =20 BT_DBG("chan %p, err %d, state %s", chan, err, @@ -812,12 +815,11 @@ static void l2cap_chan_le_connect_reject(struct l2cap= _chan *chan) } =20 static void l2cap_chan_ecred_connect_reject(struct l2cap_chan *chan) + __must_hold(&chan->lock) + __must_hold(&chan->conn->lock) { l2cap_state_change(chan, BT_DISCONN); =20 - lockdep_assert_held(&chan->lock); - lockdep_assert_held(&chan->conn->lock); - __l2cap_ecred_conn_rsp_defer(chan); } =20 @@ -848,8 +850,6 @@ static void __l2cap_chan_close(struct l2cap_chan *chan,= int reason) =20 BT_DBG("chan %p state %s", chan, state_to_string(chan->state)); =20 - lockdep_assert_held(&chan->lock); - switch (chan->state) { case BT_LISTEN: chan->ops->teardown(chan, 0); @@ -934,7 +934,10 @@ void l2cap_chan_close_unlocked(struct l2cap_chan *chan= , int reason) bool have_conn; =20 have_conn =3D l2cap_chan_lock_conn(chan); - __l2cap_chan_close(chan, reason); + + /* Context analysis: consider chan->conn->lock held also if conn NULL */ + context_unsafe(__l2cap_chan_close(chan, reason)); + l2cap_chan_unlock_conn(chan, have_conn); } EXPORT_SYMBOL(l2cap_chan_close_unlocked); @@ -1336,6 +1339,8 @@ void l2cap_send_conn_req(struct l2cap_chan *chan) } =20 static void l2cap_chan_ready(struct l2cap_chan *chan) + __must_hold(&chan->lock) + __must_hold(&chan->conn->lock) { /* The channel may have already been flagged as connected in * case of receiving data before the L2CAP info req/rsp @@ -1471,6 +1476,7 @@ static void l2cap_ecred_connect(struct l2cap_chan *ch= an) } =20 static void l2cap_le_start(struct l2cap_chan *chan) + __must_hold(&chan->lock) __must_hold(&chan->conn->lock) { struct l2cap_conn *conn =3D chan->conn; @@ -1492,6 +1498,7 @@ static void l2cap_le_start(struct l2cap_chan *chan) } =20 static void l2cap_start_connection(struct l2cap_chan *chan) + __must_hold(&chan->lock) __must_hold(&chan->conn->lock) { if (chan->conn->hcon->type =3D=3D LE_LINK) { @@ -1542,6 +1549,7 @@ static bool l2cap_check_enc_key_size(struct hci_conn = *hcon, } =20 static void l2cap_do_start(struct l2cap_chan *chan) + __must_hold(&chan->lock) __must_hold(&chan->conn->lock) { struct l2cap_conn *conn =3D chan->conn; @@ -1893,6 +1901,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int= err) l2cap_chan_hold(chan); l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + l2cap_chan_del(chan, err); =20 chan->ops->close(chan); @@ -4218,6 +4228,8 @@ static struct l2cap_chan *l2cap_new_connection(struct= l2cap_conn *conn, =20 __l2cap_chan_add(conn, chan); =20 + lockdep_assert_held(&chan->conn->lock); + if (pchan->ops->new_connection && pchan->ops->new_connection(pchan, chan) < 0) { l2cap_chan_del(chan, 0); @@ -4419,6 +4431,8 @@ static int l2cap_connect_create_rsp(struct l2cap_conn= *conn, =20 l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + switch (result) { case L2CAP_CR_SUCCESS: if (__l2cap_get_chan_by_dcid(conn, dcid)) { @@ -4520,6 +4534,8 @@ static inline int l2cap_config_req(struct l2cap_conn = *conn, =20 l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + if (chan->state !=3D BT_CONFIG && chan->state !=3D BT_CONNECT2 && chan->state !=3D BT_CONNECTED) { cmd_reject_invalid_cid(conn, cmd->ident, chan->scid, @@ -4634,6 +4650,8 @@ static inline int l2cap_config_rsp(struct l2cap_conn = *conn, =20 l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + switch (result) { case L2CAP_CONF_SUCCESS: l2cap_conf_rfc_get(chan, rsp->data, len); @@ -4743,6 +4761,8 @@ static inline int l2cap_disconnect_req(struct l2cap_c= onn *conn, =20 l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + rsp.dcid =3D cpu_to_le16(chan->scid); rsp.scid =3D cpu_to_le16(chan->dcid); l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp); @@ -4783,6 +4803,8 @@ static inline int l2cap_disconnect_rsp(struct l2cap_c= onn *conn, =20 l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + if (chan->state !=3D BT_DISCONN) { l2cap_chan_unlock(chan); l2cap_chan_put(chan); @@ -4995,6 +5017,8 @@ static int l2cap_le_connect_rsp(struct l2cap_conn *co= nn, =20 l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + switch (result) { case L2CAP_CR_LE_SUCCESS: if (__l2cap_get_chan_by_dcid(conn, dcid)) { @@ -5213,6 +5237,8 @@ static int l2cap_le_connect_req(struct l2cap_conn *co= nn, =20 l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + bacpy(&chan->src, &conn->hcon->src); bacpy(&chan->dst, &conn->hcon->dst); chan->src_type =3D bdaddr_src_type(conn->hcon); @@ -5444,6 +5470,8 @@ static inline int l2cap_ecred_conn_req(struct l2cap_c= onn *conn, =20 l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + bacpy(&chan->src, &conn->hcon->src); bacpy(&chan->dst, &conn->hcon->dst); chan->src_type =3D bdaddr_src_type(conn->hcon); @@ -5533,6 +5561,8 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_c= onn *conn, l2cap_chan_hold(chan); l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + /* Check that there is a dcid for each pending channel */ if (cmd_len < sizeof(dcid)) { l2cap_chan_del(chan, ECONNREFUSED); @@ -5760,6 +5790,8 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap= _conn *conn, continue; l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + l2cap_chan_del(chan, ECONNRESET); =20 l2cap_chan_unlock(chan); @@ -5789,6 +5821,7 @@ static inline int l2cap_le_command_rej(struct l2cap_c= onn *conn, goto done; =20 l2cap_chan_lock(chan); + lockdep_assert_held(&chan->conn->lock); l2cap_chan_del(chan, ECONNREFUSED); l2cap_chan_unlock(chan); l2cap_chan_put(chan); @@ -7176,6 +7209,8 @@ static void l2cap_data_channel(struct l2cap_conn *con= n, u16 cid, =20 l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + BT_DBG("chan %p, len %d", chan, skb->len); =20 /* If we receive data on a fixed channel before the info req/rsp --=20 2.55.0 From nobody Sat Sep 26 11:46:37 2026 Received: from meesny.iki.fi (meesny.iki.fi [195.140.195.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BE0CA387347; Tue, 1 Sep 2026 21:05:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=195.140.195.201 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788296702; cv=pass; b=DSoscg3HWulBha+vRSZFlaag5G2hAUt+G6rBXJut8SNMzftXc9vL0KNN/2+H7kg+OK0HSR7AlZdlcnoo+UjLbOYUQgxjsavIOPVV0YSBuy7dTdVGv5bKrd7WZhvPFvnBhky6df0TSXv2H63o7QT1/s2cOzWz3O2aZ1BAb9Qtc2M= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788296702; c=relaxed/simple; bh=Z4wrzi/jCko2jVUjv/y05CcT0TV0/eHdeWoQdL3wWpA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TzcFEoby9hwcLznTBA1SIEYVfpF5+TBKW4g68fZ7avN38mhOh42s5KIoq2HV3tWl4pWT+R456e0hCXINRbB4lb0BEqDeWqHHwVVwBbQE+3suLDwI666offLtiRk1jhRqd95LRR31LblvPDZykxb+Jwi/csJgzVeUqMsnRstTqm0= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi; spf=pass smtp.mailfrom=iki.fi; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b=BqIr+eoZ; arc=pass smtp.client-ip=195.140.195.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iki.fi Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b="BqIr+eoZ" Received: from monolith.lan (unknown [IPv6:2a03:1b20:4:f011::dd01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: pav) by meesny.iki.fi (Postfix) with ESMTPSA id 4hZJK25X5GzyYW; Wed, 02 Sep 2026 00:04:54 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788296694; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=rQstipzFC8XSCMgp+rCFNiXIjI+TWPVN6KaF5ptHhNU=; b=BqIr+eoZ7ktqaZURh5h/44aKGe0rNTpEDfSJUDRTX38SZwvQhsTMpE0kPEQ1zSFlITEIkr +dd5pwTP30CuqAsEAxxC4DF8OXCCH98b45xpNTHm4P7Y0CAWKeonz4gh3mjxhevk65KgBJ Bh1oYm0HD4dwKqlCUFvu9EEhrjzK588= ARC-Seal: i=1; a=rsa-sha256; d=iki.fi; s=meesny; cv=none; t=1788296694; b=s+VnxlymNDdaHmF2mTrg3ycK3dQVp1FEjLzXB3QCSAuYgP26YPfhdyxyX2el6X1WwllZ+N +fyC/g01pqxFEdIp5ddTPb+REGAuTTacMzmu3sXYshBaTh9gndqcUdSI4p59jK5W/zSMyC vUiZ1Roqj2LAeOccPsaFkPHJXIq0WxE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788296694; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=rQstipzFC8XSCMgp+rCFNiXIjI+TWPVN6KaF5ptHhNU=; b=wsqijSY5z28rOZE2t0pbhJYB/c4+rPHv2Spcu/hvQk8tbLbWbDP+o4cPjIF7vMTJZFdmVZ hYL7bK9hNqtvbH7/r1qPFHOYARonfwLLB70/uNZj300IoU7y9snMv+SDAJW8KLIhhe6lZx QKprSSd2KhCnDULmxnsX4hNMxO8cM3I= ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pav smtp.mailfrom=pav@iki.fi From: Pauli Virtanen To: linux-bluetooth@vger.kernel.org Cc: Pauli Virtanen , marcel@holtmann.org, luiz.dentz@gmail.com, elver@google.com, linux-kernel@vger.kernel.org Subject: [PATCH 3/4] Bluetooth: L2CAP: annotate locking for l2cap_ops callbacks Date: Wed, 2 Sep 2026 00:04:35 +0300 Message-ID: <14d8b302f8673675ab69ed236674c647969d7589.1788296635.git.pav@iki.fi> X-Mailer: git-send-email 2.55.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Annotate current locking context for l2cap_ops callbacks. Signed-off-by: Pauli Virtanen --- include/net/bluetooth/l2cap.h | 13 +++++++++---- net/bluetooth/l2cap_core.c | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 3e1e2b36d7b6..efb9b7f422d1 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -653,21 +653,26 @@ struct l2cap_ops { char *name; =20 int (*new_connection)(struct l2cap_chan *chan, - struct l2cap_chan *new_chan); + struct l2cap_chan *new_chan) + __must_hold(&chan->lock) + __must_hold(&new_chan->lock); int (*recv) (struct l2cap_chan * chan, struct sk_buff *skb); void (*teardown) (struct l2cap_chan *chan, int err) __must_hold(&chan->lock); - void (*close) (struct l2cap_chan *chan); + void (*close) (struct l2cap_chan *chan) + __must_hold(&chan->lock); void (*state_change) (struct l2cap_chan *chan, int state, int err); void (*ready) (struct l2cap_chan *chan) __must_hold(&chan->lock) __must_hold(&chan->conn->lock); void (*defer) (struct l2cap_chan *chan); - void (*resume) (struct l2cap_chan *chan); + void (*resume) (struct l2cap_chan *chan) + __must_hold(&chan->lock); void (*suspend) (struct l2cap_chan *chan); - void (*set_shutdown) (struct l2cap_chan *chan); + void (*set_shutdown) (struct l2cap_chan *chan) + __must_hold(&chan->lock); long (*get_sndtimeo) (struct l2cap_chan *chan); struct pid *(*get_peer_pid) (struct l2cap_chan *chan); struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan, diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 219d92431be0..b7d5fa6f6a83 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -4214,6 +4214,7 @@ static inline int l2cap_command_rej(struct l2cap_conn= *conn, static struct l2cap_chan *l2cap_new_connection(struct l2cap_conn *conn, struct l2cap_chan *pchan) __must_hold(&conn->lock) + __must_hold(&pchan->lock) { struct l2cap_chan *chan; =20 --=20 2.55.0 From nobody Sat Sep 26 11:46:37 2026 Received: from meesny.iki.fi (meesny.iki.fi [195.140.195.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4B1B8406261; Tue, 1 Sep 2026 21:05:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=195.140.195.201 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788296707; cv=pass; b=gF0peF1ajAOO/Bi7gbuBXq5uZaFVUFUIwMVU8dn3pMsNAO8eM6YqJMQYPdpHGd56iMYzCojJciWCg46WXlIJ/r86/ZJlRFAZ+kEptZUO6aqDRkpKMFOFIBGP7jMs0rS51B2ouEKrRQLLMRE0M9sZhZoyp3hmXa3DXkoACTs70gg= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788296707; c=relaxed/simple; bh=nUb+Kw11eg4gqQYRw1zJn6IfcxOia+Zh7pODmMOOg4Y=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=F45c1wBKE0cblz01eUHmMmw1W3h7VzsbvvvRWss3m04Vj/f/qGTxu71LmWNWLluTL6FY3/oAvjDdfBsyzj/OTXLt19QRH/XlTnK39KOaFUnD4emsUrXgkSTLhbkUmvjVOORuXVLSSHCJ3C1onYSwhvmDAbLrwVwKE5QHMM4Z3Ec= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi; spf=pass smtp.mailfrom=iki.fi; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b=k5Xv1eZK; arc=pass smtp.client-ip=195.140.195.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iki.fi Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b="k5Xv1eZK" Received: from monolith.lan (unknown [IPv6:2a03:1b20:4:f011::dd01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: pav) by meesny.iki.fi (Postfix) with ESMTPSA id 4hZJK710FczyQn; Wed, 02 Sep 2026 00:04:59 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788296699; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=pItbY5onH1Vlt47pfP8WyBfdNBB9um1JXokdD+/CiFY=; b=k5Xv1eZKyjb6hTAeZjQ33rL0E2g+rkzB7lSs5MYy47XdLfRcuF2msU5DnZtKgpsrrpsId6 2zDO+V/67ASA4YivwaLgV7FJGG9HcGjvpm7kW79iioIy5znXNF4c00whHZi6VNJ1Vx8Wda xjSoTzCFJUNYSD23jsnHHAZ/cbBrhFc= ARC-Seal: i=1; a=rsa-sha256; d=iki.fi; s=meesny; cv=none; t=1788296699; b=o/u7SoNQ0j/Jrn7OwepVGQO4fN0cAs88S40qE/kz3Kh9pLtSGvOWp3D4hgFA5BPBhEKqjn UFAb0/U+UuZEg1c08wbWGSOkJT4d8jgbmbYU3z3czZc8foTWLHPIbAx/dUmJVtKIJHxL1e 8SBtdn8Fv/vaEu2ewmRHzxXc0ku7DRw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788296699; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=pItbY5onH1Vlt47pfP8WyBfdNBB9um1JXokdD+/CiFY=; b=SKznPzmiogRJS3eC06LjMY6e0b9efvqsSuoNViEdhJKcw8mXbu4q3zxPHsQRtOhdFp4y48 7NyZkMDMH8DZOgpTOG0R2ZLCSCDQQ+j93sDy2k3TLTrlEWHs57WjAHbstyVh5l9aXcJysZ ry7opfCSEOCCb27ioHXwFrZPpTOLE3E= ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pav smtp.mailfrom=pav@iki.fi From: Pauli Virtanen To: linux-bluetooth@vger.kernel.org Cc: Pauli Virtanen , marcel@holtmann.org, luiz.dentz@gmail.com, elver@google.com, linux-kernel@vger.kernel.org Subject: [PATCH 4/4] Bluetooth: L2CAP: refuse __l2cap_chan_add if chan already has conn Date: Wed, 2 Sep 2026 00:04:36 +0300 Message-ID: <1e0a04c3e50261e7fa59686ab861819951e90809.1788296635.git.pav@iki.fi> X-Mailer: git-send-email 2.55.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" l2cap_chan may be linked to l2cap_conn at most once. This is assumed in several places, eg l2cap_chan_del cleanup. There is a TOCTOU race where the invariant is violated: [Task 1] [Task 2] l2cap_chan_connect l2cap_sock_bind l2cap_chan_lock lock_sock l2cap_state_change if (sk->sk_state !=3D BT_OPEN) chan->state =3D BT_CONNECT l2cap_sock_state_change_cb chan->state =3D BT_BOUND sk->sk_state =3D BT_BOUND lock_sock <------------------ release_sock sk->sk_state =3D BT_CONNECT l2cap_sock_connect() does not check sk->sk_state, so since chan->state is now BT_BOUND, subsequent connect() ends up with second __l2cap_chan_add. Explicitly document and check the invariant in __l2cap_chan_add with WARN_ON_ONCE. The only callsite where it could be hit is l2cap_chan_connect, so add pre-check there to avoid relying on chan->state. chan->state read/write is not properly guarded currently so there can be other TOCTOUC problems. Add l2cap_lock_chan in l2cap_sock_bind() to guard chan->state write. Fixes: b66774b48dd9 ("Bluetooth: L2CAP: Fix UAF in channel timeout by holdi= ng conn ref") Assisted-by: deepseek-4-flash # finding the race condition Signed-off-by: Pauli Virtanen --- net/bluetooth/l2cap_core.c | 7 ++++++- net/bluetooth/l2cap_sock.c | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index b7d5fa6f6a83..a22edd2baf5e 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -623,6 +623,10 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct = l2cap_chan *chan) BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, __le16_to_cpu(chan->psm), chan->dcid); =20 + /* Caller must ensure l2cap_chan is linked to l2cap_conn only once */ + if (WARN_ON_ONCE(chan->conn || test_bit(FLAG_DEL, &chan->flags))) + return; + conn->disc_reason =3D HCI_ERROR_REMOTE_USER_TERM; =20 chan->conn =3D l2cap_conn_get(conn); @@ -7623,7 +7627,8 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le1= 6 psm, u16 cid, } } =20 - if (cid && __l2cap_get_chan_by_dcid(conn, cid)) { + if ((cid && __l2cap_get_chan_by_dcid(conn, cid)) || chan->conn || + test_bit(FLAG_DEL, &chan->flags)) { hci_conn_drop(hcon); err =3D -EBUSY; goto chan_unlock; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index dee3025f0ec2..278adb05c4c9 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -109,6 +109,7 @@ static int l2cap_sock_bind(struct socket *sock, struct = sockaddr_unsized *addr, i return -EINVAL; } =20 + l2cap_chan_lock(chan); lock_sock(sk); =20 if (sk->sk_state !=3D BT_OPEN) { @@ -174,6 +175,7 @@ static int l2cap_sock_bind(struct socket *sock, struct = sockaddr_unsized *addr, i =20 done: release_sock(sk); + l2cap_chan_unlock(chan); return err; } =20 --=20 2.55.0