Skip to content

[PW_SID:1096214] Bluetooth: L2CAP: rate-limit ECHO_RSP per signaling PDU#207

Open
BluezTestBot wants to merge 6 commits into
workflowfrom
1096214
Open

[PW_SID:1096214] Bluetooth: L2CAP: rate-limit ECHO_RSP per signaling PDU#207
BluezTestBot wants to merge 6 commits into
workflowfrom
1096214

Conversation

@BluezTestBot
Copy link
Copy Markdown

l2cap_sig_channel() walks every L2CAP signaling command packed in
one inbound ACL frame and dispatches each to l2cap_bredr_sig_cmd().
The L2CAP_ECHO_REQ handler unconditionally calls

l2cap_send_cmd(conn, ident, L2CAP_ECHO_RSP, cmd_len, data);

per request, with no per-PDU cap and no per-connection rate limit
anywhere in the path (HCI -> hci_conn -> l2cap_sig_channel ->
l2cap_bredr_sig_cmd).

A peer that packs N L2CAP_ECHO_REQ commands (4 bytes each) into a
single inbound signaling PDU forces the kernel to emit N separate
ACL frames carrying L2CAP_ECHO_RSP. Measured between two
unmodified upstream kernels over real radio (Intel AX210 attacker,
Intel BE200 target):

N=1 : 13 B in, 13 B out, 1 ACL frame back, 23 ms wall
N=4 : 25 B in, 52 B out, 4 ACL frames back, 12 ms wall
N=16 : 73 B in, 208 B out, 16 ACL frames back, 28 ms wall
N=48 : 201 B in, 624 B out, 48 ACL frames back, 67 ms wall
N=168 : 681 B in, 2184 B out, 168 ACL frames back, 220 ms wall

The 10x latency growth at N=168 vs N=1 (220ms vs 23ms) is the
target's signaling work-queue and radio TX queue saturating on the
burst. A sustained flood (50 inbound PDUs of 168 packed echoes
each) drives ~840 ECHO_RSPs/sec from the target until the kernel's
input ACL queue back-pressures the attacker; during the attack
window the target's BT radio is fully occupied answering echoes
and any other ongoing BT traffic (audio, HID, file transfer) is
starved. bluetoothd CPU stays at 0% throughout -- the entire path
is kernel-side.

L2CAP signaling channel CID 0x0001 is pre-auth, so no pairing is
required to reach the bug. Reproducible from any device with a
programmable Bluetooth radio within range of a target running an
unpatched kernel with CONFIG_BT_BREDR=y (effectively every
Linux distribution that ships Bluetooth).

Cap the number of echoes answered per inbound signaling PDU to
L2CAP_SIG_ECHO_BURST (4). Subsequent ECHO_REQs in the same PDU
are silently dropped. Legitimate clients (l2ping, BlueZ test
suite, specification-compliant L2CAP) send one ECHO_REQ per PDU
and are unaffected. Worst-case amplification ratio is now 4:1
per PDU, bounded.

Fixes: 1da177e ("Linux-2.6.12-rc2")
Signed-off-by: Michael Bommarito michael.bommarito@gmail.com
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-7

net/bluetooth/l2cap_core.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)

tedd-an and others added 6 commits May 13, 2026 17:39
This patch adds workflow files for ci:

[sync.yml]
 - The workflow file for scheduled work
 - Sync the repo with upstream repo and rebase the workflow branch
 - Review the patches in the patchwork and creates the PR if needed

[ci.yml]
 - The workflow file for CI tasks
 - Run CI tests when PR is created

Signed-off-by: Tedd Ho-Jeong An <tedd.an@intel.com>
This replaces the bzcafe action with bluez/action-ci so we can maintain
everything in the github bluez organization

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This attempts to sync every 5 minutes instead of 30.

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
bluez/action-ci uses master as default branch for workflow which is
incorrect for kernel

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
The CI action now creates individual GitHub Check Runs per test, which
requires 'checks: write' permission on the GITHUB_TOKEN. Also make the
pull_request trigger types explicit to include 'reopened', allowing CI
to be retriggered by closing and reopening a PR.
l2cap_sig_channel() walks every L2CAP signaling command packed in
one inbound ACL frame and dispatches each to l2cap_bredr_sig_cmd().
The L2CAP_ECHO_REQ handler unconditionally calls

  l2cap_send_cmd(conn, ident, L2CAP_ECHO_RSP, cmd_len, data);

