]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
Bluetooth: L2CAP: Validate L2CAP_INFO_RSP payload length before access
authorLukas Johannes Möller <research@johannes-moeller.dev>
Tue, 10 Mar 2026 21:59:47 +0000 (21:59 +0000)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Thu, 12 Mar 2026 19:29:07 +0000 (15:29 -0400)
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")
Cc: stable@vger.kernel.org
Signed-off-by: Lukas Johannes Möller <research@johannes-moeller.dev>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
net/bluetooth/l2cap_core.c

index 08a12515bfed95e77b329e56562f734d3fd0229e..5deb6c4f1e41da74d8035c5ca74f99e7fcd9d1d3 100644 (file)
@@ -4612,7 +4612,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;
@@ -4631,7 +4632,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;