This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 9d12f6ccc62f5cd44b466d546fcab1ed8e97ee6f
Author: Alan Carvalho de Assis <[email protected]>
AuthorDate: Thu Sep 17 10:15:46 2026 -0300

    wireless/bluetooth: Validate the L2CAP header on the first ACL fragment.
    
    bt_conn_receive() read the 4-octet L2CAP header out of the first fragment
    of a PDU without checking that 4 octets had been received, and then
    computed the outstanding length by subtracting the fragment length from
    the declared PDU length.
    
    Two problems follow.  A fragment shorter than the header was parsed from
    whatever happened to follow it in the buffer.  And a fragment carrying
    more data than the PDU it declares made the subtraction wrap, because
    conn->rx_len is 16 bits: the connection was then left expecting up to
    65535 further octets, holding the partial PDU and accumulating later
    fragments against an expectation that could never be satisfied.
    
    Check that the fragment is long enough to hold a header before reading
    it, and that it does not exceed the PDU it declares before computing what
    remains.  Drop the fragment and reset the reassembly state otherwise.
    
    Ref: Core v6.0, Vol 3, Part A, 3.1 (B-frame format)
    Ref: Core v6.0, Vol 4, Part E, 5.4.2 (HCI ACL Data packets)
    Testing: builds for sim:bluetooth with Make; every commit in this series
    verified to build individually.  Not yet exercised at runtime - the
    scriptable controller adds the truncated and oversized fragment cases
    separately.
    
    Signed-off-by: Alan C. Assis <[email protected]>
    Assisted-by: Claude Code Opus 5
---
 wireless/bluetooth/bt_conn.c | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/wireless/bluetooth/bt_conn.c b/wireless/bluetooth/bt_conn.c
index 752054dfc17..17afac483df 100644
--- a/wireless/bluetooth/bt_conn.c
+++ b/wireless/bluetooth/bt_conn.c
@@ -294,7 +294,18 @@ void bt_conn_receive(FAR struct bt_conn_s *conn, FAR 
struct bt_buf_s *buf,
     {
       case BT_HCI_ACL_NEW:
 
-        /* First packet */
+        /* First packet.  The L2CAP header is read from the fragment, so
+         * the fragment has to be long enough to hold one.
+         */
+
+        if (buf->len < sizeof(*hdr))
+          {
+            wlerr("ERROR: First L2CAP frame too short for a header (%u)\n",
+                  buf->len);
+            bt_conn_reset_rx_state(conn);
+            bt_buf_release(buf);
+            return;
+          }
 
         hdr = (FAR void *)buf->data;
         len = BT_LE162HOST(hdr->len);
@@ -307,6 +318,21 @@ void bt_conn_receive(FAR struct bt_conn_s *conn, FAR 
struct bt_buf_s *buf,
             bt_conn_reset_rx_state(conn);
           }
 
+        /* The fragment must not carry more than the PDU it declares.  If
+         * it does, the outstanding length below underflows and the
+         * connection is parked waiting for a remainder that cannot come,
+         * holding the partial PDU until some later error clears it.
+         */
+
+        if (buf->len > sizeof(*hdr) + len)
+          {
+            wlerr("ERROR: First L2CAP frame exceeds its PDU (%u > %zu)\n",
+                  buf->len, sizeof(*hdr) + len);
+            bt_conn_reset_rx_state(conn);
+            bt_buf_release(buf);
+            return;
+          }
+
         conn->rx_len = (sizeof(*hdr) + len) - buf->len;
         wlinfo("rx_len %u\n", conn->rx_len);
         if (conn->rx_len)

Reply via email to