per request, with no per-PDU cap and no per-connection rate limit
anywhere in the path (HCI -> hci_conn -> l2cap_sig_channel ->
l2cap_bredr_sig_cmd).

A peer that packs N L2CAP_ECHO_REQ commands (4 bytes each) into a
single inbound signaling PDU forces the kernel to emit N separate
ACL frames carrying L2CAP_ECHO_RSP.  Measured between two
unmodified upstream kernels over real radio (Intel AX210 attacker,
Intel BE200 target):

  N=1   :    13 B in,    13 B out,  1 ACL frame back,  23 ms wall
  N=4   :    25 B in,    52 B out,  4 ACL frames back, 12 ms wall
  N=16  :    73 B in,   208 B out, 16 ACL frames back, 28 ms wall
  N=48  :   201 B in,   624 B out, 48 ACL frames back, 67 ms wall
  N=168 :   681 B in,  2184 B out, 168 ACL frames back, 220 ms wall

The 10x latency growth at N=168 vs N=1 (220ms vs 23ms) is the
target's signaling work-queue and radio TX queue saturating on the
burst.  A sustained flood (50 inbound PDUs of 168 packed echoes
each) drives ~840 ECHO_RSPs/sec from the target until the kernel's
input ACL queue back-pressures the attacker; during the attack
window the target's BT radio is fully occupied answering echoes
and any other ongoing BT traffic (audio, HID, file transfer) is
starved.  bluetoothd CPU stays at 0% throughout -- the entire path
is kernel-side.

L2CAP signaling channel CID 0x0001 is pre-auth, so no pairing is
required to reach the bug.  Reproducible from any device with a
programmable Bluetooth radio within range of a target running an
unpatched kernel with CONFIG_BT_BREDR=y (effectively every
Linux distribution that ships Bluetooth).

Cap the number of echoes answered per inbound signaling PDU to
L2CAP_SIG_ECHO_BURST (4).  Subsequent ECHO_REQs in the same PDU
are silently dropped.  Legitimate clients (l2ping, BlueZ test
suite, specification-compliant L2CAP) send one ECHO_REQ per PDU
and are unaffected.  Worst-case amplification ratio is now 4:1
per PDU, bounded.

Fixes: 1da177e ("Linux-2.6.12-rc2")
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-7
@github-actions
Copy link
Copy Markdown

CheckPatch
Desc: Run checkpatch.pl script
Duration: 0.76 seconds
Result: PASS

@github-actions
Copy link
Copy Markdown

GitLint
Desc: Run gitlint
Duration: 0.34 seconds
Result: PASS

@github-actions
Copy link
Copy Markdown

SubjectPrefix
Desc: Check subject contains "Bluetooth" prefix
Duration: 0.13 seconds
Result: PASS

@github-actions
Copy link
Copy Markdown

BuildKernel
Desc: Build Kernel for Bluetooth
Duration: 25.56 seconds
Result: PASS

@github-actions
Copy link
Copy Markdown

CheckAllWarning
Desc: Run linux kernel with all warning enabled
Duration: 27.84 seconds
Result: PASS

@github-actions
Copy link
Copy Markdown

CheckSparse
Desc: Run sparse tool with linux kernel
Duration: 26.36 seconds
Result: PASS

@github-actions
Copy link
Copy Markdown

BuildKernel32
Desc: Build 32bit Kernel for Bluetooth
Duration: 24.38 seconds
Result: PASS

@github-actions
Copy link
Copy Markdown

TestRunnerSetup
Desc: Setup kernel and bluez for test-runner
Duration: 533.67 seconds
Result: PASS

@github-actions
Copy link
Copy Markdown

TestRunner_l2cap-tester
Desc: Run l2cap-tester with test-runner
Duration: 378.52 seconds
Result: PASS

@github-actions
Copy link
Copy Markdown

IncrementalBuild
Desc: Incremental build with the patches in the series
Duration: 25.29 seconds
Result: PASS

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants