Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH v2] Bluetooth: L2CAP: reject BR/EDR signaling packets over MTUsig
@ 2026-05-20 13:50 Michael Bommarito
  2026-05-20 14:00 ` Luiz Augusto von Dentz
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Michael Bommarito @ 2026-05-20 13:50 UTC (permalink / raw)
  To: Marcel Holtmann, Luiz Augusto von Dentz
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, linux-bluetooth, netdev, linux-kernel, stable

net/bluetooth/l2cap_core.c:l2cap_sig_channel() accepts BR/EDR
signaling packets up to the channel MTU and dispatches each command
without enforcing the signaling MTU (MTUsig). A Bluetooth BR/EDR peer
within radio range can send a fixed-channel CID 0x0001 packet that is
larger than MTUsig and contains many L2CAP_ECHO_REQ commands before
pairing.

In a real-radio stock-kernel run, one 681-byte signaling
packet containing 168 zero-length ECHO_REQ commands made the target
transmit 168 ECHO_RSP frames over about 220 ms.

Define Linux's BR/EDR signaling MTU as the spec minimum of 48 bytes and
reject larger signaling packets before dispatching their commands. When
the over-MTUsig packet contains a request command, send one
L2CAP_COMMAND_REJECT_RSP with L2CAP_REJ_MTU_EXCEEDED and the first
request identifier; packets for which no valid request command is found
are dropped.

Cc: stable@vger.kernel.org
Suggested-by: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Link: https://lore.kernel.org/r/20260518002800.1361430-1-michael.bommarito@gmail.com
Assisted-by: Claude:claude-opus-4-7
Assisted-by: Codex:gpt-5-5-xhigh
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
I reproduced the stock behavior with a real-radio BR/EDR ACL link and a
harness that sends a single fixed-channel signaling packet containing
packed zero-length ECHO_REQ commands. The patched code builds for
net/bluetooth/l2cap_core.o on x86_64 defconfig. There are no in-tree
Bluetooth selftests that reference l2cap_sig_channel(), L2CAP_SIG_MTU,
or L2CAP_ECHO_REQ.

The unrestricted BR/EDR signaling parser and ECHO_REQ response path both
trace to the initial git import; no later introducing commit is
available for a Fixes tag.

Changes in v2:
- Replace the per-PDU echo-count cap with the MTUsig direction from
  review.
- Reject the whole over-MTUsig signaling packet with one
  L2CAP_REJ_MTU_EXCEEDED command reject.
- Add L2CAP_SIG_MTU and drop over-MTUsig packets when no valid request
  command identifier is found.

v1: https://lore.kernel.org/r/20260518002800.1361430-1-michael.bommarito@gmail.com
---
 include/net/bluetooth/l2cap.h |  1 +
 net/bluetooth/l2cap_core.c    | 60 +++++++++++++++++++++++++++++++++++
 2 files changed, 61 insertions(+)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 5172afee54943..e0a1f2293679a 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -33,6 +33,7 @@
 /* L2CAP defaults */
 #define L2CAP_DEFAULT_MTU		672
 #define L2CAP_DEFAULT_MIN_MTU		48
+#define L2CAP_SIG_MTU			48	/* BR/EDR signaling MTU */
 #define L2CAP_DEFAULT_FLUSH_TO		0xFFFF
 #define L2CAP_EFS_DEFAULT_FLUSH_TO	0xFFFFFFFF
 #define L2CAP_DEFAULT_TX_WINDOW		63
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 77dec104a9c36..5417e3cb0636d 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -5626,6 +5626,55 @@ static inline void l2cap_sig_send_rej(struct l2cap_conn *conn, u16 ident)
 	l2cap_send_cmd(conn, ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
 }
 
+static bool l2cap_sig_cmd_is_req(u8 code)
+{
+	switch (code) {
+	case L2CAP_CONN_REQ:
+	case L2CAP_CONF_REQ:
+	case L2CAP_DISCONN_REQ:
+	case L2CAP_ECHO_REQ:
+	case L2CAP_INFO_REQ:
+	case L2CAP_CONN_PARAM_UPDATE_REQ:
+	case L2CAP_LE_CONN_REQ:
+	case L2CAP_ECRED_CONN_REQ:
+	case L2CAP_ECRED_RECONF_REQ:
+		return true;
+	}
+
+	return false;
+}
+
+static u8 l2cap_sig_first_req_ident(const struct sk_buff *skb)
+{
+	const u8 *data = skb->data;
+	unsigned int len = skb->len;
+
+	while (len >= L2CAP_CMD_HDR_SIZE) {
+		const struct l2cap_cmd_hdr *cmd = (const void *)data;
+		u16 cmd_len = le16_to_cpu(cmd->len);
+
+		if (cmd->ident && l2cap_sig_cmd_is_req(cmd->code))
+			return cmd->ident;
+
+		if (cmd_len > len - L2CAP_CMD_HDR_SIZE)
+			break;
+
+		data += L2CAP_CMD_HDR_SIZE + cmd_len;
+		len -= L2CAP_CMD_HDR_SIZE + cmd_len;
+	}
+
+	return 0;
+}
+
+static inline void l2cap_sig_send_mtu_rej(struct l2cap_conn *conn, u8 ident)
+{
+	struct l2cap_cmd_rej_mtu rej;
+
+	rej.reason = cpu_to_le16(L2CAP_REJ_MTU_EXCEEDED);
+	rej.max_mtu = cpu_to_le16(L2CAP_SIG_MTU);
+	l2cap_send_cmd(conn, ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
+}
+
 static inline void l2cap_sig_channel(struct l2cap_conn *conn,
 				     struct sk_buff *skb)
 {
@@ -5638,6 +5687,17 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
 	if (hcon->type != ACL_LINK)
 		goto drop;
 
+	if (skb->len > L2CAP_SIG_MTU) {
+		u8 ident = l2cap_sig_first_req_ident(skb);
+
+		BT_DBG("signaling packet exceeds MTU");
+
+		if (ident)
+			l2cap_sig_send_mtu_rej(conn, ident);
+
+		goto drop;
+	}
+
 	while (skb->len >= L2CAP_CMD_HDR_SIZE) {
 		u16 len;
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v2] Bluetooth: L2CAP: reject BR/EDR signaling packets over MTUsig
  2026-05-20 13:50 [PATCH v2] Bluetooth: L2CAP: reject BR/EDR signaling packets over MTUsig Michael Bommarito
@ 2026-05-20 14:00 ` Luiz Augusto von Dentz
  2026-05-20 14:12   ` Michael Bommarito
  2026-05-20 14:48 ` [v2] " bluez.test.bot
  2026-05-21  0:05 ` [PATCH v3] " Michael Bommarito
  2 siblings, 1 reply; 12+ messages in thread
From: Luiz Augusto von Dentz @ 2026-05-20 14:00 UTC (permalink / raw)
  To: Michael Bommarito
  Cc: Marcel Holtmann, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, linux-bluetooth, netdev, linux-kernel,
	stable

Hi Michael,

On Wed, May 20, 2026 at 9:50 AM Michael Bommarito
<michael.bommarito@gmail.com> wrote:
>
> net/bluetooth/l2cap_core.c:l2cap_sig_channel() accepts BR/EDR
> signaling packets up to the channel MTU and dispatches each command
> without enforcing the signaling MTU (MTUsig). A Bluetooth BR/EDR peer
> within radio range can send a fixed-channel CID 0x0001 packet that is
> larger than MTUsig and contains many L2CAP_ECHO_REQ commands before
> pairing.
>
> In a real-radio stock-kernel run, one 681-byte signaling
> packet containing 168 zero-length ECHO_REQ commands made the target
> transmit 168 ECHO_RSP frames over about 220 ms.
>
> Define Linux's BR/EDR signaling MTU as the spec minimum of 48 bytes and
> reject larger signaling packets before dispatching their commands. When
> the over-MTUsig packet contains a request command, send one
> L2CAP_COMMAND_REJECT_RSP with L2CAP_REJ_MTU_EXCEEDED and the first
> request identifier; packets for which no valid request command is found
> are dropped.
>
> Cc: stable@vger.kernel.org
> Suggested-by: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
> Link: https://lore.kernel.org/r/20260518002800.1361430-1-michael.bommarito@gmail.com
> Assisted-by: Claude:claude-opus-4-7
> Assisted-by: Codex:gpt-5-5-xhigh
> Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
> ---
> I reproduced the stock behavior with a real-radio BR/EDR ACL link and a
> harness that sends a single fixed-channel signaling packet containing
> packed zero-length ECHO_REQ commands. The patched code builds for
> net/bluetooth/l2cap_core.o on x86_64 defconfig. There are no in-tree
> Bluetooth selftests that reference l2cap_sig_channel(), L2CAP_SIG_MTU,
> or L2CAP_ECHO_REQ.
>
> The unrestricted BR/EDR signaling parser and ECHO_REQ response path both
> trace to the initial git import; no later introducing commit is
> available for a Fixes tag.
>
> Changes in v2:
> - Replace the per-PDU echo-count cap with the MTUsig direction from
>   review.
> - Reject the whole over-MTUsig signaling packet with one
>   L2CAP_REJ_MTU_EXCEEDED command reject.
> - Add L2CAP_SIG_MTU and drop over-MTUsig packets when no valid request
>   command identifier is found.
>
> v1: https://lore.kernel.org/r/20260518002800.1361430-1-michael.bommarito@gmail.com
> ---
>  include/net/bluetooth/l2cap.h |  1 +
>  net/bluetooth/l2cap_core.c    | 60 +++++++++++++++++++++++++++++++++++
>  2 files changed, 61 insertions(+)
>
> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> index 5172afee54943..e0a1f2293679a 100644
> --- a/include/net/bluetooth/l2cap.h
> +++ b/include/net/bluetooth/l2cap.h
> @@ -33,6 +33,7 @@
>  /* L2CAP defaults */
>  #define L2CAP_DEFAULT_MTU              672
>  #define L2CAP_DEFAULT_MIN_MTU          48
> +#define L2CAP_SIG_MTU                  48      /* BR/EDR signaling MTU */
>  #define L2CAP_DEFAULT_FLUSH_TO         0xFFFF
>  #define L2CAP_EFS_DEFAULT_FLUSH_TO     0xFFFFFFFF
>  #define L2CAP_DEFAULT_TX_WINDOW                63
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index 77dec104a9c36..5417e3cb0636d 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -5626,6 +5626,55 @@ static inline void l2cap_sig_send_rej(struct l2cap_conn *conn, u16 ident)
>         l2cap_send_cmd(conn, ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
>  }
>
> +static bool l2cap_sig_cmd_is_req(u8 code)
> +{
> +       switch (code) {
> +       case L2CAP_CONN_REQ:
> +       case L2CAP_CONF_REQ:
> +       case L2CAP_DISCONN_REQ:
> +       case L2CAP_ECHO_REQ:
> +       case L2CAP_INFO_REQ:
> +       case L2CAP_CONN_PARAM_UPDATE_REQ:
> +       case L2CAP_LE_CONN_REQ:
> +       case L2CAP_ECRED_CONN_REQ:
> +       case L2CAP_ECRED_RECONF_REQ:
> +               return true;
> +       }
> +
> +       return false;
> +}
> +
> +static u8 l2cap_sig_first_req_ident(const struct sk_buff *skb)
> +{
> +       const u8 *data = skb->data;
> +       unsigned int len = skb->len;
> +
> +       while (len >= L2CAP_CMD_HDR_SIZE) {
> +               const struct l2cap_cmd_hdr *cmd = (const void *)data;
> +               u16 cmd_len = le16_to_cpu(cmd->len);
> +
> +               if (cmd->ident && l2cap_sig_cmd_is_req(cmd->code))
> +                       return cmd->ident;
> +
> +               if (cmd_len > len - L2CAP_CMD_HDR_SIZE)
> +                       break;
> +
> +               data += L2CAP_CMD_HDR_SIZE + cmd_len;
> +               len -= L2CAP_CMD_HDR_SIZE + cmd_len;
> +       }

Weird, does the AI come up with this? The id is actually _not_
important because the error code will essentially indicate that the
entire packet was rejected. Therefore, it doesn't matter if the id is
for a request or a response, it still needs rejection if it exceeds
the MTU, so this seems overengineered.

> +       return 0;
> +}
> +
> +static inline void l2cap_sig_send_mtu_rej(struct l2cap_conn *conn, u8 ident)
> +{
> +       struct l2cap_cmd_rej_mtu rej;
> +
> +       rej.reason = cpu_to_le16(L2CAP_REJ_MTU_EXCEEDED);
> +       rej.max_mtu = cpu_to_le16(L2CAP_SIG_MTU);
> +       l2cap_send_cmd(conn, ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
> +}
> +
>  static inline void l2cap_sig_channel(struct l2cap_conn *conn,
>                                      struct sk_buff *skb)
>  {
> @@ -5638,6 +5687,17 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
>         if (hcon->type != ACL_LINK)
>                 goto drop;
>
> +       if (skb->len > L2CAP_SIG_MTU) {
> +               u8 ident = l2cap_sig_first_req_ident(skb);
> +
> +               BT_DBG("signaling packet exceeds MTU");
> +
> +               if (ident)
> +                       l2cap_sig_send_mtu_rej(conn, ident);
> +
> +               goto drop;
> +       }
> +
>         while (skb->len >= L2CAP_CMD_HDR_SIZE) {
>                 u16 len;
>
> --
> 2.53.0
>


-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2] Bluetooth: L2CAP: reject BR/EDR signaling packets over MTUsig
  2026-05-20 14:00 ` Luiz Augusto von Dentz
