Skip to contentSkip to conversation

Bluetooth: L2CAP: Fix type confusion in l2cap_ecred_reconf_rsp()

PATCH In review Lukas Johannes Möller 2 participants 4 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/2 Bluetooth: L2CAP: Fix type confusion in l2cap_ecred_reconf_rsp()

l2cap_ecred_reconf_rsp() casts the incoming data to struct l2cap_ecred_conn_rsp (the ECRED *connection* response, 8 bytes with result at offset 6) instead of struct l2cap_ecred_reconf_rsp (2 bytes with result at offset 0).

This causes two problems:

- The sizeof(*rsp) length check requires 8 bytes instead of the correct 2, so valid L2CAP_ECRED_RECONF_RSP packets are rejected with -EPROTO.

- rsp->result reads from offset 6 instead of offset 0, returning wrong data when the packet is large enough to pass the check.

Fix by using the correct type. Also pass the already byte-swapped result variable to BT_DBG instead of the raw __le16 field.

Fixes 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode")
---
 net/bluetooth/l2cap_core.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
net/bluetooth/l2cap_core.c +2 -2
index ad98db9632fd..f8ed03095592 100644
@@ -5424,7 +5424,7 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn,
 					 u8 *data)
 {
 	struct l2cap_chan *chan, *tmp;
-	struct l2cap_ecred_conn_rsp *rsp = (void *) data;
+	struct l2cap_ecred_reconf_rsp *rsp = (void *) data;
 	u16 result;
 
 	if (cmd_len < sizeof(*rsp))
@@ -5432,7 +5432,7 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn,
 
 	result = __le16_to_cpu(rsp->result);
 
-	BT_DBG("result 0x%4.4x", rsp->result);
+	BT_DBG("result 0x%4.4x", result);
 
 	if (!result)
 		return 0;
Signature · 1 line
2.43.0
#2 lore raw

Hi Lukas,

Quoted 48 lines · Lukas Johannes Möller

l2cap_ecred_reconf_rsp() casts the incoming data to struct l2cap_ecred_conn_rsp (the ECRED *connection* response, 8 bytes with result at offset 6) instead of struct l2cap_ecred_reconf_rsp (2 bytes with result at offset 0).

This causes two problems:

- The sizeof(*rsp) length check requires 8 bytes instead of the correct 2, so valid L2CAP_ECRED_RECONF_RSP packets are rejected with -EPROTO.

- rsp->result reads from offset 6 instead of offset 0, returning wrong data when the packet is large enough to pass the check.

Fix by using the correct type. Also pass the already byte-swapped result variable to BT_DBG instead of the raw __le16 field.

Fixes 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode")
---
 net/bluetooth/l2cap_core.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
net/bluetooth/l2cap_core.c +2 -3
index ad98db9632fd..f8ed03095592 100644
@@ -5424,7 +5424,7 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn,
                                         u8 *data)
 {
        struct l2cap_chan *chan, *tmp;
-       struct l2cap_ecred_conn_rsp *rsp = (void *) data;
+       struct l2cap_ecred_reconf_rsp *rsp = (void *) data;
        u16 result;
 
        if (cmd_len < sizeof(*rsp))
@@ -5432,7 +5432,7 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn,
 
        result = __le16_to_cpu(rsp->result);
 
-       BT_DBG("result 0x%4.4x", rsp->result);
+       BT_DBG("result 0x%4.4x", result);
 
        if (!result)
                return 0;
--
Quoted 1 line

2.43.0

Looks good, but need to include linux-bluetooth so CI can pickup and check if there are any regressions caused by this change.

Signature · 1 line
Luiz Augusto von Dentz
#3 lore raw

PATCH 2/2 Bluetooth: L2CAP: Validate L2CAP_INFO_RSP payload length before access

In reply to Lukas Johannes Möller

l2cap_information_rsp() checks that cmd_len covers the fixed l2cap_info_rsp header (type + result, 4 bytes) but then reads rsp->data without verifying that the payload is present:

- L2CAP_IT_FEAT_MASK calls get_unaligned_le32(rsp->data), which reads 4 bytes past the header (needs cmd_len >= 8).

- L2CAP_IT_FIXED_CHAN reads rsp->data[0], 1 byte past the header (needs cmd_len >= 5).

A truncated L2CAP_INFO_RSP with result == L2CAP_IR_SUCCESS triggers an out-of-bounds read of adjacent skb data.

Guard each data access with the required payload length check. If the payload is too short, skip the read and let the state machine complete with safe defaults (feat_mask and remote_fixed_chan remain zero from kzalloc), so the info timer cleanup and l2cap_conn_start() still run and the connection is not stalled.

Fixes 4e8402a3f884 ("[Bluetooth] Retrieve L2CAP features mask on connection setup")
---
 net/bluetooth/l2cap_core.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
net/bluetooth/l2cap_core.c +4 -2
index f8ed03095592..93e41d9ac124 100644
@@ -4616,7 +4616,8 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn,
 
 	switch (type) {
 	case L2CAP_IT_FEAT_MASK:
-		conn->feat_mask = get_unaligned_le32(rsp->data);
+		if (cmd_len >= sizeof(*rsp) + sizeof(u32))
+			conn->feat_mask = get_unaligned_le32(rsp->data);
 
 		if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
 			struct l2cap_info_req req;
@@ -4635,7 +4636,8 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn,
 		break;
 
 	case L2CAP_IT_FIXED_CHAN:
-		conn->remote_fixed_chan = rsp->data[0];
+		if (cmd_len >= sizeof(*rsp) + sizeof(rsp->data[0]))
+			conn->remote_fixed_chan = rsp->data[0];
 		conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
 		conn->info_ident = 0;
 
Signature · 1 line
2.43.0
#4 lore raw

Re: [PATCH 2/2] Bluetooth: L2CAP: Validate L2CAP_INFO_RSP payload length before access

Hi Lukas,

Quoted 52 lines · Lukas Johannes Möller

l2cap_information_rsp() checks that cmd_len covers the fixed l2cap_info_rsp header (type + result, 4 bytes) but then reads rsp->data without verifying that the payload is present:

- L2CAP_IT_FEAT_MASK calls get_unaligned_le32(rsp->data), which reads 4 bytes past the header (needs cmd_len >= 8).

- L2CAP_IT_FIXED_CHAN reads rsp->data[0], 1 byte past the header (needs cmd_len >= 5).

A truncated L2CAP_INFO_RSP with result == L2CAP_IR_SUCCESS triggers an out-of-bounds read of adjacent skb data.

Guard each data access with the required payload length check. If the payload is too short, skip the read and let the state machine complete with safe defaults (feat_mask and remote_fixed_chan remain zero from kzalloc), so the info timer cleanup and l2cap_conn_start() still run and the connection is not stalled.

Fixes 4e8402a3f884 ("[Bluetooth] Retrieve L2CAP features mask on connection setup")
---
 net/bluetooth/l2cap_core.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
net/bluetooth/l2cap_core.c +4 -3
index f8ed03095592..93e41d9ac124 100644
@@ -4616,7 +4616,8 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn,
 
        switch (type) {
        case L2CAP_IT_FEAT_MASK:
-               conn->feat_mask = get_unaligned_le32(rsp->data);
+               if (cmd_len >= sizeof(*rsp) + sizeof(u32))
+                       conn->feat_mask = get_unaligned_le32(rsp->data);
 
                if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
                        struct l2cap_info_req req;
@@ -4635,7 +4636,8 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn,
                break;
 
        case L2CAP_IT_FIXED_CHAN:
-               conn->remote_fixed_chan = rsp->data[0];
+               if (cmd_len >= sizeof(*rsp) + sizeof(rsp->data[0]))
+                       conn->remote_fixed_chan = rsp->data[0];
                conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
                conn->info_ident = 0;
 
--
Quoted 1 line

2.43.0

Ditto, send to linux-bluetooth so it can trigger test automation.

Signature · 1 line
Luiz Augusto von Dentz