Linux kernel -stable discussions
 help / color / mirror / Atom feed
* FAILED: patch "[PATCH] Bluetooth: L2CAP: Reject signalling responses in invalid states" failed to apply to 5.15-stable tree
@ 2026-11-07 11:06 Sasha Levin
  2026-11-08  0:05 ` [PATCH 5.15.y 0/3] Bluetooth: L2CAP: signalling response fixes Siwei Zhang
                   ` (3 more replies)
  0 siblings, 4 replies; 24+ messages in thread
From: Sasha Levin @ 2026-11-07 11:06 UTC (permalink / raw)
  To: oss, luiz.von.dentz; +Cc: stable

The patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.

To reproduce the conflict and resubmit, you may use the following commands:

git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.15.y
git checkout FETCH_HEAD
git cherry-pick -x 6320736af7dcb90da6ee9fd651ecc11c564d45b7
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '20261107060628-failed-5.15-6320736af7dc@kernel.org' --subject-prefix 'PATCH 5.15.y' 'HEAD^..'

Thanks,
Sasha

------------------ original commit in Linus's tree ------------------

From 6320736af7dcb90da6ee9fd651ecc11c564d45b7 Mon Sep 17 00:00:00 2001
From: Siwei Zhang <oss@fourdim.xyz>
Date: Tue, 13 Oct 2026 11:36:34 -0400
Subject: [PATCH] Bluetooth: L2CAP: Reject signalling responses in invalid
 states

A peer can send configuration messages while an
incoming channel is in BT_CONNECT2, before the
security or deferred accept gate has completed. A
configuration response can then promote the channel
to BT_CONNECTED. Configuration responses can also
act on channels that are closing, and a late connection
response can move a disconnecting channel back to
BT_CONFIG.

Accept connection responses only while waiting in
BT_CONNECT. Answer configuration requests in
BT_CONNECT2, but defer our own request until
BT_CONFIG so configuration cannot complete before
the gate. Ignore configuration responses outside
BT_CONFIG and BT_CONNECTED, and only complete
configuration in BT_CONFIG.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
 net/bluetooth/l2cap_core.c | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index c730da87734b3..eb55c16760a7e 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -4442,6 +4442,10 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
 
 	lockdep_assert_held(&chan->conn->lock);
 
+	/* Ignore a late response after the channel has left BT_CONNECT. */
+	if (chan->state != BT_CONNECT)
+		goto done;
+
 	switch (result) {
 	case L2CAP_CR_SUCCESS:
 		if (__l2cap_get_chan_by_dcid(conn, dcid)) {
@@ -4471,6 +4475,7 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
 		break;
 	}
 
+done:
 	l2cap_chan_unlock(chan);
 	l2cap_chan_put(chan);
 
@@ -4608,7 +4613,13 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
 		goto unlock;
 	}
 
-	if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
+	/* A channel in BT_CONNECT2 has not passed security or userspace
+	 * accept yet. Answer the peer's request, but hold our own until
+	 * the channel reaches BT_CONFIG: the CONNECT2 -> CONFIG sites send
+	 * it. Connected channels may also need to reconfigure.
+	 */
+	if ((chan->state == BT_CONFIG || chan->state == BT_CONNECTED) &&
+	    !test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
 		u8 buf[64];
 		l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
 			       l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
@@ -4661,6 +4672,10 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
 
 	lockdep_assert_held(&chan->conn->lock);
 
+	/* Connected channels may also receive reconfiguration responses. */
+	if (chan->state != BT_CONFIG && chan->state != BT_CONNECTED)
+		goto done;
+
 	switch (result) {
 	case L2CAP_CONF_SUCCESS:
 		l2cap_conf_rfc_get(chan, rsp->data, len);
@@ -4728,6 +4743,9 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
 	if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
 		set_default_fcs(chan);
 
+		if (chan->state != BT_CONFIG)
+			goto done;
+
 		if (chan->mode == L2CAP_MODE_ERTM ||
 		    chan->mode == L2CAP_MODE_STREAMING)
 			err = l2cap_ertm_init(chan);
-- 
2.53.0





^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 5.15.y 0/3] Bluetooth: L2CAP: signalling response fixes
  2026-11-07 11:06 FAILED: patch "[PATCH] Bluetooth: L2CAP: Reject signalling responses in invalid states" failed to apply to 5.15-stable tree Sasha Levin
@ 2026-11-08  0:05 ` Siwei Zhang
  2026-11-08  0:05   ` [PATCH 5.15.y 1/3] Bluetooth: L2CAP: Reject signalling responses in invalid states Siwei Zhang
                     ` (2 more replies)
  2026-11-09  1:58 ` [PATCH 5.15.y v2 0/3] Bluetooth: L2CAP: signalling response fixes Siwei Zhang
                   ` (2 subsequent siblings)
  3 siblings, 3 replies; 24+ messages in thread
From: Siwei Zhang @ 2026-11-08  0:05 UTC (permalink / raw)
  To: stable

Backports of

  6320736af7dc ("Bluetooth: L2CAP: Reject signalling responses in invalid states")
  a518b9a9ef6e ("Bluetooth: L2CAP: Only accept connection responses to outstanding requests")

which failed to apply to the 5.15-stable tree:

  https://lore.kernel.org/stable/20261107060628-failed-5.15-6320736af7dc@kernel.org/
  https://lore.kernel.org/stable/20261107060634-failed-5.15-a518b9a9ef6e@kernel.org/

Patch 3 is a9f9eeb5344f ("Bluetooth: L2CAP: Ignore connection responses
with wrong ident"), which tightens the check added by patch 2 and only
applies on top of it.

The series goes on top of the three L2CAP patches already queued for
5.15.y:

  c1398cf11b31 ("Bluetooth: L2CAP: Reject mode changes on connected channels")
  c5ebb0245fe9 ("Bluetooth: L2CAP: Reject invalid TxWindow in configuration requests")
  226fa3b676cb ("Bluetooth: L2CAP: Use default TxWindow for zero socket option")

5.15.y still has AMP and A2MP, which upstream removed in e7b02296fb40
("Bluetooth: Remove BT_HS"). Patches 1 to 3 also close the same holes
in the AMP paths; the changes are described at the top of each commit
message.

Jinwang Li (1):
  Bluetooth: L2CAP: Ignore connection responses with wrong ident

Siwei Zhang (2):
  Bluetooth: L2CAP: Reject signalling responses in invalid states
  Bluetooth: L2CAP: Only accept connection responses to outstanding
    requests

 include/net/bluetooth/l2cap.h |   2 +-
 net/bluetooth/a2mp.c          |  10 +--
 net/bluetooth/a2mp.h          |   1 +
 net/bluetooth/l2cap_core.c    | 126 ++++++++++++++++++++++++++++++----
 4 files changed, 122 insertions(+), 17 deletions(-)

-- 
2.56.0


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 5.15.y 1/3] Bluetooth: L2CAP: Reject signalling responses in invalid states
  2026-11-08  0:05 ` [PATCH 5.15.y 0/3] Bluetooth: L2CAP: signalling response fixes Siwei Zhang
@ 2026-11-08  0:05   ` Siwei Zhang
  2026-11-08  0:05   ` [PATCH 5.15.y 2/3] Bluetooth: L2CAP: Only accept connection responses to outstanding requests Siwei Zhang
  2026-11-08  0:05   ` [PATCH 5.15.y 3/3] Bluetooth: L2CAP: Ignore connection responses with wrong ident Siwei Zhang
  2 siblings, 0 replies; 24+ messages in thread
From: Siwei Zhang @ 2026-11-08  0:05 UTC (permalink / raw)
  To: stable; +Cc: Luiz Augusto von Dentz

commit 6320736af7dcb90da6ee9fd651ecc11c564d45b7 upstream.

Adjusted context as stable does not have the lockdep_assert_held()
calls, and l2cap_get_chan_by_scid() still returns the channel locked,
so l2cap_config_rsp() does not lock it again.

Stable still has AMP support, which upstream removed in
commit e7b02296fb40 ("Bluetooth: Remove BT_HS"). Close the same holes
there:

l2cap_logical_finish_create() answers the peer's configuration request
and completes configuration once the AMP logical link is up. Only do
this in BT_CONFIG, so a channel that has not been accepted yet or is
being closed is neither marked as configured nor made ready.

l2cap_do_create() moves an incoming AMP channel to BT_CONFIG and sends
a successful create channel response once the physical link is up. It
only checked that we have no connection request outstanding, so a
channel still waiting in BT_CONNECT2 for security or deferred accept
was accepted, as was a channel already past BT_CONNECT2. Only do this
for a channel in BT_CONNECT2 that passes the checks l2cap_connect()
makes before it accepts a channel.

A peer can send configuration messages while an
incoming channel is in BT_CONNECT2, before the
security or deferred accept gate has completed. A
configuration response can then promote the channel
to BT_CONNECTED. Configuration responses can also
act on channels that are closing, and a late connection
response can move a disconnecting channel back to
BT_CONFIG.

Accept connection responses only while waiting in
BT_CONNECT. Answer configuration requests in
BT_CONNECT2, but defer our own request until
BT_CONFIG so configuration cannot complete before
the gate. Ignore configuration responses outside
BT_CONFIG and BT_CONNECTED, and only complete
configuration in BT_CONFIG.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
 net/bluetooth/l2cap_core.c | 38 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 36 insertions(+), 2 deletions(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index cc49e651907d..3204b95742a8 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -4443,6 +4443,10 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
 
 	l2cap_chan_lock(chan);
 
+	/* Ignore a late response after the channel has left BT_CONNECT. */
+	if (chan->state != BT_CONNECT)
+		goto done;
+
 	switch (result) {
 	case L2CAP_CR_SUCCESS:
 		if (__l2cap_get_chan_by_dcid(conn, dcid)) {
@@ -4472,6 +4476,7 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
 		break;
 	}
 
+done:
 	l2cap_chan_unlock(chan);
 	l2cap_chan_put(chan);
 
@@ -4607,7 +4612,13 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
 		goto unlock;
 	}
 
-	if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
+	/* A channel in BT_CONNECT2 has not passed security or userspace
+	 * accept yet. Answer the peer's request, but hold our own until
+	 * the channel reaches BT_CONFIG: the CONNECT2 -> CONFIG sites send
+	 * it. Connected channels may also need to reconfigure.
+	 */
+	if ((chan->state == BT_CONFIG || chan->state == BT_CONNECTED) &&
+	    !test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
 		u8 buf[64];
 		l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
 			       l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
@@ -4658,6 +4669,10 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
 	if (!chan)
 		return 0;
 
+	/* Connected channels may also receive reconfiguration responses. */
+	if (chan->state != BT_CONFIG && chan->state != BT_CONNECTED)
+		goto done;
+
 	switch (result) {
 	case L2CAP_CONF_SUCCESS:
 		l2cap_conf_rfc_get(chan, rsp->data, len);
@@ -4733,6 +4748,9 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
 	if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
 		set_default_fcs(chan);
 
+		if (chan->state != BT_CONFIG)
+			goto done;
+
 		if (chan->mode == L2CAP_MODE_ERTM ||
 		    chan->mode == L2CAP_MODE_STREAMING)
 			err = l2cap_ertm_init(chan);
@@ -5146,6 +5164,12 @@ static void l2cap_logical_finish_create(struct l2cap_chan *chan,
 	chan->hs_hchan = hchan;
 	chan->hs_hcon->l2cap_data = chan->conn;
 
+	/* Only answer the peer's configuration request and complete
+	 * configuration while the channel is being configured.
+	 */
+	if (chan->state != BT_CONFIG)
+		return;
+
 	l2cap_send_efs_conf_rsp(chan, &rsp, chan->ident, 0);
 
 	if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
@@ -5256,7 +5280,17 @@ static void l2cap_do_create(struct l2cap_chan *chan, int result,
 		return;
 	}
 
-	/* Incoming channel on AMP */
+	/* Incoming channel on AMP. Only answer it while it waits in
+	 * BT_CONNECT2 and has passed the feature mask exchange, security
+	 * and deferred accept, as l2cap_connect() requires before it
+	 * accepts a channel.
+	 */
+	if (chan->state != BT_CONNECT2 ||
+	    !(chan->conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) ||
+	    test_bit(FLAG_DEFER_SETUP, &chan->flags) ||
+	    !l2cap_chan_check_security(chan, false))
+		return;
+
 	if (__l2cap_no_conn_pending(chan)) {
 		struct l2cap_conn_rsp rsp;
 		char buf[128];
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 5.15.y 2/3] Bluetooth: L2CAP: Only accept connection responses to outstanding requests
  2026-11-08  0:05 ` [PATCH 5.15.y 0/3] Bluetooth: L2CAP: signalling response fixes Siwei Zhang
  2026-11-08  0:05   ` [PATCH 5.15.y 1/3] Bluetooth: L2CAP: Reject signalling responses in invalid states Siwei Zhang
@ 2026-11-08  0:05   ` Siwei Zhang
  2026-11-09  0:34     ` Sasha Levin
  2026-11-08  0:05   ` [PATCH 5.15.y 3/3] Bluetooth: L2CAP: Ignore connection responses with wrong ident Siwei Zhang
  2 siblings, 1 reply; 24+ messages in thread
From: Siwei Zhang @ 2026-11-08  0:05 UTC (permalink / raw)
  To: stable; +Cc: Luiz Augusto von Dentz

commit a518b9a9ef6ee3b18ecdf6ba5360c608aaf969e9 upstream.

Adjusted context as stable does not have the lockdep_assert_held()
call and the __must_hold() context analysis annotations, and
l2cap_connect_create_rsp() still holds conn->chan_lock and returns
through the unlock label when the channel lookup fails.

Stable still has AMP and A2MP support, which upstream removed in
commit e7b02296fb40 ("Bluetooth: Remove BT_HS"). Close the same holes
there:

l2cap_do_create() sends an L2CAP_CREATE_CHAN_REQ whose response is also
handled by l2cap_connect_create_rsp(). Set CONF_CONNECT_PEND in
l2cap_send_create_chan_req() as l2cap_send_conn_req() does, so that
the response to it is still accepted. This also makes
__l2cap_no_conn_pending() see that request as outstanding, so
l2cap_do_start(), l2cap_conn_start() and l2cap_security_cfm() leave
the channel alone until it is answered, as they already do for a
pending connection request. l2cap_do_create() itself now does the same
instead of sending a second request.

When an A2MP Discover Response lists no AMP controller,
a2mp_discover_rsp() falls back to sending a connection request for
every channel in BT_CONNECT, including channels still waiting for
security or the feature mask exchange, channels that are not
connection oriented and channels already setting up an AMP link. A
peer can send that response unsolicited, and the request it triggers
sets CONF_CONNECT_PEND, so the peer's connection response would still
be accepted before security completes. Only handle a Discover Response
while our Discover Request is outstanding. Move the checks
l2cap_do_start() makes before sending the connection request into
l2cap_chan_conn_req_allowed(), and add l2cap_amp_fallback_conn_req(),
which only sends the fallback request for a connection oriented channel
that has no request outstanding and passes those checks.
l2cap_send_conn_req() is no longer used outside l2cap_core.c, so make
it static.

An outgoing channel waits in BT_CONNECT until security
and the feature mask exchange complete, and only then
sends its connection request. A peer can answer it
before that with a connection response matching our
source CID. The channel then moves to BT_CONFIG,
completes configuration and becomes connected before
security has completed. If security then fails,
l2cap_security_cfm() leaves the connected channel
alone, so it stays up on a link that did not reach
the required security level.

A connection response with a zero source CID is
matched by identifier. Another channel can hold the
same identifier for a response it still has to send,
so the lookup can pick the wrong channel.

Only accept a connection response while our request
is outstanding, and only look at such channels when
matching by identifier.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
 include/net/bluetooth/l2cap.h |  2 +-
 net/bluetooth/a2mp.c          | 10 +++--
 net/bluetooth/a2mp.h          |  1 +
 net/bluetooth/l2cap_core.c    | 81 +++++++++++++++++++++++++++++------
 4 files changed, 77 insertions(+), 17 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 57315b9dc059..47156c773362 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -998,7 +998,7 @@ 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_send_conn_req(struct l2cap_chan *chan);
+void l2cap_amp_fallback_conn_req(struct l2cap_chan *chan);
 void l2cap_move_start(struct l2cap_chan *chan);
 void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
 		       u8 status);
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index e7adb8a98cf9..1b32fb05d70d 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -196,6 +196,10 @@ static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
 	u16 ext_feat;
 	bool found = false;
 
+	/* Only handle the response to our own Discover Request */
+	if (!test_and_clear_bit(DISCOVER_REQ_SENT, &mgr->state))
+		return 0;
+
 	if (len < sizeof(*rsp))
 		return -EINVAL;
 
@@ -254,10 +258,7 @@ static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
 				continue;
 
 			l2cap_chan_lock(chan);
-
-			if (chan->state == BT_CONNECT)
-				l2cap_send_conn_req(chan);
-
+			l2cap_amp_fallback_conn_req(chan);
 			l2cap_chan_unlock(chan);
 		}
 
@@ -1050,5 +1051,6 @@ void a2mp_discover_amp(struct l2cap_chan *chan)
 
 	req.mtu = cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU);
 	req.ext_feat = 0;
+	set_bit(DISCOVER_REQ_SENT, &mgr->state);
 	a2mp_send(mgr, A2MP_DISCOVER_REQ, 1, sizeof(req), &req);
 }
diff --git a/net/bluetooth/a2mp.h b/net/bluetooth/a2mp.h
index 2fd253a61a2a..1bf31aed8547 100644
--- a/net/bluetooth/a2mp.h
+++ b/net/bluetooth/a2mp.h
@@ -15,6 +15,7 @@ enum amp_mgr_state {
 	READ_LOC_AMP_ASSOC,
 	READ_LOC_AMP_ASSOC_FINAL,
 	WRITE_REMOTE_AMP_ASSOC,
+	DISCOVER_REQ_SENT,
 };
 
 struct amp_mgr {
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 3204b95742a8..227b1c8f35ca 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -185,6 +185,28 @@ static struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn,
 	return c;
 }
 
+/* Our connection request has been sent and is still outstanding */
+static bool l2cap_chan_connect_pending(struct l2cap_chan *chan)
+{
+	return chan->state == BT_CONNECT &&
+	       test_bit(CONF_CONNECT_PEND, &chan->conf_state);
+}
+
+/* Other channels may hold the same ident for a response they still have
+ * to send, so only look at channels waiting for a connection response.
+ */
+static struct l2cap_chan *__l2cap_get_connect_chan_by_ident(struct l2cap_conn *conn,
+							    u8 ident)
+{
+	struct l2cap_chan *c;
+
+	list_for_each_entry(c, &conn->chan_l, list) {
+		if (c->ident == ident && l2cap_chan_connect_pending(c))
+			return c;
+	}
+	return NULL;
+}
+
 static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src,
 						      u8 src_type)
 {
@@ -1305,7 +1327,7 @@ static bool l2cap_check_efs(struct l2cap_chan *chan)
 	return true;
 }
 
-void l2cap_send_conn_req(struct l2cap_chan *chan)
+static void l2cap_send_conn_req(struct l2cap_chan *chan)
 {
 	struct l2cap_conn *conn = chan->conn;
 	struct l2cap_conn_req req;
@@ -1329,6 +1351,8 @@ static void l2cap_send_create_chan_req(struct l2cap_chan *chan, u8 amp_id)
 
 	chan->ident = l2cap_get_ident(chan->conn);
 
+	set_bit(CONF_CONNECT_PEND, &chan->conf_state);
+
 	l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CREATE_CHAN_REQ,
 		       sizeof(req), &req);
 }
@@ -1592,6 +1616,26 @@ static bool l2cap_check_enc_key_size(struct hci_conn *hcon,
 		hcon->enc_key_size >= min_key_size);
 }
 
+/* Check that a BR/EDR channel may send its connection request now */
+static bool l2cap_chan_conn_req_allowed(struct l2cap_chan *chan)
+{
+	struct l2cap_conn *conn = chan->conn;
+
+	if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
+		return false;
+
+	if (!l2cap_chan_check_security(chan, true) ||
+	    !__l2cap_no_conn_pending(chan))
+		return false;
+
+	if (!l2cap_check_enc_key_size(conn->hcon, chan)) {
+		__set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
+		return false;
+	}
+
+	return true;
+}
+
 static void l2cap_do_start(struct l2cap_chan *chan)
 {
 	struct l2cap_conn *conn = chan->conn;
@@ -1606,17 +1650,23 @@ static void l2cap_do_start(struct l2cap_chan *chan)
 		return;
 	}
 
-	if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
-		return;
+	if (l2cap_chan_conn_req_allowed(chan))
+		l2cap_start_connection(chan);
+}
 
-	if (!l2cap_chan_check_security(chan, true) ||
-	    !__l2cap_no_conn_pending(chan))
+/* A2MP found no AMP controller to use, so send the BR/EDR connection
+ * request instead, if the channel is still waiting to send one and
+ * passes the same checks as in l2cap_do_start(). Test for an outstanding
+ * request first, as the security check may start authentication.
+ */
+void l2cap_amp_fallback_conn_req(struct l2cap_chan *chan)
+{
+	if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED ||
+	    chan->state != BT_CONNECT || !__l2cap_no_conn_pending(chan))
 		return;
 
-	if (l2cap_check_enc_key_size(conn->hcon, chan))
-		l2cap_start_connection(chan);
-	else
-		__set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
+	if (l2cap_chan_conn_req_allowed(chan))
+		l2cap_send_conn_req(chan);
 }
 
 static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
