Skip to contentSkip to conversation

Bluetooth: L2CAP: Fix stack buffer overflow in deferred ECRED connection response

PATCH In review Lukas Johannes Möller 2 participants 2 messages Mar 10 1 message not in the archive

Subsystems (2)
lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

#1 lore raw

PATCH 1/1 Bluetooth: L2CAP: Fix stack buffer overflow in deferred ECRED connection response

l2cap_ecred_rsp_defer() appends channel SCIDs to rsp_flex->dcid[rsp->count++] without checking rsp->count against L2CAP_ECRED_MAX_CID. The dcid[] flexible array member is backed by a stack-allocated structure with room for only L2CAP_ECRED_MAX_CID (5) entries.

Per-request validation in l2cap_ecred_conn_req() limits a single L2CAP_ECRED_CONN_REQ to at most 5 SCIDs, but multiple requests can reuse the same attacker-controlled signaling identifier. When __l2cap_ecred_conn_rsp_defer() later walks all channels with that ident, the callback writes past the fixed backing array. For LE links (SCIDs 0x0040..0x007f) the maximum overwrite is 118 bytes past the end of the buffer.

Add a bounds check in l2cap_ecred_rsp_defer() that cleans up excess channels, and reject incoming requests in l2cap_ecred_conn_req() when channels are already pending for the same ident.

Fixes da49b602f7f7 ("Bluetooth: L2CAP: Use DEFER_SETUP to group ECRED connections")
---
 net/bluetooth/l2cap_core.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
net/bluetooth/l2cap_core.c +15 -0
index ad98db9632fd..a0b56fb0afb0 100644
@@ -3833,6 +3833,12 @@ static void l2cap_ecred_rsp_defer(struct l2cap_chan *chan, void *data)
 	    !test_and_clear_bit(FLAG_DEFER_SETUP, &chan->flags))
 		return;
 
+	if (rsp->count >= L2CAP_ECRED_MAX_CID) {
+		chan->ident = 0;
+		l2cap_chan_del(chan, ECONNRESET);
+		return;
+	}
+
 	/* Reset ident so only one response is sent */
 	chan->ident = 0;
 
@@ -5132,6 +5138,15 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
 		goto unlock;
 	}
 
+	/* Check if incoming channels are already pending for this ident */
+	list_for_each_entry(chan, &conn->chan_l, list) {
+		if (chan->ident == cmd->ident &&
+		    !test_bit(FLAG_ECRED_CONN_REQ_SENT, &chan->flags)) {
+			result = L2CAP_CR_LE_INVALID_PARAMS;
+			goto unlock;
+		}
+	}
+
 	result = L2CAP_CR_LE_SUCCESS;
 
 	for (i = 0; i < num_scid; i++) {

base-commit: 1f318b96cc84d7c2ab792fcc0bfd42a7ca890681

Signature · 1 line
2.43.0
#2 lore raw

Hi Lukas,

Quoted 60 lines · Lukas Johannes Möller

l2cap_ecred_rsp_defer() appends channel SCIDs to rsp_flex->dcid[rsp->count++] without checking rsp->count against L2CAP_ECRED_MAX_CID. The dcid[] flexible array member is backed by a stack-allocated structure with room for only L2CAP_ECRED_MAX_CID (5) entries.

Per-request validation in l2cap_ecred_conn_req() limits a single L2CAP_ECRED_CONN_REQ to at most 5 SCIDs, but multiple requests can reuse the same attacker-controlled signaling identifier. When __l2cap_ecred_conn_rsp_defer() later walks all channels with that ident, the callback writes past the fixed backing array. For LE links (SCIDs 0x0040..0x007f) the maximum overwrite is 118 bytes past the end of the buffer.

Add a bounds check in l2cap_ecred_rsp_defer() that cleans up excess channels, and reject incoming requests in l2cap_ecred_conn_req() when channels are already pending for the same ident.

Fixes da49b602f7f7 ("Bluetooth: L2CAP: Use DEFER_SETUP to group ECRED connections")
---
 net/bluetooth/l2cap_core.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
net/bluetooth/l2cap_core.c +15 -0
index ad98db9632fd..a0b56fb0afb0 100644
@@ -3833,6 +3833,12 @@ static void l2cap_ecred_rsp_defer(struct l2cap_chan *chan, void *data)
            !test_and_clear_bit(FLAG_DEFER_SETUP, &chan->flags))
                return;
 
+       if (rsp->count >= L2CAP_ECRED_MAX_CID) {
+               chan->ident = 0;
+               l2cap_chan_del(chan, ECONNRESET);
+               return;
+       }
+
        /* Reset ident so only one response is sent */
        chan->ident = 0;
 
@@ -5132,6 +5138,15 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
                goto unlock;
        }
 
+       /* Check if incoming channels are already pending for this ident */
+       list_for_each_entry(chan, &conn->chan_l, list) {
+               if (chan->ident == cmd->ident &&
+                   !test_bit(FLAG_ECRED_CONN_REQ_SENT, &chan->flags)) {
+                       result = L2CAP_CR_LE_INVALID_PARAMS;
+                       goto unlock;
+               }
+       }
+
        result = L2CAP_CR_LE_SUCCESS;
 
        for (i = 0; i < num_scid; i++) {
Quoted 3 lines

base-commit: 1f318b96cc84d7c2ab792fcc0bfd42a7ca890681 --
2.43.0

This is already a similar change under review:

https://patchwork.kernel.org/project/bluetooth/patch/[email protected]/

Signature · 1 line
Luiz Augusto von Dentz