← Notes

Bluetooth: L2CAP: Validate L2CAP_INFO_RSP payload length before access

Overview

CVECVE-2026-31393
Componentnet/bluetooth/l2cap_core.c (l2cap_information_rsp())
Attack surfaceBluetooth BR/EDR L2CAP signalling during capability discovery
FixedLinux v6.14 (4b0c8bb9885a)
ClassCWE-125 (Out-of-Bounds Read)
CVSS v3.18.1 (High, kernel.org CNA) -- CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H
Found and patched byLukas Johannes Moeller (@JohannesLks)

TL;DR

l2cap_information_rsp() validates the 4-byte L2CAP_INFO_RSP header, then reads optional response payload fields without proving those bytes are present. A nearby device can send a truncated success response and make the kernel read past the received command buffer before pairing or authentication.

Root Cause

The handler first ensures the fixed response header exists:

if (cmd_len < sizeof(struct l2cap_info_rsp))
    return -EPROTO;

That is sufficient for type and result, but not for the data interpreted after a successful response:

case L2CAP_IT_FEAT_MASK:
    conn->feat_mask = get_unaligned_le32(rsp->data);
    break;

case L2CAP_IT_FIXED_CHAN:
    if (rsp->data[0] & L2CAP_FC_SIG_BREDR)
        ...

The missing invariant is per-response minimum length: FEAT_MASK needs 8 total command bytes, while FIXED_CHAN needs at least 5.

Impact

  • Triggerable by a Bluetooth peer within radio range during L2CAP setup.
  • Observed security property: kernel heap out-of-bounds read into parser state, not a demonstrated controlled leak to userspace.
  • Practical impact is conservative: memory-safety bug in pre-pairing Bluetooth parsing, fixed upstream; no code execution primitive claimed.

Fix

The fix adds payload-length checks at the point where each optional field is read:

case L2CAP_IT_FEAT_MASK:
    if (cmd_len >= 8)
        conn->feat_mask = get_unaligned_le32(rsp->data);
    break;

case L2CAP_IT_FIXED_CHAN:
    if (cmd_len >= 5 && (rsp->data[0] & L2CAP_FC_SIG_BREDR))
        ...