@@ -4426,7 +4476,7 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
 			goto unlock;
 		}
 	} else {
-		chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
+		chan = __l2cap_get_connect_chan_by_ident(conn, cmd->ident);
 		if (!chan) {
 			err = -EBADSLT;
 			goto unlock;
@@ -4443,8 +4493,11 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
 
 	l2cap_chan_lock(chan);
 
-	/* Ignore a late response after the channel has left BT_CONNECT. */
-	if (chan->state != BT_CONNECT)
+	/* Only accept a response to a connection request we sent and that
+	 * is still outstanding. A channel waiting in BT_CONNECT for security
+	 * or the feature mask has not sent one yet.
+	 */
+	if (!l2cap_chan_connect_pending(chan))
 		goto done;
 
 	switch (result) {
@@ -5269,6 +5322,10 @@ static void l2cap_do_create(struct l2cap_chan *chan, int result,
 
 	/* Outgoing channel on AMP */
 	if (chan->state == BT_CONNECT) {
+		/* Never send a second request while one is outstanding */
+		if (!__l2cap_no_conn_pending(chan))
+			return;
+
 		if (result == L2CAP_CR_SUCCESS) {
 			chan->local_amp_id = local_amp_id;
 			l2cap_send_create_chan_req(chan, remote_amp_id);
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 5.15.y 3/3] Bluetooth: L2CAP: Ignore connection responses with wrong ident
  2026-11-08  0:05 ` [PATCH 5.15.y 0/3] Bluetooth: L2CAP: signalling response fixes Siwei Zhang
  2026-11-08  0:05   ` [PATCH 5.15.y 1/3] Bluetooth: L2CAP: Reject signalling responses in invalid states Siwei Zhang
  2026-11-08  0:05   ` [PATCH 5.15.y 2/3] Bluetooth: L2CAP: Only accept connection responses to outstanding requests Siwei Zhang
@ 2026-11-08  0:05   ` Siwei Zhang
  2 siblings, 0 replies; 24+ messages in thread
From: Siwei Zhang @ 2026-11-08  0:05 UTC (permalink / raw)
  To: stable; +Cc: Jinwang Li, Luiz Augusto von Dentz

From: Jinwang Li <jinwang.li@oss.qualcomm.com>

commit a9f9eeb5344fc7dc625e5700ccf09891bc2603b5 upstream.

Adjusted context as stable does not have the lockdep_assert_held()
call in l2cap_connect_create_rsp().

Stable still has AMP support, where the response to an
L2CAP_CREATE_CHAN_REQ is also handled by l2cap_connect_create_rsp().
l2cap_send_create_chan_req() stores its ident in chan->ident as
l2cap_send_conn_req() does, so that response is checked the same way.
l2cap_move_channel_req() looks the channel up by dcid and overwrites
chan->ident before checking it. A channel still waiting for its
connection response has dcid 0, so a Move Channel Request with icid 0
would replace the ident this check needs and the real response would be
dropped. Only handle Move Channel Requests for connected channels.

L2CAP/COS/CED/BI-28-C requires the IUT to ignore a Connection Response
that carries an invalid Identifier.

l2cap_connect_create_rsp() only checks that a connection request is
outstanding, not that the response answers it. Add an ident check
against the pending request so that a mismatched response is dropped.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Jinwang Li <jinwang.li@oss.qualcomm.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
---
 net/bluetooth/l2cap_core.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 227b1c8f35ca..c485b43d5fe0 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -4493,11 +4493,11 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
 
 	l2cap_chan_lock(chan);
 
-	/* Only accept a response to a connection request we sent and that
-	 * is still outstanding. A channel waiting in BT_CONNECT for security
-	 * or the feature mask has not sent one yet.
+	/* Only accept a response matching a connection request we sent and
+	 * that is still outstanding. A channel waiting in BT_CONNECT for
+	 * security or the feature mask has not sent one yet.
 	 */
-	if (!l2cap_chan_connect_pending(chan))
+	if (!l2cap_chan_connect_pending(chan) || chan->ident != cmd->ident)
 		goto done;
 
 	switch (result) {
@@ -5485,6 +5485,17 @@ static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
 		return -EINVAL;
 
 	chan = l2cap_get_chan_by_dcid(conn, icid);
+
+	/* Only connected channels can be moved. A channel still waiting
+	 * for its connection response has no dcid yet, and its ident must
+	 * not be overwritten.
+	 */
+	if (chan && chan->state != BT_CONNECTED) {
+		l2cap_chan_unlock(chan);
+		l2cap_chan_put(chan);
+		chan = NULL;
+	}
+
 	if (!chan) {
 		rsp.icid = cpu_to_le16(icid);
 		rsp.result = cpu_to_le16(L2CAP_MR_NOT_ALLOWED);
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [PATCH 5.15.y 2/3] Bluetooth: L2CAP: Only accept connection responses to outstanding requests
  2026-11-08  0:05   ` [PATCH 5.15.y 2/3] Bluetooth: L2CAP: Only accept connection responses to outstanding requests Siwei Zhang
@ 2026-11-09  0:34     ` Sasha Levin
  2026-11-09  2:03       ` Siwei Zhang
  0 siblings, 1 reply; 24+ messages in thread
From: Sasha Levin @ 2026-11-09  0:34 UTC (permalink / raw)
  To: stable; +Cc: Sasha Levin, Luiz Augusto von Dentz, Siwei Zhang

> +	/* Only handle the response to our own Discover Request */
> +	if (!test_and_clear_bit(DISCOVER_REQ_SENT, &mgr->state))
> +		return 0;
> +

This early return skips the skb_pull(skb, le16_to_cpu(hdr->len)) that every
other A2MP handler does. a2mp_chan_recv_cb() loops while skb->len >=
sizeof(hdr), so the payload of an unsolicited Discover Response gets parsed as
the next A2MP command header.

Please pull the payload before returning (or drop the A2MP extras from the
patch) and resend the 5.15 series. The 7.3 through 6.1 versions are queued.

-- 
Thanks,
Sasha

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 5.15.y v2 0/3] Bluetooth: L2CAP: signalling response fixes
  2026-11-07 11:06 FAILED: patch "[PATCH] Bluetooth: L2CAP: Reject signalling responses in invalid states" failed to apply to 5.15-stable tree Sasha Levin
  2026-11-08  0:05 ` [PATCH 5.15.y 0/3] Bluetooth: L2CAP: signalling response fixes Siwei Zhang
@ 2026-11-09  1:58 ` Siwei Zhang
  2026-11-09  1:58   ` [PATCH 5.15.y v2 1/3] Bluetooth: L2CAP: Reject signalling responses in invalid states Siwei Zhang
                     ` (3 more replies)
  2026-11-10 19:10 ` [PATCH 5.15.y v3 " Siwei Zhang
  2026-11-11 22:07 ` [PATCH 5.15.y v4 0/3] Bluetooth: L2CAP: signalling response fixes Siwei Zhang
  3 siblings, 4 replies; 24+ messages in thread
From: Siwei Zhang @ 2026-11-09  1:58 UTC (permalink / raw)
  To: stable; +Cc: Luiz Augusto von Dentz

Backports of

  6320736af7dc ("Bluetooth: L2CAP: Reject signalling responses in invalid states")
  a518b9a9ef6e ("Bluetooth: L2CAP: Only accept connection responses to outstanding requests")

which failed to apply to the 5.15-stable tree:

  https://lore.kernel.org/stable/20261107060628-failed-5.15-6320736af7dc@kernel.org/
  https://lore.kernel.org/stable/20261107060634-failed-5.15-a518b9a9ef6e@kernel.org/

Patch 3 is a9f9eeb5344f ("Bluetooth: L2CAP: Ignore connection responses
with wrong ident"), which tightens the check added by patch 2 and only
applies on top of it.

The series goes on top of the three L2CAP patches already queued for
5.15.y:

  c1398cf11b31 ("Bluetooth: L2CAP: Reject mode changes on connected channels")
  c5ebb0245fe9 ("Bluetooth: L2CAP: Reject invalid TxWindow in configuration requests")
  226fa3b676cb ("Bluetooth: L2CAP: Use default TxWindow for zero socket option")

5.15.y still has AMP and A2MP, which upstream removed in e7b02296fb40
("Bluetooth: Remove BT_HS"). Patches 1 to 3 also close the same holes
in the AMP paths; the changes are described at the top of each commit
message.

Changes in v2:
- Patch 2: a2mp_discover_rsp() now pulls the payload of an unsolicited
  Discover Response before returning, so a2mp_chan_recv_cb() does not
  parse it as the next A2MP command header.
  https://lore.kernel.org/stable/2026-11-08-1-daily-reply-0003-l2cap-a2mp-5-15@kernel.org/

v1: https://lore.kernel.org/stable/20261108000542.1969015-1-oss@fourdim.xyz/

Jinwang Li (1):
  Bluetooth: L2CAP: Ignore connection responses with wrong ident

Siwei Zhang (2):
  Bluetooth: L2CAP: Reject signalling responses in invalid states
  Bluetooth: L2CAP: Only accept connection responses to outstanding
    requests

 include/net/bluetooth/l2cap.h |   2 +-
 net/bluetooth/a2mp.c          |  12 ++--
 net/bluetooth/a2mp.h          |   1 +
 net/bluetooth/l2cap_core.c    | 126 ++++++++++++++++++++++++++++++----
 4 files changed, 124 insertions(+), 17 deletions(-)

-- 
2.56.0


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 5.15.y v2 1/3] Bluetooth: L2CAP: Reject signalling responses in invalid states
  2026-11-09  1:58 ` [PATCH 5.15.y v2 0/3] Bluetooth: L2CAP: signalling response fixes Siwei Zhang
@ 2026-11-09  1:58   ` Siwei Zhang
  2026-11-09  1:58   ` [PATCH 5.15.y v2 2/3] Bluetooth: L2CAP: Only accept connection responses to outstanding requests Siwei Zhang
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 24+ messages in thread
From: Siwei Zhang @ 2026-11-09  1:58 UTC (permalink / raw)
  To: stable; +Cc: Luiz Augusto von Dentz

commit 6320736af7dcb90da6ee9fd651ecc11c564d45b7 upstream.

Adjusted context as stable does not have the lockdep_assert_held()
calls, and l2cap_get_chan_by_scid() still returns the channel locked,
so l2cap_config_rsp() does not lock it again.

Stable still has AMP support, which upstream removed in
commit e7b02296fb40 ("Bluetooth: Remove BT_HS"). Close the same holes
there:

l2cap_logical_finish_create() answers the peer's configuration request
and completes configuration once the AMP logical link is up. Only do
this in BT_CONFIG, so a channel that has not been accepted yet or is
being closed is neither marked as configured nor made ready.

l2cap_do_create() moves an incoming AMP channel to BT_CONFIG and sends
a successful create channel response once the physical link is up. It
only checked that we have no connection request outstanding, so a
channel still waiting in BT_CONNECT2 for security or deferred accept
was accepted, as was a channel already past BT_CONNECT2. Only do this
for a channel in BT_CONNECT2 that passes the checks l2cap_connect()
makes before it accepts a channel.

A peer can send configuration messages while an
incoming channel is in BT_CONNECT2, before the
security or deferred accept gate has completed. A
configuration response can then promote the channel
to BT_CONNECTED. Configuration responses can also
act on channels that are closing, and a late connection
response can move a disconnecting channel back to
BT_CONFIG.

Accept connection responses only while waiting in
BT_CONNECT. Answer configuration requests in
BT_CONNECT2, but defer our own request until
BT_CONFIG so configuration cannot complete before
the gate. Ignore configuration responses outside
BT_CONFIG and BT_CONNECTED, and only complete
configuration in BT_CONFIG.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
 net/bluetooth/l2cap_core.c | 38 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 36 insertions(+), 2 deletions(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index cc49e651907d..3204b95742a8 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -4443,6 +4443,10 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
 
 	l2cap_chan_lock(chan);
 
+	/* Ignore a late response after the channel has left BT_CONNECT. */
+	if (chan->state != BT_CONNECT)
+		goto done;
+
 	switch (result) {
 	case L2CAP_CR_SUCCESS:
 		if (__l2cap_get_chan_by_dcid(conn, dcid)) {
@@ -4472,6 +4476,7 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
 		break;
 	}
 
+done:
 	l2cap_chan_unlock(chan);
 	l2cap_chan_put(chan);
 
@@ -4607,7 +4612,13 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
 		goto unlock;
 	}
 
-	if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
+	/* A channel in BT_CONNECT2 has not passed security or userspace
+	 * accept yet. Answer the peer's request, but hold our own until
+	 * the channel reaches BT_CONFIG: the CONNECT2 -> CONFIG sites send
+	 * it. Connected channels may also need to reconfigure.
+	 */
+	if ((chan->state == BT_CONFIG || chan->state == BT_CONNECTED) &&
+	    !test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
 		u8 buf[64];
 		l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
 			       l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
@@ -4658,6 +4669,10 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
 	if (!chan)
 		return 0;
 
+	/* Connected channels may also receive reconfiguration responses. */
+	if (chan->state != BT_CONFIG && chan->state != BT_CONNECTED)
+		goto done;
+
 	switch (result) {
 	case L2CAP_CONF_SUCCESS:
 		l2cap_conf_rfc_get(chan, rsp->data, len);
@@ -4733,6 +4748,9 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
 	if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
 		set_default_fcs(chan);
 
+		if (chan->state != BT_CONFIG)
+			goto done;
+
 		if (chan->mode == L2CAP_MODE_ERTM ||
 		    chan->mode == L2CAP_MODE_STREAMING)
 			err = l2cap_ertm_init(chan);
@@ -5146,6 +5164,12 @@ static void l2cap_logical_finish_create(struct l2cap_chan *chan,
 	chan->hs_hchan = hchan;
 	chan->hs_hcon->l2cap_data = chan->conn;
 
+	/* Only answer the peer's configuration request and complete
+	 * configuration while the channel is being configured.
+	 */
+	if (chan->state != BT_CONFIG)
+		return;
+
 	l2cap_send_efs_conf_rsp(chan, &rsp, chan->ident, 0);
 
 	if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
@@ -5256,7 +5280,17 @@ static void l2cap_do_create(struct l2cap_chan *chan, int result,
 		return;
 	}
 
-	/* Incoming channel on AMP */
+	/* Incoming channel on AMP. Only answer it while it waits in
+	 * BT_CONNECT2 and has passed the feature mask exchange, security
+	 * and deferred accept, as l2cap_connect() requires before it
+	 * accepts a channel.
+	 */
+	if (chan->state != BT_CONNECT2 ||
+	    !(chan->conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) ||
+	    test_bit(FLAG_DEFER_SETUP, &chan->flags) ||
+	    !l2cap_chan_check_security(chan, false))
+		return;
+
 	if (__l2cap_no_conn_pending(chan)) {
 		struct l2cap_conn_rsp rsp;
 		char buf[128];
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 5.15.y v2 2/3] Bluetooth: L2CAP: Only accept connection responses to outstanding requests
  2026-11-09  1:58 ` [PATCH 5.15.y v2 0/3] Bluetooth: L2CAP: signalling response fixes Siwei Zhang
  2026-11-09  1:58   ` [PATCH 5.15.y v2 1/3] Bluetooth: L2CAP: Reject signalling responses in invalid states Siwei Zhang
@ 2026-11-09  1:58   ` Siwei Zhang
  2026-11-09  1:58   ` [PATCH 5.15.y v2 3/3] Bluetooth: L2CAP: Ignore connection responses with wrong ident Siwei Zhang
  2026-11-09 15:53   ` [PATCH 5.15.y v2 0/3] Bluetooth: L2CAP: signalling response fixes Sasha Levin
  3 siblings, 0 replies; 24+ messages in thread
From: Siwei Zhang @ 2026-11-09  1:58 UTC (permalink / raw)
  To: stable; +Cc: Luiz Augusto von Dentz

commit a518b9a9ef6ee3b18ecdf6ba5360c608aaf969e9 upstream.

Adjusted context as stable does not have the lockdep_assert_held()
call and the __must_hold() context analysis annotations, and
l2cap_connect_create_rsp() still holds conn->chan_lock and returns
through the unlock label when the channel lookup fails.

Stable still has AMP and A2MP support, which upstream removed in
commit e7b02296fb40 ("Bluetooth: Remove BT_HS"). Close the same holes
there:

l2cap_do_create() sends an L2CAP_CREATE_CHAN_REQ whose response is also
handled by l2cap_connect_create_rsp(). Set CONF_CONNECT_PEND in
l2cap_send_create_chan_req() as l2cap_send_conn_req() does, so that
the response to it is still accepted. This also makes
__l2cap_no_conn_pending() see that request as outstanding, so
l2cap_do_start(), l2cap_conn_start() and l2cap_security_cfm() leave
the channel alone until it is answered, as they already do for a
pending connection request. l2cap_do_create() itself now does the same
instead of sending a second request.

When an A2MP Discover Response lists no AMP controller,
a2mp_discover_rsp() falls back to sending a connection request for
every channel in BT_CONNECT, including channels still waiting for
security or the feature mask exchange, channels that are not
connection oriented and channels already setting up an AMP link. A
peer can send that response unsolicited, and the request it triggers
sets CONF_CONNECT_PEND, so the peer's connection response would still
be accepted before security completes. Only handle a Discover Response
while our Discover Request is outstanding. Move the checks
l2cap_do_start() makes before sending the connection request into
l2cap_chan_conn_req_allowed(), and add l2cap_amp_fallback_conn_req(),
which only sends the fallback request for a connection oriented channel
that has no request outstanding and passes those checks.
l2cap_send_conn_req() is no longer used outside l2cap_core.c, so make
it static.

An outgoing channel waits in BT_CONNECT until security
and the feature mask exchange complete, and only then
sends its connection request. A peer can answer it
before that with a connection response matching our
source CID. The channel then moves to BT_CONFIG,
completes configuration and becomes connected before
security has completed. If security then fails,
l2cap_security_cfm() leaves the connected channel
alone, so it stays up on a link that did not reach
the required security level.

A connection response with a zero source CID is
matched by identifier. Another channel can hold the
same identifier for a response it still has to send,
so the lookup can pick the wrong channel.

Only accept a connection response while our request
is outstanding, and only look at such channels when
matching by identifier.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
v2: Pull the payload of an unsolicited A2MP Discover Response before
    returning from a2mp_discover_rsp().
    https://lore.kernel.org/stable/2026-11-08-1-daily-reply-0003-l2cap-a2mp-5-15@kernel.org/

 include/net/bluetooth/l2cap.h |  2 +-
 net/bluetooth/a2mp.c          | 12 ++++--
 net/bluetooth/a2mp.h          |  1 +
 net/bluetooth/l2cap_core.c    | 81 +++++++++++++++++++++++++++++------
 4 files changed, 79 insertions(+), 17 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 57315b9dc059..47156c773362 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -998,7 +998,7 @@ 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_send_conn_req(struct l2cap_chan *chan);
+void l2cap_amp_fallback_conn_req(struct l2cap_chan *chan);
 void l2cap_move_start(struct l2cap_chan *chan);
 void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
 		       u8 status);
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index e7adb8a98cf9..2ef7e3280325 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -196,6 +196,12 @@ static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
 	u16 ext_feat;
 	bool found = false;
 
+	/* Only handle the response to our own Discover Request */
+	if (!test_and_clear_bit(DISCOVER_REQ_SENT, &mgr->state)) {
+		skb_pull(skb, le16_to_cpu(hdr->len));
+		return 0;
+	}
+
 	if (len < sizeof(*rsp))
 		return -EINVAL;
 
@@ -254,10 +260,7 @@ static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
 				continue;
 
 			l2cap_chan_lock(chan);
-
-			if (chan->state == BT_CONNECT)
-				l2cap_send_conn_req(chan);
-
+			l2cap_amp_fallback_conn_req(chan);
 			l2cap_chan_unlock(chan);
 		}
 
@@ -1050,5 +1053,6 @@ void a2mp_discover_amp(struct l2cap_chan *chan)
 
 	req.mtu = cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU);
 	req.ext_feat = 0;
+	set_bit(DISCOVER_REQ_SENT, &mgr->state);
 	a2mp_send(mgr, A2MP_DISCOVER_REQ, 1, sizeof(req), &req);
 }
diff --git a/net/bluetooth/a2mp.h b/net/bluetooth/a2mp.h
index 2fd253a61a2a..1bf31aed8547 100644
--- a/net/bluetooth/a2mp.h
+++ b/net/bluetooth/a2mp.h
@@ -15,6 +15,7 @@ enum amp_mgr_state {
 	READ_LOC_AMP_ASSOC,
 	READ_LOC_AMP_ASSOC_FINAL,
 	WRITE_REMOTE_AMP_ASSOC,
+	DISCOVER_REQ_SENT,
 };
 
 struct amp_mgr {
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 3204b95742a8..227b1c8f35ca 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -185,6 +185,28 @@ static struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn,
 	return c;
 }
 
+/* Our connection request has been sent and is still outstanding */
+static bool l2cap_chan_connect_pending(struct l2cap_chan *chan)
+{
+	return chan->state == BT_CONNECT &&
+	       test_bit(CONF_CONNECT_PEND, &chan->conf_state);
+}
+
+/* Other channels may hold the same ident for a response they still have
+ * to send, so only look at channels waiting for a connection response.
+ */
+static struct l2cap_chan *__l2cap_get_connect_chan_by_ident(struct l2cap_conn *conn,
+							    u8 ident)
+{
+	struct l2cap_chan *c;
+
+	list_for_each_entry(c, &conn->chan_l, list) {
+		if (c->ident == ident && l2cap_chan_connect_pending(c))
+			return c;
+	}
+	return NULL;
+}
+
 static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src,
 						      u8 src_type)
 {
@@ -1305,7 +1327,7 @@ static bool l2cap_check_efs(struct l2cap_chan *chan)
 	return true;
 }
 
-void l2cap_send_conn_req(struct l2cap_chan *chan)
+static void l2cap_send_conn_req(struct l2cap_chan *chan)
 {
 	struct l2cap_conn *conn = chan->conn;
 	struct l2cap_conn_req req;
@@ -1329,6 +1351,8 @@ static void l2cap_send_create_chan_req(struct l2cap_chan *chan, u8 amp_id)
 
 	chan->ident = l2cap_get_ident(chan->conn);
 
+	set_bit(CONF_CONNECT_PEND, &chan->conf_state);
+
 	l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CREATE_CHAN_REQ,
 		       sizeof(req), &req);
 }
@@ -1592,6 +1616,26 @@ static bool l2cap_check_enc_key_size(struct hci_conn *hcon,
 		hcon->enc_key_size >= min_key_size);
 }
 
+/* Check that a BR/EDR channel may send its connection request now */
+static bool l2cap_chan_conn_req_allowed(struct l2cap_chan *chan)
+{
+	struct l2cap_conn *conn = chan->conn;
+
+	if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
+		return false;
+
+	if (!l2cap_chan_check_security(chan, true) ||
+	    !__l2cap_no_conn_pending(chan))
+		return false;
+
+	if (!l2cap_check_enc_key_size(conn->hcon, chan)) {
+		__set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
+		return false;
+	}
+
+	return true;
+}
+
 static void l2cap_do_start(struct l2cap_chan *chan)
 {
 	struct l2cap_conn *conn = chan->conn;
@@ -1606,17 +1650,23 @@ static void l2cap_do_start(struct l2cap_chan *chan)
 		return;
 	}
 
-	if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
-		return;
+	if (l2cap_chan_conn_req_allowed(chan))
+		l2cap_start_connection(chan);
+}
 
-	if (!l2cap_chan_check_security(chan, true) ||
-	    !__l2cap_no_conn_pending(chan))
+/* A2MP found no AMP controller to use, so send the BR/EDR connection
+ * request instead, if the channel is still waiting to send one and
+ * passes the same checks as in l2cap_do_start(). Test for an outstanding
+ * request first, as the security check may start authentication.
+ */
+void l2cap_amp_fallback_conn_req(struct l2cap_chan *chan)
+{
+	if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED ||
+	    chan->state != BT_CONNECT || !__l2cap_no_conn_pending(chan))
 		return;
 
-	if (l2cap_check_enc_key_size(conn->hcon, chan))
-		l2cap_start_connection(chan);
-	else
-		__set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
+	if (l2cap_chan_conn_req_allowed(chan))
+		l2cap_send_conn_req(chan);
 }
 
 static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
@@ -4426,7 +4476,7 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
 			goto unlock;
 		}
 	} else {
-		chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
+		chan = __l2cap_get_connect_chan_by_ident(conn, cmd->ident);
 		if (!chan) {
 			err = -EBADSLT;
 			goto unlock;
@@ -4443,8 +4493,11 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
 
 	l2cap_chan_lock(chan);
 
-	/* Ignore a late response after the channel has left BT_CONNECT. */
-	if (chan->state != BT_CONNECT)
+	/* Only accept a response to a connection request we sent and that
+	 * is still outstanding. A channel waiting in BT_CONNECT for security
+	 * or the feature mask has not sent one yet.
+	 */
+	if (!l2cap_chan_connect_pending(chan))
 		goto done;
 
 	switch (result) {
@@ -5269,6 +5322,10 @@ static void l2cap_do_create(struct l2cap_chan *chan, int result,
 
 	/* Outgoing channel on AMP */
 	if (chan->state == BT_CONNECT) {
+		/* Never send a second request while one is outstanding */
+		if (!__l2cap_no_conn_pending(chan))
+			return;
+
 		if (result == L2CAP_CR_SUCCESS) {
 			chan->local_amp_id = local_amp_id;
 			l2cap_send_create_chan_req(chan, remote_amp_id);
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 5.15.y v2 3/3] Bluetooth: L2CAP: Ignore connection responses with wrong ident
  2026-11-09  1:58 ` [PATCH 5.15.y v2 0/3] Bluetooth: L2CAP: signalling response fixes Siwei Zhang
  2026-11-09  1:58   ` [PATCH 5.15.y v2 1/3] Bluetooth: L2CAP: Reject signalling responses in invalid states Siwei Zhang
  2026-11-09  1:58   ` [PATCH 5.15.y v2 2/3] Bluetooth: L2CAP: Only accept connection responses to outstanding requests Siwei Zhang
@ 2026-11-09  1:58   ` Siwei Zhang
  2026-11-09 15:53   ` [PATCH 5.15.y v2 0/3] Bluetooth: L2CAP: signalling response fixes Sasha Levin
  3 siblings, 0 replies; 24+ messages in thread
From: Siwei Zhang @ 2026-11-09  1:58 UTC (permalink / raw)
  To: stable; +Cc: Luiz Augusto von Dentz, Jinwang Li

From: Jinwang Li <jinwang.li@oss.qualcomm.com>

commit a9f9eeb5344fc7dc625e5700ccf09891bc2603b5 upstream.

Adjusted context as stable does not have the lockdep_assert_held()
call in l2cap_connect_create_rsp().

Stable still has AMP support, where the response to an
L2CAP_CREATE_CHAN_REQ is also handled by l2cap_connect_create_rsp().
l2cap_send_create_chan_req() stores its ident in chan->ident as
l2cap_send_conn_req() does, so that response is checked the same way.
l2cap_move_channel_req() looks the channel up by dcid and overwrites
chan->ident before checking it. A channel still waiting for its
connection response has dcid 0, so a Move Channel Request with icid 0
would replace the ident this check needs and the real response would be
dropped. Only handle Move Channel Requests for connected channels.

L2CAP/COS/CED/BI-28-C requires the IUT to ignore a Connection Response
that carries an invalid Identifier.

l2cap_connect_create_rsp() only checks that a connection request is
outstanding, not that the response answers it. Add an ident check
against the pending request so that a mismatched response is dropped.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Jinwang Li <jinwang.li@oss.qualcomm.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
---
 net/bluetooth/l2cap_core.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 227b1c8f35ca..c485b43d5fe0 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -4493,11 +4493,11 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
 
 	l2cap_chan_lock(chan);
 
-	/* Only accept a response to a connection request we sent and that
-	 * is still outstanding. A channel waiting in BT_CONNECT for security
-	 * or the feature mask has not sent one yet.
+	/* Only accept a response matching a connection request we sent and
+	 * that is still outstanding. A channel waiting in BT_CONNECT for
+	 * security or the feature mask has not sent one yet.
 	 */
-	if (!l2cap_chan_connect_pending(chan))
+	if (!l2cap_chan_connect_pending(chan) || chan->ident != cmd->ident)
 		goto done;
 
 	switch (result) {
@@ -5485,6 +5485,17 @@ static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
 		return -EINVAL;
 
 	chan = l2cap_get_chan_by_dcid(conn, icid);
+
+	/* Only connected channels can be moved. A channel still waiting
+	 * for its connection response has no dcid yet, and its ident must
+	 * not be overwritten.
+	 */
+	if (chan && chan->state != BT_CONNECTED) {
+		l2cap_chan_unlock(chan);
+		l2cap_chan_put(chan);
+		chan = NULL;
+	}
+
 	if (!chan) {
 		rsp.icid = cpu_to_le16(icid);
 		rsp.result = cpu_to_le16(L2CAP_MR_NOT_ALLOWED);
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [PATCH 5.15.y 2/3] Bluetooth: L2CAP: Only accept connection responses to outstanding requests
  2026-11-09  0:34     ` Sasha Levin
@ 2026-11-09  2:03       ` Siwei Zhang
  0 siblings, 0 replies; 24+ messages in thread
From: Siwei Zhang @ 2026-11-09  2:03 UTC (permalink / raw)
  To: Sasha Levin, stable; +Cc: Luiz Augusto von Dentz



On Sun, Nov 8, 2026, at 7:34 PM, Sasha Levin wrote:
>> +	/* Only handle the response to our own Discover Request */
>> +	if (!test_and_clear_bit(DISCOVER_REQ_SENT, &mgr->state))
>> +		return 0;
>> +
>
> This early return skips the skb_pull(skb, le16_to_cpu(hdr->len)) that every
> other A2MP handler does. a2mp_chan_recv_cb() loops while skb->len >=
> sizeof(hdr), so the payload of an unsolicited Discover Response gets parsed as
> the next A2MP command header.
>

Thank you for pointing this out.

> Please pull the payload before returning (or drop the A2MP extras from the
> patch) and resend the 5.15 series. The 7.3 through 6.1 versions are queued.
>

Latest v2 for 5.10 and 5.15 series sent. 
Thank you taking care of these patches for me.

> -- 
> Thanks,
> Sasha

Best,
Siwei

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 5.15.y v2 0/3] Bluetooth: L2CAP: signalling response fixes
  2026-11-09  1:58 ` [PATCH 5.15.y v2 0/3] Bluetooth: L2CAP: signalling response fixes Siwei Zhang
                     ` (2 preceding siblings ...)
  2026-11-09  1:58   ` [PATCH 5.15.y v2 3/3] Bluetooth: L2CAP: Ignore connection responses with wrong ident Siwei Zhang
@ 2026-11-09 15:53   ` Sasha Levin
  2026-11-10 15:08     ` Siwei Zhang
  2026-11-10 19:13     ` Siwei Zhang
  3 siblings, 2 replies; 24+ messages in thread
From: Sasha Levin @ 2026-11-09 15:53 UTC (permalink / raw)
  To: stable; +Cc: Sasha Levin, Luiz Augusto von Dentz, Siwei Zhang

> Bluetooth: L2CAP: signalling response fixes

Thanks for the v2. The 5.15 and 5.10 series add AMP/A2MP hunks that are not in
6320736af7dc ("Bluetooth: L2CAP: Reject signalling responses in invalid
states"), a518b9a9ef6e ("Bluetooth: L2CAP: Only accept connection responses to
outstanding requests") or a9f9eeb5344f ("Bluetooth: L2CAP: Ignore connection
responses with wrong ident").

Luiz, could you ack those AMP extras? I will queue both series once there is an
ack.

-- 
Thanks,
Sasha

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 5.15.y v2 0/3] Bluetooth: L2CAP: signalling response fixes
  2026-11-09 15:53   ` [PATCH 5.15.y v2 0/3] Bluetooth: L2CAP: signalling response fixes Sasha Levin
@ 2026-11-10 15:08     ` Siwei Zhang
  2026-11-10 19:13     ` Siwei Zhang
  1 sibling, 0 replies; 24+ messages in thread
From: Siwei Zhang @ 2026-11-10 15:08 UTC (permalink / raw)
  To: Sasha Levin, stable; +Cc: Luiz Augusto von Dentz, linux-bluetooth



On Mon, Nov 9, 2026, at 10:53 AM, Sasha Levin wrote:
>> Bluetooth: L2CAP: signalling response fixes
>
> Thanks for the v2. The 5.15 and 5.10 series add AMP/A2MP hunks that are not in
> 6320736af7dc ("Bluetooth: L2CAP: Reject signalling responses in invalid
> states"), a518b9a9ef6e ("Bluetooth: L2CAP: Only accept connection responses to
> outstanding requests") or a9f9eeb5344f ("Bluetooth: L2CAP: Ignore connection
> responses with wrong ident").
>
> Luiz, could you ack those AMP extras? I will queue both series once there is an
> ack.

CC linux-bluetooth for better visibility.

Original thread link:
https://lore.kernel.org/stable/2026-11-09-1-daily-reply-0038-bt-l2cap-v2@kernel.org/

Patches for 5.15:
https://lore.kernel.org/stable/20261109015902.3034747-1-oss@fourdim.xyz/

Patches for 5.10:
https://lore.kernel.org/stable/20261109020039.3035406-1-oss@fourdim.xyz/

>
> -- 
> Thanks,
> Sasha

Best,
Siwei

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 5.15.y v3 0/3] Bluetooth: L2CAP: signalling response fixes
  2026-11-07 11:06 FAILED: patch "[PATCH] Bluetooth: L2CAP: Reject signalling responses in invalid states" failed to apply to 5.15-stable tree Sasha Levin
  2026-11-08  0:05 ` [PATCH 5.15.y 0/3] Bluetooth: L2CAP: signalling response fixes Siwei Zhang
  2026-11-09  1:58 ` [PATCH 5.15.y v2 0/3] Bluetooth: L2CAP: signalling response fixes Siwei Zhang
@ 2026-11-10 19:10 ` Siwei Zhang
  2026-11-10 19:10   ` [PATCH 5.15.y v3 1/3] Bluetooth: L2CAP: Reject signalling responses in invalid states Siwei Zhang
                     ` (2 more replies)
  2026-11-11 22:07 ` [PATCH 5.15.y v4 0/3] Bluetooth: L2CAP: signalling response fixes Siwei Zhang
  3 siblings, 3 replies; 24+ messages in thread
From: Siwei Zhang @ 2026-11-10 19:10 UTC (permalink / raw)
  To: stable; +Cc: Luiz Augusto von Dentz

Backports of

  6320736af7dc ("Bluetooth: L2CAP: Reject signalling responses in invalid states")
  a518b9a9ef6e ("Bluetooth: L2CAP: Only accept connection responses to outstanding requests")

which failed to apply to the 5.15-stable tree:

  https://lore.kernel.org/stable/20261107060628-failed-5.15-6320736af7dc@kernel.org/
  https://lore.kernel.org/stable/20261107060634-failed-5.15-a518b9a9ef6e@kernel.org/

Patch 3 is a9f9eeb5344f ("Bluetooth: L2CAP: Ignore connection responses
with wrong ident"), which tightens the check added by patch 2 and only
applies on top of it.

The series goes on top of the three L2CAP patches already queued for
5.15.y:

  c1398cf11b31 ("Bluetooth: L2CAP: Reject mode changes on connected channels")
  c5ebb0245fe9 ("Bluetooth: L2CAP: Reject invalid TxWindow in configuration requests")
  226fa3b676cb ("Bluetooth: L2CAP: Use default TxWindow for zero socket option")

5.15.y still has AMP and A2MP, which upstream removed in e7b02296fb40
("Bluetooth: Remove BT_HS"). This version leaves that code alone, so
the patches only carry the upstream changes, with context adjusted as
described at the top of each commit message. The changes are the same
as in the 6.1.y and 6.6.y backports.

One side effect on AMP: the response to an L2CAP Create Channel
Request also goes through l2cap_connect_create_rsp(), but
l2cap_send_create_chan_req() does not set CONF_CONNECT_PEND. Patch 2
therefore ignores that response, and an outgoing channel can no longer
be set up over an AMP controller.

Changes in v3:
- Drop the AMP and A2MP changes from all three patches. They are not
  upstream and did not get the maintainer ack asked for in the v2
  review.
  https://lore.kernel.org/stable/2026-11-09-1-daily-reply-0038-bt-l2cap-v2@kernel.org/

Changes in v2:
- Patch 2: a2mp_discover_rsp() now pulls the payload of an unsolicited
  Discover Response before returning, so a2mp_chan_recv_cb() does not
  parse it as the next A2MP command header. Dropped again in v3 with
  the other AMP changes.
  https://lore.kernel.org/stable/2026-11-08-1-daily-reply-0003-l2cap-a2mp-5-15@kernel.org/

v2: https://lore.kernel.org/stable/20261109015902.3034747-1-oss@fourdim.xyz/
v1: https://lore.kernel.org/stable/20261108000542.1969015-1-oss@fourdim.xyz/

Jinwang Li (1):
  Bluetooth: L2CAP: Ignore connection responses with wrong ident

Siwei Zhang (2):
  Bluetooth: L2CAP: Reject signalling responses in invalid states
  Bluetooth: L2CAP: Only accept connection responses to outstanding
    requests

 net/bluetooth/l2cap_core.c | 47 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 45 insertions(+), 2 deletions(-)

-- 
2.56.0


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 5.15.y v3 1/3] Bluetooth: L2CAP: Reject signalling responses in invalid states
  2026-11-10 19:10 ` [PATCH 5.15.y v3 " Siwei Zhang
@ 2026-11-10 19:10   ` Siwei Zhang
  2026-11-10 19:10   ` [PATCH 5.15.y v3 2/3] Bluetooth: L2CAP: Only accept connection responses to outstanding requests Siwei Zhang
  2026-11-10 19:10   ` [PATCH 5.15.y v3 3/3] Bluetooth: L2CAP: Ignore connection responses with wrong ident Siwei Zhang
  2 siblings, 0 replies; 24+ messages in thread
From: Siwei Zhang @ 2026-11-10 19:10 UTC (permalink / raw)
  To: stable; +Cc: Luiz Augusto von Dentz

commit 6320736af7dcb90da6ee9fd651ecc11c564d45b7 upstream.

Adjusted context as stable does not have the lockdep_assert_held()
calls, and l2cap_get_chan_by_scid() still returns the channel locked,
so l2cap_config_rsp() does not lock it again.

A peer can send configuration messages while an
incoming channel is in BT_CONNECT2, before the
security or deferred accept gate has completed. A
configuration response can then promote the channel
to BT_CONNECTED. Configuration responses can also
act on channels that are closing, and a late connection
response can move a disconnecting channel back to
BT_CONFIG.

Accept connection responses only while waiting in
BT_CONNECT. Answer configuration requests in
BT_CONNECT2, but defer our own request until
BT_CONFIG so configuration cannot complete before
the gate. Ignore configuration responses outside
BT_CONFIG and BT_CONNECTED, and only complete
configuration in BT_CONFIG.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
v3: Drop the AMP changes to l2cap_logical_finish_create() and
    l2cap_do_create(), which are not in 6320736af7dc.
    https://lore.kernel.org/stable/2026-11-09-1-daily-reply-0038-bt-l2cap-v2@kernel.org/

 net/bluetooth/l2cap_core.c | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index cc49e651907d..9a883e476684 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -4443,6 +4443,10 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
 
 	l2cap_chan_lock(chan);
 
+	/* Ignore a late response after the channel has left BT_CONNECT. */
+	if (chan->state != BT_CONNECT)
+		goto done;
+
 	switch (result) {
 	case L2CAP_CR_SUCCESS:
 		if (__l2cap_get_chan_by_dcid(conn, dcid)) {
@@ -4472,6 +4476,7 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
 		break;
 	}
 
+done:
 	l2cap_chan_unlock(chan);
 	l2cap_chan_put(chan);
 
@@ -4607,7 +4612,13 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
 		goto unlock;
 	}
 
-	if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
+	/* A channel in BT_CONNECT2 has not passed security or userspace
+	 * accept yet. Answer the peer's request, but hold our own until
+	 * the channel reaches BT_CONFIG: the CONNECT2 -> CONFIG sites send
+	 * it. Connected channels may also need to reconfigure.
+	 */
+	if ((chan->state == BT_CONFIG || chan->state == BT_CONNECTED) &&
+	    !test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
 		u8 buf[64];
 		l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
 			       l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
@@ -4658,6 +4669,10 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
 	if (!chan)
 		return 0;
 
+	/* Connected channels may also receive reconfiguration responses. */
+	if (chan->state != BT_CONFIG && chan->state != BT_CONNECTED)
+		goto done;
+
 	switch (result) {
 	case L2CAP_CONF_SUCCESS:
 		l2cap_conf_rfc_get(chan, rsp->data, len);
@@ -4733,6 +4748,9 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
 	if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
 		set_default_fcs(chan);
 
+		if (chan->state != BT_CONFIG)
+			goto done;
+
 		if (chan->mode == L2CAP_MODE_ERTM ||
 		    chan->mode == L2CAP_MODE_STREAMING)
 			err = l2cap_ertm_init(chan);
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 5.15.y v3 2/3] Bluetooth: L2CAP: Only accept connection responses to outstanding requests
  2026-11-10 19:10 ` [PATCH 5.15.y v3 " Siwei Zhang
  2026-11-10 19:10   ` [PATCH 5.15.y v3 1/3] Bluetooth: L2CAP: Reject signalling responses in invalid states Siwei Zhang
@ 2026-11-10 19:10   ` Siwei Zhang
  2026-11-11 21:54     ` Sasha Levin
  2026-11-10 19:10   ` [PATCH 5.15.y v3 3/3] Bluetooth: L2CAP: Ignore connection responses with wrong ident Siwei Zhang
  2 siblings, 1 reply; 24+ messages in thread
From: Siwei Zhang @ 2026-11-10 19:10 UTC (permalink / raw)
  To: stable; +Cc: Luiz Augusto von Dentz

commit a518b9a9ef6ee3b18ecdf6ba5360c608aaf969e9 upstream.

Adjusted context as stable does not have the lockdep_assert_held()
call and the __must_hold() context analysis annotations, and
l2cap_connect_create_rsp() still holds conn->chan_lock and returns
through the unlock label when the channel lookup fails.

An outgoing channel waits in BT_CONNECT until security
and the feature mask exchange complete, and only then
sends its connection request. A peer can answer it
before that with a connection response matching our
source CID. The channel then moves to BT_CONFIG,
completes configuration and becomes connected before
security has completed. If security then fails,
l2cap_security_cfm() leaves the connected channel
alone, so it stays up on a link that did not reach
the required security level.

A connection response with a zero source CID is
matched by identifier. Another channel can hold the
same identifier for a response it still has to send,
so the lookup can pick the wrong channel.

Only accept a connection response while our request
is outstanding, and only look at such channels when
matching by identifier.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
v3: Drop the AMP and A2MP changes, which are not in a518b9a9ef6e.
    https://lore.kernel.org/stable/2026-11-09-1-daily-reply-0038-bt-l2cap-v2@kernel.org/
v2: Pull the payload of an unsolicited A2MP Discover Response before
    returning from a2mp_discover_rsp().
    https://lore.kernel.org/stable/2026-11-08-1-daily-reply-0003-l2cap-a2mp-5-15@kernel.org/

 net/bluetooth/l2cap_core.c | 31 ++++++++++++++++++++++++++++---
 1 file changed, 28 insertions(+), 3 deletions(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 9a883e476684..fd6c39c5c81a 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -185,6 +185,28 @@ static struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn,
 	return c;
 }
 
+/* Our connection request has been sent and is still outstanding */
+static bool l2cap_chan_connect_pending(struct l2cap_chan *chan)
+{
+	return chan->state == BT_CONNECT &&
+	       test_bit(CONF_CONNECT_PEND, &chan->conf_state);
+}
+
+/* Other channels may hold the same ident for a response they still have
+ * to send, so only look at channels waiting for a connection response.
+ */
+static struct l2cap_chan *__l2cap_get_connect_chan_by_ident(struct l2cap_conn *conn,
+							    u8 ident)
+{
+	struct l2cap_chan *c;
+
+	list_for_each_entry(c, &conn->chan_l, list) {
+		if (c->ident == ident && l2cap_chan_connect_pending(c))
+			return c;
+	}
+	return NULL;
+}
+
 static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src,
 						      u8 src_type)
 {
@@ -4426,7 +4448,7 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
 			goto unlock;
 		}
 	} else {
-		chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
+		chan = __l2cap_get_connect_chan_by_ident(conn, cmd->ident);
 		if (!chan) {
 			err = -EBADSLT;
 			goto unlock;
@@ -4443,8 +4465,11 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
 
 	l2cap_chan_lock(chan);
 
-	/* Ignore a late response after the channel has left BT_CONNECT. */
-	if (chan->state != BT_CONNECT)
+	/* Only accept a response to a connection request we sent and that
+	 * is still outstanding. A channel waiting in BT_CONNECT for security
+	 * or the feature mask has not sent one yet.
+	 */
+	if (!l2cap_chan_connect_pending(chan))
 		goto done;
 
 	switch (result) {
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 5.15.y v3 3/3] Bluetooth: L2CAP: Ignore connection responses with wrong ident
  2026-11-10 19:10 ` [PATCH 5.15.y v3 " Siwei Zhang
  2026-11-10 19:10   ` [PATCH 5.15.y v3 1/3] Bluetooth: L2CAP: Reject signalling responses in invalid states Siwei Zhang
  2026-11-10 19:10   ` [PATCH 5.15.y v3 2/3] Bluetooth: L2CAP: Only accept connection responses to outstanding requests Siwei Zhang
@ 2026-11-10 19:10   ` Siwei Zhang
  2 siblings, 0 replies; 24+ messages in thread
From: Siwei Zhang @ 2026-11-10 19:10 UTC (permalink / raw)
  To: stable; +Cc: Luiz Augusto von Dentz, Jinwang Li

From: Jinwang Li <jinwang.li@oss.qualcomm.com>

commit a9f9eeb5344fc7dc625e5700ccf09891bc2603b5 upstream.

Adjusted context as stable does not have the lockdep_assert_held()
call in l2cap_connect_create_rsp().

L2CAP/COS/CED/BI-28-C requires the IUT to ignore a Connection Response
that carries an invalid Identifier.

l2cap_connect_create_rsp() only checks that a connection request is
outstanding, not that the response answers it. Add an ident check
against the pending request so that a mismatched response is dropped.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Jinwang Li <jinwang.li@oss.qualcomm.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
---
v3: Drop the AMP change to l2cap_move_channel_req(), which is not in
    a9f9eeb5344f.
    https://lore.kernel.org/stable/2026-11-09-1-daily-reply-0038-bt-l2cap-v2@kernel.org/

 net/bluetooth/l2cap_core.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index fd6c39c5c81a..fcca325c004d 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -4465,11 +4465,11 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
 
 	l2cap_chan_lock(chan);
 
-	/* Only accept a response to a connection request we sent and that
-	 * is still outstanding. A channel waiting in BT_CONNECT for security
-	 * or the feature mask has not sent one yet.
+	/* Only accept a response matching a connection request we sent and
+	 * that is still outstanding. A channel waiting in BT_CONNECT for
+	 * security or the feature mask has not sent one yet.
 	 */
-	if (!l2cap_chan_connect_pending(chan))
+	if (!l2cap_chan_connect_pending(chan) || chan->ident != cmd->ident)
 		goto done;
 
 	switch (result) {
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [PATCH 5.15.y v2 0/3] Bluetooth: L2CAP: signalling response fixes
  2026-11-09 15:53   ` [PATCH 5.15.y v2 0/3] Bluetooth: L2CAP: signalling response fixes Sasha Levin
  2026-11-10 15:08     ` Siwei Zhang
@ 2026-11-10 19:13     ` Siwei Zhang
  1 sibling, 0 replies; 24+ messages in thread
From: Siwei Zhang @ 2026-11-10 19:13 UTC (permalink / raw)
  To: Sasha Levin, stable; +Cc: Luiz Augusto von Dentz



On Mon, Nov 9, 2026, at 10:53 AM, Sasha Levin wrote:
>> Bluetooth: L2CAP: signalling response fixes
>
> Thanks for the v2. The 5.15 and 5.10 series add AMP/A2MP hunks that are not in
> 6320736af7dc ("Bluetooth: L2CAP: Reject signalling responses in invalid
> states"), a518b9a9ef6e ("Bluetooth: L2CAP: Only accept connection responses to
> outstanding requests") or a9f9eeb5344f ("Bluetooth: L2CAP: Ignore connection
> responses with wrong ident").
>
> Luiz, could you ack those AMP extras? I will queue both series once there is an
> ack.
>

Hi Sasha,

I would like to drop these AMP extra fixes to make the changes consistent.
Patch v3 sent.

> -- 
> Thanks,
> Sasha

Best,
Siwei

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 5.15.y v3 2/3] Bluetooth: L2CAP: Only accept connection responses to outstanding requests
  2026-11-10 19:10   ` [PATCH 5.15.y v3 2/3] Bluetooth: L2CAP: Only accept connection responses to outstanding requests Siwei Zhang
@ 2026-11-11 21:54     ` Sasha Levin
  0 siblings, 0 replies; 24+ messages in thread
From: Sasha Levin @ 2026-11-11 21:54 UTC (permalink / raw)
  To: stable; +Cc: Sasha Levin, Luiz Augusto von Dentz, Siwei Zhang

> [PATCH 5.15.y v3 2/3] Bluetooth: L2CAP: Only accept connection responses to outstanding requests
This breaks outgoing AMP channel setup on 5.15. AMP is still present here and
l2cap_send_create_chan_req() never sets CONF_CONNECT_PEND, so the new
l2cap_chan_connect_pending() check drops the Create Channel Response and the
channel hangs in BT_CONNECT. The check comes from a518b9a9ef6e ("Bluetooth:
L2CAP: Only accept connection responses to outstanding requests").

Could you add set_bit(CONF_CONNECT_PEND, &chan->conf_state) in
l2cap_send_create_chan_req() and send a v4? Patches 1/3 and 3/3 look fine.

-- 
Thanks,
Sasha

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 5.15.y v4 0/3] Bluetooth: L2CAP: signalling response fixes
  2026-11-07 11:06 FAILED: patch "[PATCH] Bluetooth: L2CAP: Reject signalling responses in invalid states" failed to apply to 5.15-stable tree Sasha Levin
                   ` (2 preceding siblings ...)
  2026-11-10 19:10 ` [PATCH 5.15.y v3 " Siwei Zhang
@ 2026-11-11 22:07 ` Siwei Zhang
  2026-11-11 22:07   ` [PATCH 5.15.y v4 1/3] Bluetooth: L2CAP: Reject signalling responses in invalid states Siwei Zhang
                     ` (3 more replies)
  3 siblings, 4 replies; 24+ messages in thread
From: Siwei Zhang @ 2026-11-11 22:07 UTC (permalink / raw)
  To: stable; +Cc: Luiz Augusto von Dentz

Backports of

  6320736af7dc ("Bluetooth: L2CAP: Reject signalling responses in invalid states")
  a518b9a9ef6e ("Bluetooth: L2CAP: Only accept connection responses to outstanding requests")

which failed to apply to the 5.15-stable tree:

  https://lore.kernel.org/stable/20261107060628-failed-5.15-6320736af7dc@kernel.org/
  https://lore.kernel.org/stable/20261107060634-failed-5.15-a518b9a9ef6e@kernel.org/

Patch 3 is a9f9eeb5344f ("Bluetooth: L2CAP: Ignore connection responses
with wrong ident"), which tightens the check added by patch 2 and only
applies on top of it.

The series goes on top of the three L2CAP patches already queued for
5.15.y:

  c1398cf11b31 ("Bluetooth: L2CAP: Reject mode changes on connected channels")
  c5ebb0245fe9 ("Bluetooth: L2CAP: Reject invalid TxWindow in configuration requests")
  226fa3b676cb ("Bluetooth: L2CAP: Use default TxWindow for zero socket option")

5.15.y still has AMP and A2MP, which upstream removed in e7b02296fb40
("Bluetooth: Remove BT_HS"). Patch 2 sets CONF_CONNECT_PEND in
l2cap_send_create_chan_req(), so the response to an AMP Create Channel
Request still passes the new check. Apart from that line, the patches
only carry the upstream changes, with context adjusted as described at
the top of each commit message.

Changes in v4:
- Patch 2: set CONF_CONNECT_PEND in l2cap_send_create_chan_req(), so
  the Create Channel Response is no longer dropped and an outgoing AMP
  channel does not hang in BT_CONNECT.
  https://lore.kernel.org/stable/2026-11-11-1-daily-reply-0023-a0d5fd86605d193ae993@kernel.org/

Changes in v3:
- Drop the AMP and A2MP changes from all three patches. They are not
  upstream and did not get the maintainer ack asked for in the v2
  review.
  https://lore.kernel.org/stable/2026-11-09-1-daily-reply-0038-bt-l2cap-v2@kernel.org/

Changes in v2:
- Patch 2: a2mp_discover_rsp() now pulls the payload of an unsolicited
  Discover Response before returning, so a2mp_chan_recv_cb() does not
  parse it as the next A2MP command header. Dropped again in v3 with
  the other AMP changes.
  https://lore.kernel.org/stable/2026-11-08-1-daily-reply-0003-l2cap-a2mp-5-15@kernel.org/

v3: https://lore.kernel.org/stable/20261110191058.1747963-1-oss@fourdim.xyz/
v2: https://lore.kernel.org/stable/20261109015902.3034747-1-oss@fourdim.xyz/
v1: https://lore.kernel.org/stable/20261108000542.1969015-1-oss@fourdim.xyz/

Jinwang Li (1):
  Bluetooth: L2CAP: Ignore connection responses with wrong ident

Siwei Zhang (2):
  Bluetooth: L2CAP: Reject signalling responses in invalid states
  Bluetooth: L2CAP: Only accept connection responses to outstanding
    requests

 net/bluetooth/l2cap_core.c | 49 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 47 insertions(+), 2 deletions(-)

-- 
2.56.0


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 5.15.y v4 1/3] Bluetooth: L2CAP: Reject signalling responses in invalid states
  2026-11-11 22:07 ` [PATCH 5.15.y v4 0/3] Bluetooth: L2CAP: signalling response fixes Siwei Zhang
@ 2026-11-11 22:07   ` Siwei Zhang
  2026-11-11 22:07   ` [PATCH 5.15.y v4 2/3] Bluetooth: L2CAP: Only accept connection responses to outstanding requests Siwei Zhang
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 24+ messages in thread
From: Siwei Zhang @ 2026-11-11 22:07 UTC (permalink / raw)
  To: stable; +Cc: Luiz Augusto von Dentz

commit 6320736af7dcb90da6ee9fd651ecc11c564d45b7 upstream.

Adjusted context as stable does not have the lockdep_assert_held()
calls, and l2cap_get_chan_by_scid() still returns the channel locked,
so l2cap_config_rsp() does not lock it again.

A peer can send configuration messages while an
incoming channel is in BT_CONNECT2, before the
security or deferred accept gate has completed. A
configuration response can then promote the channel
to BT_CONNECTED. Configuration responses can also
act on channels that are closing, and a late connection
response can move a disconnecting channel back to
BT_CONFIG.

Accept connection responses only while waiting in
BT_CONNECT. Answer configuration requests in
BT_CONNECT2, but defer our own request until
BT_CONFIG so configuration cannot complete before
the gate. Ignore configuration responses outside
BT_CONFIG and BT_CONNECTED, and only complete
configuration in BT_CONFIG.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
v4: No change.
v3: Drop the AMP changes to l2cap_logical_finish_create() and
    l2cap_do_create(), which are not in 6320736af7dc.
    https://lore.kernel.org/stable/2026-11-09-1-daily-reply-0038-bt-l2cap-v2@kernel.org/

 net/bluetooth/l2cap_core.c | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index cc49e651907d..9a883e476684 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -4443,6 +4443,10 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
 
 	l2cap_chan_lock(chan);
 
+	/* Ignore a late response after the channel has left BT_CONNECT. */
+	if (chan->state != BT_CONNECT)
+		goto done;
+
 	switch (result) {
 	case L2CAP_CR_SUCCESS:
 		if (__l2cap_get_chan_by_dcid(conn, dcid)) {
@@ -4472,6 +4476,7 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
 		break;
 	}
 
+done:
 	l2cap_chan_unlock(chan);
 	l2cap_chan_put(chan);
 
@@ -4607,7 +4612,13 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
 		goto unlock;
 	}
 
-	if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
+	/* A channel in BT_CONNECT2 has not passed security or userspace
+	 * accept yet. Answer the peer's request, but hold our own until
+	 * the channel reaches BT_CONFIG: the CONNECT2 -> CONFIG sites send
+	 * it. Connected channels may also need to reconfigure.
+	 */
+	if ((chan->state == BT_CONFIG || chan->state == BT_CONNECTED) &&
+	    !test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
 		u8 buf[64];
 		l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
 			       l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
@@ -4658,6 +4669,10 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
 	if (!chan)
 		return 0;
 
+	/* Connected channels may also receive reconfiguration responses. */
+	if (chan->state != BT_CONFIG && chan->state != BT_CONNECTED)
+		goto done;
+
 	switch (result) {
 	case L2CAP_CONF_SUCCESS:
 		l2cap_conf_rfc_get(chan, rsp->data, len);
@@ -4733,6 +4748,9 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
 	if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
 		set_default_fcs(chan);
 
+		if (chan->state != BT_CONFIG)
+			goto done;
+
 		if (chan->mode == L2CAP_MODE_ERTM ||
 		    chan->mode == L2CAP_MODE_STREAMING)
 			err = l2cap_ertm_init(chan);
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 5.15.y v4 2/3] Bluetooth: L2CAP: Only accept connection responses to outstanding requests
  2026-11-11 22:07 ` [PATCH 5.15.y v4 0/3] Bluetooth: L2CAP: signalling response fixes Siwei Zhang
  2026-11-11 22:07   ` [PATCH 5.15.y v4 1/3] Bluetooth: L2CAP: Reject signalling responses in invalid states Siwei Zhang
@ 2026-11-11 22:07   ` Siwei Zhang
  2026-11-11 22:07   ` [PATCH 5.15.y v4 3/3] Bluetooth: L2CAP: Ignore connection responses with wrong ident Siwei Zhang
  2026-11-13  2:33   ` [PATCH 5.15.y v4 0/3] Bluetooth: L2CAP: signalling response fixes Sasha Levin
  3 siblings, 0 replies; 24+ messages in thread
From: Siwei Zhang @ 2026-11-11 22:07 UTC (permalink / raw)
  To: stable; +Cc: Luiz Augusto von Dentz

commit a518b9a9ef6ee3b18ecdf6ba5360c608aaf969e9 upstream.

Adjusted context as stable does not have the lockdep_assert_held()
call and the __must_hold() context analysis annotations, and
l2cap_connect_create_rsp() still holds conn->chan_lock and returns
through the unlock label when the channel lookup fails.

Stable still has AMP support, which upstream removed in
commit e7b02296fb40 ("Bluetooth: Remove BT_HS"). The response to an
L2CAP_CREATE_CHAN_REQ is also handled by l2cap_connect_create_rsp(),
so set CONF_CONNECT_PEND in l2cap_send_create_chan_req() as
l2cap_send_conn_req() does. Otherwise that response is dropped and an
outgoing AMP channel hangs in BT_CONNECT. This also makes
__l2cap_no_conn_pending() see the request as outstanding, so
l2cap_do_start(), l2cap_conn_start() and l2cap_security_cfm() leave
the channel alone until it is answered, as they already do for a
pending connection request.

An outgoing channel waits in BT_CONNECT until security
and the feature mask exchange complete, and only then
sends its connection request. A peer can answer it
before that with a connection response matching our
source CID. The channel then moves to BT_CONFIG,
completes configuration and becomes connected before
security has completed. If security then fails,
l2cap_security_cfm() leaves the connected channel
alone, so it stays up on a link that did not reach
the required security level.

A connection response with a zero source CID is
matched by identifier. Another channel can hold the
same identifier for a response it still has to send,
so the lookup can pick the wrong channel.

Only accept a connection response while our request
is outstanding, and only look at such channels when
matching by identifier.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
v4: Set CONF_CONNECT_PEND in l2cap_send_create_chan_req(), so the
    response to an AMP Create Channel Request is not dropped.
    https://lore.kernel.org/stable/2026-11-11-1-daily-reply-0023-a0d5fd86605d193ae993@kernel.org/
v3: Drop the AMP and A2MP changes, which are not in a518b9a9ef6e.
    https://lore.kernel.org/stable/2026-11-09-1-daily-reply-0038-bt-l2cap-v2@kernel.org/
v2: Pull the payload of an unsolicited A2MP Discover Response before
    returning from a2mp_discover_rsp().
    https://lore.kernel.org/stable/2026-11-08-1-daily-reply-0003-l2cap-a2mp-5-15@kernel.org/

 net/bluetooth/l2cap_core.c | 33 ++++++++++++++++++++++++++++++---
 1 file changed, 30 insertions(+), 3 deletions(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 9a883e476684..75c2ab39be16 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -185,6 +185,28 @@ static struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn,
 	return c;
 }
 
+/* Our connection request has been sent and is still outstanding */
+static bool l2cap_chan_connect_pending(struct l2cap_chan *chan)
+{
+	return chan->state == BT_CONNECT &&
+	       test_bit(CONF_CONNECT_PEND, &chan->conf_state);
+}
+
+/* Other channels may hold the same ident for a response they still have
+ * to send, so only look at channels waiting for a connection response.
+ */
+static struct l2cap_chan *__l2cap_get_connect_chan_by_ident(struct l2cap_conn *conn,
+							    u8 ident)
+{
+	struct l2cap_chan *c;
+
+	list_for_each_entry(c, &conn->chan_l, list) {
+		if (c->ident == ident && l2cap_chan_connect_pending(c))
+			return c;
+	}
+	return NULL;
+}
+
 static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src,
 						      u8 src_type)
 {
@@ -1329,6 +1351,8 @@ static void l2cap_send_create_chan_req(struct l2cap_chan *chan, u8 amp_id)
 
 	chan->ident = l2cap_get_ident(chan->conn);
 
+	set_bit(CONF_CONNECT_PEND, &chan->conf_state);
+
 	l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CREATE_CHAN_REQ,
 		       sizeof(req), &req);
 }
@@ -4426,7 +4450,7 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
 			goto unlock;
 		}
 	} else {
-		chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
+		chan = __l2cap_get_connect_chan_by_ident(conn, cmd->ident);
 		if (!chan) {
 			err = -EBADSLT;
 			goto unlock;
@@ -4443,8 +4467,11 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
 
 	l2cap_chan_lock(chan);
 
-	/* Ignore a late response after the channel has left BT_CONNECT. */
-	if (chan->state != BT_CONNECT)
+	/* Only accept a response to a connection request we sent and that
+	 * is still outstanding. A channel waiting in BT_CONNECT for security
+	 * or the feature mask has not sent one yet.
+	 */
+	if (!l2cap_chan_connect_pending(chan))
 		goto done;
 
 	switch (result) {
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 5.15.y v4 3/3] Bluetooth: L2CAP: Ignore connection responses with wrong ident
  2026-11-11 22:07 ` [PATCH 5.15.y v4 0/3] Bluetooth: L2CAP: signalling response fixes Siwei Zhang
  2026-11-11 22:07   ` [PATCH 5.15.y v4 1/3] Bluetooth: L2CAP: Reject signalling responses in invalid states Siwei Zhang
  2026-11-11 22:07   ` [PATCH 5.15.y v4 2/3] Bluetooth: L2CAP: Only accept connection responses to outstanding requests Siwei Zhang
@ 2026-11-11 22:07   ` Siwei Zhang
  2026-11-13  2:33   ` [PATCH 5.15.y v4 0/3] Bluetooth: L2CAP: signalling response fixes Sasha Levin
  3 siblings, 0 replies; 24+ messages in thread
From: Siwei Zhang @ 2026-11-11 22:07 UTC (permalink / raw)
  To: stable; +Cc: Luiz Augusto von Dentz, Jinwang Li

From: Jinwang Li <jinwang.li@oss.qualcomm.com>

commit a9f9eeb5344fc7dc625e5700ccf09891bc2603b5 upstream.

Adjusted context as stable does not have the lockdep_assert_held()
call in l2cap_connect_create_rsp().

L2CAP/COS/CED/BI-28-C requires the IUT to ignore a Connection Response
that carries an invalid Identifier.

l2cap_connect_create_rsp() only checks that a connection request is
outstanding, not that the response answers it. Add an ident check
against the pending request so that a mismatched response is dropped.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Jinwang Li <jinwang.li@oss.qualcomm.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
---
v4: No change.
v3: Drop the AMP change to l2cap_move_channel_req(), which is not in
    a9f9eeb5344f.
    https://lore.kernel.org/stable/2026-11-09-1-daily-reply-0038-bt-l2cap-v2@kernel.org/

 net/bluetooth/l2cap_core.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 75c2ab39be16..a25a13408786 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -4467,11 +4467,11 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
 
 	l2cap_chan_lock(chan);
 
-	/* Only accept a response to a connection request we sent and that
-	 * is still outstanding. A channel waiting in BT_CONNECT for security
-	 * or the feature mask has not sent one yet.
+	/* Only accept a response matching a connection request we sent and
+	 * that is still outstanding. A channel waiting in BT_CONNECT for
+	 * security or the feature mask has not sent one yet.
 	 */
-	if (!l2cap_chan_connect_pending(chan))
+	if (!l2cap_chan_connect_pending(chan) || chan->ident != cmd->ident)
 		goto done;
 
 	switch (result) {
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [PATCH 5.15.y v4 0/3] Bluetooth: L2CAP: signalling response fixes
  2026-11-11 22:07 ` [PATCH 5.15.y v4 0/3] Bluetooth: L2CAP: signalling response fixes Siwei Zhang
                     ` (2 preceding siblings ...)
  2026-11-11 22:07   ` [PATCH 5.15.y v4 3/3] Bluetooth: L2CAP: Ignore connection responses with wrong ident Siwei Zhang
@ 2026-11-13  2:33   ` Sasha Levin
  3 siblings, 0 replies; 24+ messages in thread
From: Sasha Levin @ 2026-11-13  2:33 UTC (permalink / raw)
  To: stable; +Cc: Sasha Levin, Luiz Augusto von Dentz, Siwei Zhang

On 2026-11-11, Siwei Zhang wrote:
> [PATCH 5.15.y v4 0/3] Bluetooth: L2CAP: signalling response fixes
> Backports of
>   6320736af7dc ("Bluetooth: L2CAP: Reject signalling responses in invalid states")
>   a518b9a9ef6e ("Bluetooth: L2CAP: Only accept connection responses to outstanding requests")

Queued the series for 5.15 and 5.10, thanks.


-- 
Thanks,
Sasha

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2026-11-13  2:33 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-07 11:06 FAILED: patch "[PATCH] Bluetooth: L2CAP: Reject signalling responses in invalid states" failed to apply to 5.15-stable tree Sasha Levin
2026-11-08  0:05 ` [PATCH 5.15.y 0/3] Bluetooth: L2CAP: signalling response fixes Siwei Zhang
2026-11-08  0:05   ` [PATCH 5.15.y 1/3] Bluetooth: L2CAP: Reject signalling responses in invalid states Siwei Zhang
2026-11-08  0:05   ` [PATCH 5.15.y 2/3] Bluetooth: L2CAP: Only accept connection responses to outstanding requests Siwei Zhang
2026-11-09  0:34     ` Sasha Levin
2026-11-09  2:03       ` Siwei Zhang
2026-11-08  0:05   ` [PATCH 5.15.y 3/3] Bluetooth: L2CAP: Ignore connection responses with wrong ident Siwei Zhang
2026-11-09  1:58 ` [PATCH 5.15.y v2 0/3] Bluetooth: L2CAP: signalling response fixes Siwei Zhang
2026-11-09  1:58   ` [PATCH 5.15.y v2 1/3] Bluetooth: L2CAP: Reject signalling responses in invalid states Siwei Zhang
2026-11-09  1:58   ` [PATCH 5.15.y v2 2/3] Bluetooth: L2CAP: Only accept connection responses to outstanding requests Siwei Zhang
2026-11-09  1:58   ` [PATCH 5.15.y v2 3/3] Bluetooth: L2CAP: Ignore connection responses with wrong ident Siwei Zhang
2026-11-09 15:53   ` [PATCH 5.15.y v2 0/3] Bluetooth: L2CAP: signalling response fixes Sasha Levin
2026-11-10 15:08     ` Siwei Zhang
2026-11-10 19:13     ` Siwei Zhang
2026-11-10 19:10 ` [PATCH 5.15.y v3 " Siwei Zhang
2026-11-10 19:10   ` [PATCH 5.15.y v3 1/3] Bluetooth: L2CAP: Reject signalling responses in invalid states Siwei Zhang
2026-11-10 19:10   ` [PATCH 5.15.y v3 2/3] Bluetooth: L2CAP: Only accept connection responses to outstanding requests Siwei Zhang
2026-11-11 21:54     ` Sasha Levin
2026-11-10 19:10   ` [PATCH 5.15.y v3 3/3] Bluetooth: L2CAP: Ignore connection responses with wrong ident Siwei Zhang
2026-11-11 22:07 ` [PATCH 5.15.y v4 0/3] Bluetooth: L2CAP: signalling response fixes Siwei Zhang
2026-11-11 22:07   ` [PATCH 5.15.y v4 1/3] Bluetooth: L2CAP: Reject signalling responses in invalid states Siwei Zhang
2026-11-11 22:07   ` [PATCH 5.15.y v4 2/3] Bluetooth: L2CAP: Only accept connection responses to outstanding requests Siwei Zhang
2026-11-11 22:07   ` [PATCH 5.15.y v4 3/3] Bluetooth: L2CAP: Ignore connection responses with wrong ident Siwei Zhang
2026-11-13  2:33   ` [PATCH 5.15.y v4 0/3] Bluetooth: L2CAP: signalling response fixes Sasha Levin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox