From 5e92a05dc437225e1d139e57b60d4127851db645 Mon Sep 17 00:00:00 2001 From: AlmAck Date: Sat, 29 Aug 2026 19:00:13 +0200 Subject: [PATCH] wireless/bluetooth: fix inverted MTU cap in bt_conn_send() bt_conn_send() splits an outgoing L2CAP PDU into HCI ACL fragments no larger than g_btdev.le_mtu, the controller's HCI ACL data packet length. The first fragment caps its length correctly: len = remaining; if (len > g_btdev.le_mtu) { len = g_btdev.le_mtu; } The continuation loop below uses '<' instead of '>', so a continuation shorter than le_mtu has its length raised to le_mtu rather than left alone. Both len and remaining are uint16_t, which turns a wrong length into an underflow: With le_mtu 251 and a 300-byte PDU, the first fragment takes 251 bytes and leaves remaining == 49. The loop then raises len from 49 to 251, so memcpy(bt_buf_extend(buf, len), ptr, len); reads 202 bytes past the end of the source, and remaining -= len; evaluates 49 - 251 as a uint16_t, wrapping to 65334. On the next iteration len is 65334, which is not less than le_mtu, so it survives the cap. bt_buf_extend() carries only a DEBUGASSERT on tailroom, so with assertions disabled it adds 65334 to buf->len and returns, and the memcpy writes 64 KB into a pooled buffer sized for a few hundred bytes. Only the last fragment of a multi-fragment PDU is normally shorter than le_mtu, so the first fragmented transmission triggers it. Signed-off-by: AlmAck --- wireless/bluetooth/bt_conn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wireless/bluetooth/bt_conn.c b/wireless/bluetooth/bt_conn.c index 4764527f5ff..752054dfc17 100644 --- a/wireless/bluetooth/bt_conn.c +++ b/wireless/bluetooth/bt_conn.c @@ -442,7 +442,7 @@ void bt_conn_send(FAR struct bt_conn_s *conn, FAR struct bt_buf_s *buf) buf = bt_l2cap_create_pdu(conn); len = remaining; - if (len < g_btdev.le_mtu) + if (len > g_btdev.le_mtu) { len = g_btdev.le_mtu; }