@ 2026-05-20 14:12   ` Michael Bommarito
  2026-05-20 15:18     ` Luiz Augusto von Dentz
  0 siblings, 1 reply; 12+ messages in thread
From: Michael Bommarito @ 2026-05-20 14:12 UTC (permalink / raw)
  To: Luiz Augusto von Dentz
  Cc: Marcel Holtmann, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, linux-bluetooth, netdev, linux-kernel,
	stable

On Wed, May 20, 2026 at 10:00 AM Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
> Weird, does the AI come up with this? The id is actually _not_
> important because the error code will essentially indicate that the
> entire packet was rejected. Therefore, it doesn't matter if the id is
> for a request or a response, it still needs rejection if it exceeds
> the MTU, so this seems overengineered.

Yes, and I debated this with Claude, but it convinced me that the
lifted helpers were more idiomatic for the actual spec and bt system:
"The identifier shall match the first request command in the L2CAP
packet. If only responses are recognized, the packet shall be silently
discarded."

So if we ever lifted or refactored the code, it would be abundantly
clear/safe to reuse elsewhere.

There is also much shorter version that just peeks skb->data[1] and
exits early if not ident=0 if that's what you're going for.

Just let me know what version you prefer.

Thanks,
Mike

^ permalink raw reply	[flat|nested] 12+ messages in thread

