{bp-20003} wireless/bluetooth: fix inverted MTU cap in bt_conn_send() - #20077
Merged
Conversation
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 <gluca86@gmail.com>
jerpelea
requested review from
pkarashchenko,
tmedicci and
xiaoxiang781216
as code owners
September 7, 2026 08:30
cederom
approved these changes
Sep 7, 2026
Contributor
Author
|
CI fix |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
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.
Impact
RELEASE
Testing
CI