* RE: [v2] Bluetooth: L2CAP: reject BR/EDR signaling packets over MTUsig
  2026-05-20 13:50 [PATCH v2] Bluetooth: L2CAP: reject BR/EDR signaling packets over MTUsig Michael Bommarito
  2026-05-20 14:00 ` Luiz Augusto von Dentz
@ 2026-05-20 14:48 ` bluez.test.bot
  2026-05-21  0:05 ` [PATCH v3] " Michael Bommarito
  2 siblings, 0 replies; 12+ messages in thread
From: bluez.test.bot @ 2026-05-20 14:48 UTC (permalink / raw)
  To: linux-bluetooth, michael.bommarito

[-- Attachment #1: Type: text/plain, Size: 2400 bytes --]

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1098049

---Test result---

Test Summary:
CheckPatch                    FAIL      0.96 seconds
GitLint                       FAIL      0.31 seconds
SubjectPrefix                 PASS      0.12 seconds
BuildKernel                   PASS      27.08 seconds
CheckAllWarning               PASS      30.16 seconds
CheckSparse                   PASS      28.23 seconds
BuildKernel32                 PASS      25.90 seconds
TestRunnerSetup               PASS      577.67 seconds
TestRunner_l2cap-tester       PASS      378.48 seconds
IncrementalBuild              PASS      25.39 seconds

Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[v2] Bluetooth: L2CAP: reject BR/EDR signaling packets over MTUsig
WARNING: The commit message has 'stable@', perhaps it also needs a 'Fixes:' tag?

total: 0 errors, 1 warnings, 0 checks, 79 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/patch/14584036.patch has style problems, please review.

NOTE: Ignored message types: UNKNOWN_COMMIT_ID

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.


##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[v2] Bluetooth: L2CAP: reject BR/EDR signaling packets over MTUsig

WARNING: I3 - ignore-body-lines: gitlint will be switching from using Python regex 'match' (match beginning) to 'search' (match anywhere) semantics. Please review your ignore-body-lines.regex option accordingly. To remove this warning, set general.regex-style-search=True. More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search
23: B1 Line exceeds max length (84>80): "Link: https://lore.kernel.org/r/20260518002800.1361430-1-michael.bommarito@gmail.com"
47: B1 Line exceeds max length (82>80): "v1: https://lore.kernel.org/r/20260518002800.1361430-1-michael.bommarito@gmail.com"


https://github.com/bluez/bluetooth-next/pull/220

---
Regards,
Linux Bluetooth


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2] Bluetooth: L2CAP: reject BR/EDR signaling packets over MTUsig
  2026-05-20 14:12   ` Michael Bommarito
@ 2026-05-20 15:18     ` Luiz Augusto von Dentz
  2026-05-20 15:23       ` Michael Bommarito
  0 siblings, 1 reply; 12+ messages in thread
From: Luiz Augusto von Dentz @ 2026-05-20 15:18 UTC (permalink / raw)
  To: Michael Bommarito
  Cc: Marcel Holtmann, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, linux-bluetooth, netdev, linux-kernel,
	stable

Hi Michael,

On Wed, May 20, 2026 at 10:13 AM Michael Bommarito
<michael.bommarito@gmail.com> wrote:
>
> On Wed, May 20, 2026 at 10:00 AM Luiz Augusto von Dentz
> <luiz.dentz@gmail.com> wrote:
> > Weird, does the AI come up with this? The id is actually _not_
> > important because the error code will essentially indicate that the
> > entire packet was rejected. Therefore, it doesn't matter if the id is
> > for a request or a response, it still needs rejection if it exceeds
> > the MTU, so this seems overengineered.
>
> Yes, and I debated this with Claude, but it convinced me that the
> lifted helpers were more idiomatic for the actual spec and bt system:
> "The identifier shall match the first request command in the L2CAP
> packet. If only responses are recognized, the packet shall be silently
> discarded."

This coming from the spec is priceless because silently discarding the
packets means the remote stack won't know the responses were
discarded, causing the stacks to go out of sync. We also shouldn't
process packets beyond the allowed MTU. Therefore, I strongly disagree
with the spec requiring an identifier on the reject, as this implies
that even if a custom MTU is set, the packet must still be processed
if it exceeds that MTU to find the first request command within it.

> So if we ever lifted or refactored the code, it would be abundantly
> clear/safe to reuse elsewhere.
>
> There is also much shorter version that just peeks skb->data[1] and
> exits early if not ident=0 if that's what you're going for.
>
> Just let me know what version you prefer.
>
> Thanks,
> Mike



-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2] Bluetooth: L2CAP: reject BR/EDR signaling packets over MTUsig
  2026-05-20 15:18     ` Luiz Augusto von Dentz
@ 2026-05-20 15:23       ` Michael Bommarito
  2026-05-20 16:15         ` Luiz Augusto von Dentz
  0 siblings, 1 reply; 12+ messages in thread
From: Michael Bommarito @ 2026-05-20 15:23 UTC (permalink / raw)
  To: Luiz Augusto von Dentz
  Cc: Marcel Holtmann, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, linux-bluetooth, netdev, linux-kernel,
	stable

On Wed, May 20, 2026 at 11:19 AM Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
> This coming from the spec is priceless because silently discarding the
> packets means the remote stack won't know the responses were
> discarded, causing the stacks to go out of sync. We also shouldn't
> process packets beyond the allowed MTU. Therefore, I strongly disagree
> with the spec requiring an identifier on the reject, as this implies
> that even if a custom MTU is set, the packet must still be processed
> if it exceeds that MTU to find the first request command within it.

Should I keep a verbose comment string about this rationale in the
next version?  This seems like something that might trigger questions
in the future if there are issues between Linux <-> noisy/buggy
stacks.

Thanks,
Mike

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2] Bluetooth: L2CAP: reject BR/EDR signaling packets over MTUsig
  2026-05-20 15:23       ` Michael Bommarito
@ 2026-05-20 16:15         ` Luiz Augusto von Dentz
  0 siblings, 0 replies; 12+ messages in thread
From: Luiz Augusto von Dentz @ 2026-05-20 16:15 UTC (permalink / raw)
  To: Michael Bommarito
  Cc: Marcel Holtmann, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, linux-bluetooth, netdev, linux-kernel,
	stable

Hi Michael,

On Wed, May 20, 2026 at 11:23 AM Michael Bommarito
<michael.bommarito@gmail.com> wrote:
>
> On Wed, May 20, 2026 at 11:19 AM Luiz Augusto von Dentz
> <luiz.dentz@gmail.com> wrote:
> > This coming from the spec is priceless because silently discarding the
> > packets means the remote stack won't know the responses were
> > discarded, causing the stacks to go out of sync. We also shouldn't
> > process packets beyond the allowed MTU. Therefore, I strongly disagree
> > with the spec requiring an identifier on the reject, as this implies
> > that even if a custom MTU is set, the packet must still be processed
> > if it exceeds that MTU to find the first request command within it.
>
> Should I keep a verbose comment string about this rationale in the
> next version?  This seems like something that might trigger questions
> in the future if there are issues between Linux <-> noisy/buggy
> stacks.

Yep, be as verbose as possible, and quote the specification whenever necessary.

> Thanks,
> Mike



-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v3] Bluetooth: L2CAP: reject BR/EDR signaling packets over MTUsig
  2026-05-20 13:50 [PATCH v2] Bluetooth: L2CAP: reject BR/EDR signaling packets over MTUsig Michael Bommarito
  2026-05-20 14:00 ` Luiz Augusto von Dentz
  2026-05-20 14:48 ` [v2] " bluez.test.bot
@ 2026-05-21  0:05 ` Michael Bommarito
  2026-05-21 12:51   ` Luiz Augusto von Dentz
  2026-05-21 14:45   ` [PATCH v4] " Michael Bommarito
  2 siblings, 2 replies; 12+ messages in thread
From: Michael Bommarito @ 2026-05-21  0:05 UTC (permalink / raw)
  To: Marcel Holtmann, Luiz Augusto von Dentz
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, linux-bluetooth, netdev, linux-kernel, stable

net/bluetooth/l2cap_core.c:l2cap_sig_channel() accepts BR/EDR
signaling packets up to the channel MTU and dispatches each command
without enforcing the signaling MTU (MTUsig). A Bluetooth BR/EDR peer
within radio range can send a fixed-channel CID 0x0001 packet that is
larger than MTUsig and contains many L2CAP_ECHO_REQ commands before
pairing. In a real-radio stock-kernel run, one 681-byte signaling
packet containing 168 zero-length ECHO_REQ commands made the target
transmit 168 ECHO_RSP frames over about 220 ms.

Impact: a Bluetooth BR/EDR peer within radio range, before pairing, can
force 168 ECHO_RSP frames from one 681-byte fixed-channel signaling
packet containing packed ECHO_REQ commands.

Define Linux's BR/EDR signaling MTU as the spec minimum of 48 bytes and
reject any larger signaling packet with one L2CAP_COMMAND_REJECT_RSP
carrying L2CAP_REJ_MTU_EXCEEDED before any command is dispatched.

The Bluetooth Core spec wording for MTUExceeded says the reject
identifier shall match the first request command in the packet, and
that packets containing only responses shall be silently discarded.
Linux intentionally deviates from that prescription: silently
discarding desynchronizes the peer because the remote stack never
learns its responses were dropped, and locating the first request
command requires walking command headers past MTUsig, i.e. processing
bytes from a packet we have already decided is too large to process.
We therefore always emit one reject and use the identifier from the
first command header (a single fixed-offset byte read), falling back
to zero when the packet is too short to carry a header at all.

The unrestricted BR/EDR signaling parser and ECHO_REQ response path both
trace to the initial git import; no later introducing commit is
available for a Fixes tag.

Cc: stable@vger.kernel.org
Suggested-by: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Link: https://lore.kernel.org/r/20260518002800.1361430-1-michael.bommarito@gmail.com
Link: https://lore.kernel.org/r/20260520135034.1060859-1-michael.bommarito@gmail.com
Assisted-by: Claude:claude-opus-4-7
Assisted-by: Codex:gpt-5-5-xhigh
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
I reproduced the stock behavior with a real-radio BR/EDR ACL link and a
harness that sends a single fixed-channel signaling packet containing
packed zero-length ECHO_REQ commands, and confirmed on a patched kernel
that the same packet now produces one L2CAP_REJ_MTU_EXCEEDED command
reject and zero ECHO_RSP frames. The patched code builds for
net/bluetooth/l2cap_core.o on x86_64 defconfig with W=1. There are no
in-tree Bluetooth selftests that reference l2cap_sig_channel(),
L2CAP_SIG_MTU, or L2CAP_ECHO_REQ.

Changes in v3:
- Drop l2cap_sig_cmd_is_req() and l2cap_sig_first_req_ident(); the
  reject is now unconditional and uses only the first command
  header's identifier byte at a fixed offset. Per Luiz, the spec's
  "match the first request command identifier" rule would require
  parsing past MTUsig, and the spec's "silently discard if only
  responses" rule desynchronizes the peer.
- Replace the v2 walk with a verbose comment quoting the relevant
  Bluetooth Core section and documenting why Linux deviates.

Changes in v2:
- Replace the per-PDU echo-count cap with the MTUsig direction from
  review.
- Reject the whole over-MTUsig signaling packet with one
  L2CAP_REJ_MTU_EXCEEDED command reject.
- Add L2CAP_SIG_MTU and drop over-MTUsig packets when no valid request
  command identifier is found.

v1: https://lore.kernel.org/r/20260518002800.1361430-1-michael.bommarito@gmail.com
v2: https://lore.kernel.org/r/20260520135034.1060859-1-michael.bommarito@gmail.com
---
 include/net/bluetooth/l2cap.h |  1 +
 net/bluetooth/l2cap_core.c    | 47 +++++++++++++++++++++++++++++++++++
 2 files changed, 48 insertions(+)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 5172afee54943..e0a1f2293679a 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -33,6 +33,7 @@
 /* L2CAP defaults */
 #define L2CAP_DEFAULT_MTU		672
 #define L2CAP_DEFAULT_MIN_MTU		48
+#define L2CAP_SIG_MTU			48	/* BR/EDR signaling MTU */
 #define L2CAP_DEFAULT_FLUSH_TO		0xFFFF
 #define L2CAP_EFS_DEFAULT_FLUSH_TO	0xFFFFFFFF
 #define L2CAP_DEFAULT_TX_WINDOW		63
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 7701528f11677..0b1e062057695 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -5618,6 +5618,15 @@ static inline void l2cap_sig_send_rej(struct l2cap_conn *conn, u16 ident)
 	l2cap_send_cmd(conn, ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
 }
 
+static inline void l2cap_sig_send_mtu_rej(struct l2cap_conn *conn, u8 ident)
+{
+	struct l2cap_cmd_rej_mtu rej;
+
+	rej.reason = cpu_to_le16(L2CAP_REJ_MTU_EXCEEDED);
+	rej.max_mtu = cpu_to_le16(L2CAP_SIG_MTU);
+	l2cap_send_cmd(conn, ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
+}
+
 static inline void l2cap_sig_channel(struct l2cap_conn *conn,
 				     struct sk_buff *skb)
 {
@@ -5630,6 +5639,44 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
 	if (hcon->type != ACL_LINK)
 		goto drop;
 
+	/*
+	 * Bluetooth Core v5.4, Vol 3, Part A, Section 4: the BR/EDR
+	 * signaling channel has a fixed signaling MTU (MTUsig) whose
+	 * minimum and default is 48 octets.  Section 4.1 says that on
+	 * an MTUExceeded command reject the identifier "shall match
+	 * the first request command in the L2CAP packet" and that
+	 * packets containing only response commands "shall be
+	 * silently discarded".
+	 *
+	 * Linux intentionally deviates from that prescription:
+	 *
+	 *   1. Silently discarding desynchronizes the peer.  The
+	 *      remote stack never learns its responses were dropped,
+	 *      so any state machine waiting on a paired response
+	 *      stalls until its own timer fires.
+	 *
+	 *   2. Locating "the first request command" requires walking
+	 *      command headers past MTUsig, i.e. processing bytes
+	 *      from a packet we have already decided is too large to
+	 *      process.
+	 *
+	 * Reject every over-MTUsig signaling packet with one
+	 * L2CAP_REJ_MTU_EXCEEDED command reject.  The reject's
+	 * reason field is what tells the peer that the whole packet
+	 * was discarded; the identifier value is informational, so
+	 * we use the identifier from the first command header (a
+	 * single fixed-offset byte read) or zero when the packet is
+	 * too short to carry even one header.
+	 */
+	if (skb->len > L2CAP_SIG_MTU) {
+		u8 ident = (skb->len >= L2CAP_CMD_HDR_SIZE) ?
+			   skb->data[1] : 0;
+
+		BT_DBG("signaling packet exceeds MTU");
+		l2cap_sig_send_mtu_rej(conn, ident);
+		goto drop;
+	}
+
 	while (skb->len >= L2CAP_CMD_HDR_SIZE) {
 		u16 len;
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v3] Bluetooth: L2CAP: reject BR/EDR signaling packets over MTUsig
  2026-05-21  0:05 ` [PATCH v3] " Michael Bommarito
@ 2026-05-21 12:51   ` Luiz Augusto von Dentz
  2026-05-21 14:45   ` [PATCH v4] " Michael Bommarito
  1 sibling, 0 replies; 12+ messages in thread
From: Luiz Augusto von Dentz @ 2026-05-21 12:51 UTC (permalink / raw)
  To: Michael Bommarito
  Cc: Marcel Holtmann, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, linux-bluetooth, netdev, linux-kernel,
	stable

Hi Michael,

On Wed, May 20, 2026 at 8:06 PM Michael Bommarito
<michael.bommarito@gmail.com> wrote:
>
> net/bluetooth/l2cap_core.c:l2cap_sig_channel() accepts BR/EDR
> signaling packets up to the channel MTU and dispatches each command
> without enforcing the signaling MTU (MTUsig). A Bluetooth BR/EDR peer
> within radio range can send a fixed-channel CID 0x0001 packet that is
> larger than MTUsig and contains many L2CAP_ECHO_REQ commands before
> pairing. In a real-radio stock-kernel run, one 681-byte signaling
> packet containing 168 zero-length ECHO_REQ commands made the target
> transmit 168 ECHO_RSP frames over about 220 ms.
>
> Impact: a Bluetooth BR/EDR peer within radio range, before pairing, can
> force 168 ECHO_RSP frames from one 681-byte fixed-channel signaling
> packet containing packed ECHO_REQ commands.
>
> Define Linux's BR/EDR signaling MTU as the spec minimum of 48 bytes and
> reject any larger signaling packet with one L2CAP_COMMAND_REJECT_RSP
> carrying L2CAP_REJ_MTU_EXCEEDED before any command is dispatched.
>
> The Bluetooth Core spec wording for MTUExceeded says the reject
> identifier shall match the first request command in the packet, and
> that packets containing only responses shall be silently discarded.
> Linux intentionally deviates from that prescription: silently
> discarding desynchronizes the peer because the remote stack never
> learns its responses were dropped, and locating the first request
> command requires walking command headers past MTUsig, i.e. processing
> bytes from a packet we have already decided is too large to process.
> We therefore always emit one reject and use the identifier from the
> first command header (a single fixed-offset byte read), falling back
> to zero when the packet is too short to carry a header at all.
>
> The unrestricted BR/EDR signaling parser and ECHO_REQ response path both
> trace to the initial git import; no later introducing commit is
> available for a Fixes tag.
>
> Cc: stable@vger.kernel.org
> Suggested-by: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
> Link: https://lore.kernel.org/r/20260518002800.1361430-1-michael.bommarito@gmail.com
> Link: https://lore.kernel.org/r/20260520135034.1060859-1-michael.bommarito@gmail.com
> Assisted-by: Claude:claude-opus-4-7
> Assisted-by: Codex:gpt-5-5-xhigh
> Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
> ---
> I reproduced the stock behavior with a real-radio BR/EDR ACL link and a
> harness that sends a single fixed-channel signaling packet containing
> packed zero-length ECHO_REQ commands, and confirmed on a patched kernel
> that the same packet now produces one L2CAP_REJ_MTU_EXCEEDED command
> reject and zero ECHO_RSP frames. The patched code builds for
> net/bluetooth/l2cap_core.o on x86_64 defconfig with W=1. There are no
> in-tree Bluetooth selftests that reference l2cap_sig_channel(),
> L2CAP_SIG_MTU, or L2CAP_ECHO_REQ.
>
> Changes in v3:
> - Drop l2cap_sig_cmd_is_req() and l2cap_sig_first_req_ident(); the
>   reject is now unconditional and uses only the first command
>   header's identifier byte at a fixed offset. Per Luiz, the spec's
>   "match the first request command identifier" rule would require
>   parsing past MTUsig, and the spec's "silently discard if only
>   responses" rule desynchronizes the peer.
> - Replace the v2 walk with a verbose comment quoting the relevant
>   Bluetooth Core section and documenting why Linux deviates.
>
> Changes in v2:
> - Replace the per-PDU echo-count cap with the MTUsig direction from
>   review.
> - Reject the whole over-MTUsig signaling packet with one
>   L2CAP_REJ_MTU_EXCEEDED command reject.
> - Add L2CAP_SIG_MTU and drop over-MTUsig packets when no valid request
>   command identifier is found.
>
> v1: https://lore.kernel.org/r/20260518002800.1361430-1-michael.bommarito@gmail.com
> v2: https://lore.kernel.org/r/20260520135034.1060859-1-michael.bommarito@gmail.com
> ---
>  include/net/bluetooth/l2cap.h |  1 +
>  net/bluetooth/l2cap_core.c    | 47 +++++++++++++++++++++++++++++++++++
>  2 files changed, 48 insertions(+)
>
> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> index 5172afee54943..e0a1f2293679a 100644
> --- a/include/net/bluetooth/l2cap.h
> +++ b/include/net/bluetooth/l2cap.h
> @@ -33,6 +33,7 @@
>  /* L2CAP defaults */
>  #define L2CAP_DEFAULT_MTU              672
>  #define L2CAP_DEFAULT_MIN_MTU          48
> +#define L2CAP_SIG_MTU                  48      /* BR/EDR signaling MTU */
>  #define L2CAP_DEFAULT_FLUSH_TO         0xFFFF
>  #define L2CAP_EFS_DEFAULT_FLUSH_TO     0xFFFFFFFF
>  #define L2CAP_DEFAULT_TX_WINDOW                63
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index 7701528f11677..0b1e062057695 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -5618,6 +5618,15 @@ static inline void l2cap_sig_send_rej(struct l2cap_conn *conn, u16 ident)
>         l2cap_send_cmd(conn, ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
>  }
>
> +static inline void l2cap_sig_send_mtu_rej(struct l2cap_conn *conn, u8 ident)
> +{
> +       struct l2cap_cmd_rej_mtu rej;
> +
> +       rej.reason = cpu_to_le16(L2CAP_REJ_MTU_EXCEEDED);
> +       rej.max_mtu = cpu_to_le16(L2CAP_SIG_MTU);
> +       l2cap_send_cmd(conn, ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
> +}
> +
>  static inline void l2cap_sig_channel(struct l2cap_conn *conn,
>                                      struct sk_buff *skb)
>  {
> @@ -5630,6 +5639,44 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
>         if (hcon->type != ACL_LINK)
>                 goto drop;
>
> +       /*
> +        * Bluetooth Core v5.4, Vol 3, Part A, Section 4: the BR/EDR
> +        * signaling channel has a fixed signaling MTU (MTUsig) whose
> +        * minimum and default is 48 octets.  Section 4.1 says that on
> +        * an MTUExceeded command reject the identifier "shall match
> +        * the first request command in the L2CAP packet" and that
> +        * packets containing only response commands "shall be
> +        * silently discarded".
> +        *
> +        * Linux intentionally deviates from that prescription:
> +        *
> +        *   1. Silently discarding desynchronizes the peer.  The
> +        *      remote stack never learns its responses were dropped,
> +        *      so any state machine waiting on a paired response
> +        *      stalls until its own timer fires.
> +        *
> +        *   2. Locating "the first request command" requires walking
> +        *      command headers past MTUsig, i.e. processing bytes
> +        *      from a packet we have already decided is too large to
> +        *      process.
> +        *
> +        * Reject every over-MTUsig signaling packet with one
> +        * L2CAP_REJ_MTU_EXCEEDED command reject.  The reject's
> +        * reason field is what tells the peer that the whole packet
> +        * was discarded; the identifier value is informational, so
> +        * we use the identifier from the first command header (a
> +        * single fixed-offset byte read) or zero when the packet is
> +        * too short to carry even one header.
> +        */
> +       if (skb->len > L2CAP_SIG_MTU) {
> +               u8 ident = (skb->len >= L2CAP_CMD_HDR_SIZE) ?
> +                          skb->data[1] : 0;

Checking L2CAP_CMD_HDR_SIZE after L2CAP_SIG_MTU seems unnecessary, the
latter should always be large enough to accommodate a header.

> +
> +               BT_DBG("signaling packet exceeds MTU");

I'd make it print skb->len and L2CAP_SIG_MTU e.g. %u > %u, skb->len,
L2CAP_SIG_MTU.

> +               l2cap_sig_send_mtu_rej(conn, ident);
> +               goto drop;
> +       }
> +
>         while (skb->len >= L2CAP_CMD_HDR_SIZE) {
>                 u16 len;
>
> --
> 2.53.0
>


-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v4] Bluetooth: L2CAP: reject BR/EDR signaling packets over MTUsig
  2026-05-21  0:05 ` [PATCH v3] " Michael Bommarito
  2026-05-21 12:51   ` Luiz Augusto von Dentz
@ 2026-05-21 14:45   ` Michael Bommarito
  2026-05-21 17:23     ` [v4] " bluez.test.bot
  2026-05-21 19:08     ` bluez.test.bot
  1 sibling, 2 replies; 12+ messages in thread
From: Michael Bommarito @ 2026-05-21 14:45 UTC (permalink / raw)
  To: Marcel Holtmann, Luiz Augusto von Dentz; +Cc: linux-bluetooth

net/bluetooth/l2cap_core.c:l2cap_sig_channel() accepts BR/EDR
signaling packets up to the channel MTU and dispatches each command
without enforcing the signaling MTU (MTUsig). A Bluetooth BR/EDR peer
within radio range can send a fixed-channel CID 0x0001 packet that is
larger than MTUsig and contains many L2CAP_ECHO_REQ commands before
pairing. In a real-radio stock-kernel run, one 681-byte signaling
packet containing 168 zero-length ECHO_REQ commands made the target
transmit 168 ECHO_RSP frames over about 220 ms.

Impact: a Bluetooth BR/EDR peer within radio range, before pairing, can
force 168 ECHO_RSP frames from one 681-byte fixed-channel signaling
packet containing packed ECHO_REQ commands.

Define Linux's BR/EDR signaling MTU as the spec minimum of 48 bytes and
reject any larger signaling packet with one L2CAP_COMMAND_REJECT_RSP
carrying L2CAP_REJ_MTU_EXCEEDED before any command is dispatched.

The Bluetooth Core spec wording for MTUExceeded says the reject
identifier shall match the first request command in the packet, and
that packets containing only responses shall be silently discarded.
Linux intentionally deviates from that prescription: silently
discarding desynchronizes the peer because the remote stack never
learns its responses were dropped, and locating the first request
command requires walking command headers past MTUsig, i.e. processing
bytes from a packet we have already decided is too large to process.
We therefore always emit one reject and use the identifier from the
first command header, a single fixed-offset byte read.

The unrestricted BR/EDR signaling parser and ECHO_REQ response path both
trace to the initial git import; no later introducing commit is
available for a Fixes tag.

Cc: stable@vger.kernel.org
Suggested-by: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Link: https://lore.kernel.org/r/20260518002800.1361430-1-michael.bommarito@gmail.com
Link: https://lore.kernel.org/r/20260520135034.1060859-1-michael.bommarito@gmail.com
Link: https://lore.kernel.org/r/20260521000555.3712030-1-michael.bommarito@gmail.com
Assisted-by: Claude:claude-opus-4-7
Assisted-by: Codex:gpt-5-5-xhigh
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
I reproduced the stock behavior with a real-radio BR/EDR ACL link and a
harness that sends a single fixed-channel signaling packet containing
packed zero-length ECHO_REQ commands, and confirmed on a patched kernel
that the same packet now produces one L2CAP_REJ_MTU_EXCEEDED command
reject and zero ECHO_RSP frames. The patched code builds for
net/bluetooth/l2cap_core.o on x86_64 defconfig with W=1. There are no
in-tree Bluetooth selftests that reference l2cap_sig_channel(),
L2CAP_SIG_MTU, or L2CAP_ECHO_REQ.

Changes in v4:
- Drop the unreachable short-header fallback before reading the first
  command identifier; any packet over L2CAP_SIG_MTU is large enough to
  carry an L2CAP command header.
- Print both skb->len and L2CAP_SIG_MTU in the over-MTUsig debug trace.

Changes in v3:
- Drop l2cap_sig_cmd_is_req() and l2cap_sig_first_req_ident(); the
  reject is now unconditional and uses only the first command
  header's identifier byte at a fixed offset. Per Luiz, the spec's
  "match the first request command identifier" rule would require
  parsing past MTUsig, and the spec's "silently discard if only
  responses" rule desynchronizes the peer.
- Replace the v2 walk with a verbose comment quoting the relevant
  Bluetooth Core section and documenting why Linux deviates.

Changes in v2:
- Replace the per-PDU echo-count cap with the MTUsig direction from
  review.
- Reject the whole over-MTUsig signaling packet with one
  L2CAP_REJ_MTU_EXCEEDED command reject.
- Add L2CAP_SIG_MTU and drop over-MTUsig packets when no valid request
  command identifier is found.

v1: https://lore.kernel.org/r/20260518002800.1361430-1-michael.bommarito@gmail.com
v2: https://lore.kernel.org/r/20260520135034.1060859-1-michael.bommarito@gmail.com
v3: https://lore.kernel.org/r/20260521000555.3712030-1-michael.bommarito@gmail.com
---
 include/net/bluetooth/l2cap.h |  1 +
 net/bluetooth/l2cap_core.c    | 46 +++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 5172afee54943..e0a1f2293679a 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -33,6 +33,7 @@
 /* L2CAP defaults */
 #define L2CAP_DEFAULT_MTU		672
 #define L2CAP_DEFAULT_MIN_MTU		48
+#define L2CAP_SIG_MTU			48	/* BR/EDR signaling MTU */
 #define L2CAP_DEFAULT_FLUSH_TO		0xFFFF
 #define L2CAP_EFS_DEFAULT_FLUSH_TO	0xFFFFFFFF
 #define L2CAP_DEFAULT_TX_WINDOW		63
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 7701528f11677..17ee28a2ee78e 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -5618,6 +5618,15 @@ static inline void l2cap_sig_send_rej(struct l2cap_conn *conn, u16 ident)
 	l2cap_send_cmd(conn, ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
 }
 
+static inline void l2cap_sig_send_mtu_rej(struct l2cap_conn *conn, u8 ident)
+{
+	struct l2cap_cmd_rej_mtu rej;
+
+	rej.reason = cpu_to_le16(L2CAP_REJ_MTU_EXCEEDED);
+	rej.max_mtu = cpu_to_le16(L2CAP_SIG_MTU);
+	l2cap_send_cmd(conn, ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
+}
+
 static inline void l2cap_sig_channel(struct l2cap_conn *conn,
 				     struct sk_buff *skb)
 {
@@ -5630,6 +5639,43 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
 	if (hcon->type != ACL_LINK)
 		goto drop;
 
+	/*
+	 * Bluetooth Core v5.4, Vol 3, Part A, Section 4: the BR/EDR
+	 * signaling channel has a fixed signaling MTU (MTUsig) whose
+	 * minimum and default is 48 octets.  Section 4.1 says that on
+	 * an MTUExceeded command reject the identifier "shall match
+	 * the first request command in the L2CAP packet" and that
+	 * packets containing only response commands "shall be
+	 * silently discarded".
+	 *
+	 * Linux intentionally deviates from that prescription:
+	 *
+	 *   1. Silently discarding desynchronizes the peer.  The
+	 *      remote stack never learns its responses were dropped,
+	 *      so any state machine waiting on a paired response
+	 *      stalls until its own timer fires.
+	 *
+	 *   2. Locating "the first request command" requires walking
+	 *      command headers past MTUsig, i.e. processing bytes
+	 *      from a packet we have already decided is too large to
+	 *      process.
+	 *
+	 * Reject every over-MTUsig signaling packet with one
+	 * L2CAP_REJ_MTU_EXCEEDED command reject.  The reject's
+	 * reason field is what tells the peer that the whole packet
+	 * was discarded; the identifier value is informational, so
+	 * we use the identifier from the first command header, a
+	 * single fixed-offset byte read.
+	 */
+	if (skb->len > L2CAP_SIG_MTU) {
+		u8 ident = skb->data[1];
+
+		BT_DBG("signaling packet exceeds MTU: %u > %u",
+		       skb->len, L2CAP_SIG_MTU);
+		l2cap_sig_send_mtu_rej(conn, ident);
+		goto drop;
+	}
+
 	while (skb->len >= L2CAP_CMD_HDR_SIZE) {
 		u16 len;
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* RE: [v4] Bluetooth: L2CAP: reject BR/EDR signaling packets over MTUsig
  2026-05-21 14:45   ` [PATCH v4] " Michael Bommarito
@ 2026-05-21 17:23     ` bluez.test.bot
  2026-05-21 19:08     ` bluez.test.bot
  1 sibling, 0 replies; 12+ messages in thread
From: bluez.test.bot @ 2026-05-21 17:23 UTC (permalink / raw)
  To: linux-bluetooth, michael.bommarito

[-- Attachment #1: Type: text/plain, Size: 3443 bytes --]

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1098859

---Test result---

Test Summary:
CheckPatch                    FAIL      0.80 seconds
VerifyFixes                   PASS      0.48 seconds
VerifySignedoff               FAIL      0.22 seconds
GitLint                       FAIL      0.21 seconds
SubjectPrefix                 PASS      0.07 seconds
BuildKernel                   PASS      27.63 seconds
CheckAllWarning               PASS      29.12 seconds
CheckSparse                   PASS      27.57 seconds
BuildKernel32                 PASS      25.63 seconds
TestRunnerSetup               PASS      578.13 seconds
TestRunner_l2cap-tester       PASS      61.59 seconds
IncrementalBuild              PASS      24.97 seconds

Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[v4] Bluetooth: L2CAP: reject BR/EDR signaling packets over MTUsig
WARNING: The commit message has 'stable@', perhaps it also needs a 'Fixes:' tag?

total: 0 errors, 1 warnings, 0 checks, 65 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/patch/14587556.patch has style problems, please review.

NOTE: Ignored message types: UNKNOWN_COMMIT_ID

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.


##############################
Test: VerifySignedoff - FAIL
Desc: Verify Signed-off-by chain
Output:
Commit e9a1f367f155 ("Merge fec51f9217e4a020fb088da178104f4d925554fb into 133f77de6bca4b8873bcf67e3469bf1b28771a68")
	author Signed-off-by missing
	committer Signed-off-by missing
	author email:    61600790+BluezTestBot@users.noreply.github.com
	committer email: noreply@github.com
	

Errors in tree with Signed-off-by, please fix!

##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[v4] Bluetooth: L2CAP: reject BR/EDR signaling packets over MTUsig

WARNING: I3 - ignore-body-lines: gitlint will be switching from using Python regex 'match' (match beginning) to 'search' (match anywhere) semantics. Please review your ignore-body-lines.regex option accordingly. To remove this warning, set general.regex-style-search=True. More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search
37: B1 Line exceeds max length (84>80): "Link: https://lore.kernel.org/r/20260518002800.1361430-1-michael.bommarito@gmail.com"
38: B1 Line exceeds max length (84>80): "Link: https://lore.kernel.org/r/20260520135034.1060859-1-michael.bommarito@gmail.com"
39: B1 Line exceeds max length (84>80): "Link: https://lore.kernel.org/r/20260521000555.3712030-1-michael.bommarito@gmail.com"
77: B1 Line exceeds max length (82>80): "v1: https://lore.kernel.org/r/20260518002800.1361430-1-michael.bommarito@gmail.com"
78: B1 Line exceeds max length (82>80): "v2: https://lore.kernel.org/r/20260520135034.1060859-1-michael.bommarito@gmail.com"
79: B1 Line exceeds max length (82>80): "v3: https://lore.kernel.org/r/20260521000555.3712030-1-michael.bommarito@gmail.com"


https://github.com/bluez/bluetooth-next/pull/231

---
Regards,
Linux Bluetooth


^ permalink raw reply	[flat|nested] 12+ messages in thread

* RE: [v4] Bluetooth: L2CAP: reject BR/EDR signaling packets over MTUsig
  2026-05-21 14:45   ` [PATCH v4] " Michael Bommarito
  2026-05-21 17:23     ` [v4] " bluez.test.bot
@ 2026-05-21 19:08     ` bluez.test.bot
  1 sibling, 0 replies; 12+ messages in thread
From: bluez.test.bot @ 2026-05-21 19:08 UTC (permalink / raw)
  To: linux-bluetooth, michael.bommarito

[-- Attachment #1: Type: text/plain, Size: 1747 bytes --]

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1098859

---Test result---

Test Summary:
CheckPatch                    FAIL      1.00 seconds
VerifyFixes                   PASS      0.14 seconds
VerifySignedoff               PASS      0.14 seconds
GitLint                       PASS      0.35 seconds
SubjectPrefix                 PASS      0.13 seconds
BuildKernel                   PASS      27.44 seconds
CheckAllWarning               PASS      29.96 seconds
CheckSparse                   PASS      28.91 seconds
BuildKernel32                 PASS      28.26 seconds
TestRunnerSetup               PASS      587.14 seconds
TestRunner_l2cap-tester       PASS      59.17 seconds
IncrementalBuild              PASS      25.06 seconds

Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[v4] Bluetooth: L2CAP: reject BR/EDR signaling packets over MTUsig
WARNING: The commit message has 'stable@', perhaps it also needs a 'Fixes:' tag?

total: 0 errors, 1 warnings, 0 checks, 65 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/patch/14587556.patch has style problems, please review.

NOTE: Ignored message types: UNKNOWN_COMMIT_ID

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.




https://github.com/bluez/bluetooth-next/pull/231

---
Regards,
Linux Bluetooth


^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2026-05-21 19:08 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-20 13:50 [PATCH v2] Bluetooth: L2CAP: reject BR/EDR signaling packets over MTUsig Michael Bommarito
2026-05-20 14:00 ` Luiz Augusto von Dentz
2026-05-20 14:12   ` Michael Bommarito
2026-05-20 15:18     ` Luiz Augusto von Dentz
2026-05-20 15:23       ` Michael Bommarito
2026-05-20 16:15         ` Luiz Augusto von Dentz
2026-05-20 14:48 ` [v2] " bluez.test.bot
2026-05-21  0:05 ` [PATCH v3] " Michael Bommarito
2026-05-21 12:51   ` Luiz Augusto von Dentz
2026-05-21 14:45   ` [PATCH v4] " Michael Bommarito
2026-05-21 17:23     ` [v4] " bluez.test.bot
2026-05-21 19:08     ` bluez.test.bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox