* [PATCH] Bluetooth: L2CAP: handle zero txwin_size in ERTM RFC option
@ 2026-04-17 22:16 Michael Bommarito
2026-04-20 19:06 ` Luiz Augusto von Dentz
0 siblings, 1 reply; 5+ messages in thread
From: Michael Bommarito @ 2026-04-17 22:16 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz
Cc: Mat Martineau, Hyunwoo Kim, linux-bluetooth, linux-kernel, stable
Bluetooth L2CAP ERTM configuration (RFC option, type 0x04) carries an
unsigned 8-bit txwin_size field. Core Spec v5.3, Vol 3 Part A, section
5.4 specifies a valid range of 1..63 (or 1..0x3fff under the Extended
Window Size extension). A peer-supplied value of zero is out of spec
but the current l2cap_parse_conf_req() path stores it into
chan->remote_tx_win unchanged whenever CONF_EWS_RECV is not set.
The zero then reaches l2cap_seq_list_init(size = 0), which computes
alloc_size = roundup_pow_of_two(size). Per include/linux/log2.h the
result is undefined for size == 0. The runtime behaviour is
architecture-dependent:
* x86, arm64, RISC-V, MIPS, s390x, LoongArch: the ISA shift
instruction masks the shift count by (word_bits - 1), so
1UL << word_bits evaluates to 1 rather than 0.
kmalloc_array(1, sizeof(u16)) returns a valid 2-byte slab
allocation with seq_list->mask == 0. ERTM retransmission
silently collapses every reqseq onto slot 0 (correctness bug,
no memory corruption).
* ARMv7 (AArch32), PowerPC 32-bit (slw), PowerPC 64-bit (sld):
the shift instruction returns 0 for shift counts >= word
width. 1UL << word_bits therefore evaluates to 0,
kmalloc_array(0, sizeof(u16)) returns ZERO_SIZE_PTR, and
seq_list->mask becomes ULONG_MAX. Any subsequent access to
seq_list->list dereferences ZERO_SIZE_PTR (0x10), which is
always an unmapped low-memory address, and the kernel Oopses.
This is a remote kernel panic driven by a single peer-sent
CONFIG_REQ; it is not a demonstrated code-execution primitive.
Verified on qemu-system-arm -M virt -cpu cortex-a15 (ARMv7-A, same
LSL register-shift semantics as the Cortex-A9 class still shipping
in automotive infotainment on NXP i.MX6 with long-term availability
through 2028). A KASAN-inline kernel built from mainline panics in
l2cap_seq_list_init on the first peer CONFIG_REQ carrying
mode = L2CAP_MODE_ERTM and txwin_size = 0:
Unable to handle kernel paging request at virtual address
9f000002 when read
Internal error: Oops: 5 [#1] SMP ARM
PC is at l2cap_seq_list_init+0x140/0x28c
r2 : 00000010 r1 : ffffffff
Register r2 information: zero-size pointer
Mode SVC_32 ISA ARM
Call trace:
l2cap_seq_list_init from l2cap_ertm_init+0x588/0x758
l2cap_ertm_init from l2cap_config_rsp+0xeac/0x1158
l2cap_config_rsp from l2cap_recv_frame+0x1260/0x8000
l2cap_recv_frame from l2cap_recv_acldata+0xb78/0xdb0
l2cap_recv_acldata from hci_rx_work
r2 = 0x10 is ZERO_SIZE_PTR (the kernel's own decoder annotates it
as such). r1 = 0xFFFFFFFF is seq_list->mask after the 0 - 1
underflow. Faulting address 0x9f000002 is the KASAN shadow for
pointer 0x10 (shadow_offset 0x9f000000 + (0x10 >> 3)).
Trigger is one peer-supplied CONFIG_REQ on an L2CAP ERTM channel;
no local privileges required, no pairing required, no local
interaction beyond being within BR/EDR radio range of an affected
host.
Fix in two places:
* l2cap_parse_conf_req(): when the peer sends txwin_size = 0 in
the RFC option, clamp it up to L2CAP_DEFAULT_TX_WINDOW before
the chan->remote_tx_win assignment. This matches the existing
clamp on the CONF_EWS_RECV branch in the same function and
mirrors the shape of commit 25f420a0d4cf ("Bluetooth: L2CAP:
Fix ERTM re-init and zero pdu_len infinite loop") for the
sibling RFC max_pdu_size field. This is the primary fix: it
prevents zero from ever reaching l2cap_seq_list_init() on the
normal config path.
* l2cap_seq_list_init(): return -EINVAL on size == 0 as a
defence-in-depth check for any current or future caller that
might pass an unclamped value. The existing error-propagation
in l2cap_ertm_init() and its callers already tears the channel
down on error, so the peer simply loses the ERTM channel
rather than silently corrupting an unmapped ZERO_SIZE_PTR
allocation.
Related but distinct from commit 25f420a0d4cf ("Bluetooth: L2CAP:
Fix ERTM re-init and zero pdu_len infinite loop") which addressed
the sibling zero-value issue on the RFC max_pdu_size field.
Fixes: 3c588192b5e5 ("Bluetooth: Add the l2cap_seq_list structure for tracking frames")
Cc: stable@vger.kernel.org
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Assisted-by: Claude:claude-opus-4-7
---
net/bluetooth/l2cap_core.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 95c65fece39b..b2fe094263ca 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -323,6 +323,17 @@ static int l2cap_seq_list_init(struct l2cap_seq_list *seq_list, u16 size)
{
size_t alloc_size, i;
+ /*
+ * A peer may send an ERTM RFC option with txwin_size = 0, which
+ * propagates here as size = 0. roundup_pow_of_two(0) is
+ * documented UB (see include/linux/log2.h) and produces a
+ * semantically broken seq_list that silently drops every
+ * retransmission slot. Reject size = 0 explicitly so the caller
+ * (l2cap_ertm_init) tears the channel down cleanly instead.
+ */
+ if (!size)
+ return -EINVAL;
+
/* Allocated size is a power of 2 to map sequence numbers
* (which may be up to 14 bits) in to a smaller array that is
* sized for the negotiated ERTM transmit windows.
@@ -3593,6 +3604,17 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data
break;
case L2CAP_MODE_ERTM:
+ /*
+ * Peer-supplied RFC txwin_size = 0 is out of spec
+ * (Core Spec v5.3 Vol 3 Part A 5.4: ERTM tx window
+ * range is 1..63, or 1..0x3fff with EWS). Clamp up
+ * to the default window so the subsequent
+ * l2cap_seq_list_init(remote_tx_win) does not
+ * receive a zero size.
+ */
+ if (!rfc.txwin_size)
+ rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
+
if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
chan->remote_tx_win = rfc.txwin_size;
else
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [PATCH] Bluetooth: L2CAP: handle zero txwin_size in ERTM RFC option 2026-04-17 22:16 [PATCH] Bluetooth: L2CAP: handle zero txwin_size in ERTM RFC option Michael Bommarito @ 2026-04-20 19:06 ` Luiz Augusto von Dentz 2026-04-21 13:56 ` [PATCH v2 0/2] Bluetooth: L2CAP: fix zero txwin_size handling and repeated CONFIG_RSP re-init Michael Bommarito ` (2 more replies) 0 siblings, 3 replies; 5+ messages in thread From: Luiz Augusto von Dentz @ 2026-04-20 19:06 UTC (permalink / raw) To: Michael Bommarito Cc: Marcel Holtmann, Mat Martineau, Hyunwoo Kim, linux-bluetooth, linux-kernel, stable Hi Michael, On Fri, Apr 17, 2026 at 6:16 PM Michael Bommarito <michael.bommarito@gmail.com> wrote: > > Bluetooth L2CAP ERTM configuration (RFC option, type 0x04) carries an > unsigned 8-bit txwin_size field. Core Spec v5.3, Vol 3 Part A, section > 5.4 specifies a valid range of 1..63 (or 1..0x3fff under the Extended > Window Size extension). A peer-supplied value of zero is out of spec > but the current l2cap_parse_conf_req() path stores it into > chan->remote_tx_win unchanged whenever CONF_EWS_RECV is not set. > > The zero then reaches l2cap_seq_list_init(size = 0), which computes > alloc_size = roundup_pow_of_two(size). Per include/linux/log2.h the > result is undefined for size == 0. The runtime behaviour is > architecture-dependent: > > * x86, arm64, RISC-V, MIPS, s390x, LoongArch: the ISA shift > instruction masks the shift count by (word_bits - 1), so > 1UL << word_bits evaluates to 1 rather than 0. > kmalloc_array(1, sizeof(u16)) returns a valid 2-byte slab > allocation with seq_list->mask == 0. ERTM retransmission > silently collapses every reqseq onto slot 0 (correctness bug, > no memory corruption). > > * ARMv7 (AArch32), PowerPC 32-bit (slw), PowerPC 64-bit (sld): > the shift instruction returns 0 for shift counts >= word > width. 1UL << word_bits therefore evaluates to 0, > kmalloc_array(0, sizeof(u16)) returns ZERO_SIZE_PTR, and > seq_list->mask becomes ULONG_MAX. Any subsequent access to > seq_list->list dereferences ZERO_SIZE_PTR (0x10), which is > always an unmapped low-memory address, and the kernel Oopses. > This is a remote kernel panic driven by a single peer-sent > CONFIG_REQ; it is not a demonstrated code-execution primitive. > > Verified on qemu-system-arm -M virt -cpu cortex-a15 (ARMv7-A, same > LSL register-shift semantics as the Cortex-A9 class still shipping > in automotive infotainment on NXP i.MX6 with long-term availability > through 2028). A KASAN-inline kernel built from mainline panics in > l2cap_seq_list_init on the first peer CONFIG_REQ carrying > mode = L2CAP_MODE_ERTM and txwin_size = 0: > > Unable to handle kernel paging request at virtual address > 9f000002 when read > Internal error: Oops: 5 [#1] SMP ARM > PC is at l2cap_seq_list_init+0x140/0x28c > r2 : 00000010 r1 : ffffffff > Register r2 information: zero-size pointer > Mode SVC_32 ISA ARM > Call trace: > l2cap_seq_list_init from l2cap_ertm_init+0x588/0x758 > l2cap_ertm_init from l2cap_config_rsp+0xeac/0x1158 > l2cap_config_rsp from l2cap_recv_frame+0x1260/0x8000 > l2cap_recv_frame from l2cap_recv_acldata+0xb78/0xdb0 > l2cap_recv_acldata from hci_rx_work > > r2 = 0x10 is ZERO_SIZE_PTR (the kernel's own decoder annotates it > as such). r1 = 0xFFFFFFFF is seq_list->mask after the 0 - 1 > underflow. Faulting address 0x9f000002 is the KASAN shadow for > pointer 0x10 (shadow_offset 0x9f000000 + (0x10 >> 3)). > > Trigger is one peer-supplied CONFIG_REQ on an L2CAP ERTM channel; > no local privileges required, no pairing required, no local > interaction beyond being within BR/EDR radio range of an affected > host. > > Fix in two places: > > * l2cap_parse_conf_req(): when the peer sends txwin_size = 0 in > the RFC option, clamp it up to L2CAP_DEFAULT_TX_WINDOW before > the chan->remote_tx_win assignment. This matches the existing > clamp on the CONF_EWS_RECV branch in the same function and > mirrors the shape of commit 25f420a0d4cf ("Bluetooth: L2CAP: > Fix ERTM re-init and zero pdu_len infinite loop") for the > sibling RFC max_pdu_size field. This is the primary fix: it > prevents zero from ever reaching l2cap_seq_list_init() on the > normal config path. > > * l2cap_seq_list_init(): return -EINVAL on size == 0 as a > defence-in-depth check for any current or future caller that > might pass an unclamped value. The existing error-propagation > in l2cap_ertm_init() and its callers already tears the channel > down on error, so the peer simply loses the ERTM channel > rather than silently corrupting an unmapped ZERO_SIZE_PTR > allocation. > > Related but distinct from commit 25f420a0d4cf ("Bluetooth: L2CAP: > Fix ERTM re-init and zero pdu_len infinite loop") which addressed > the sibling zero-value issue on the RFC max_pdu_size field. > > Fixes: 3c588192b5e5 ("Bluetooth: Add the l2cap_seq_list structure for tracking frames") > Cc: stable@vger.kernel.org > Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com> > Assisted-by: Claude:claude-opus-4-7 > --- > net/bluetooth/l2cap_core.c | 22 ++++++++++++++++++++++ > 1 file changed, 22 insertions(+) > > diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c > index 95c65fece39b..b2fe094263ca 100644 > --- a/net/bluetooth/l2cap_core.c > +++ b/net/bluetooth/l2cap_core.c > @@ -323,6 +323,17 @@ static int l2cap_seq_list_init(struct l2cap_seq_list *seq_list, u16 size) > { > size_t alloc_size, i; > > + /* > + * A peer may send an ERTM RFC option with txwin_size = 0, which > + * propagates here as size = 0. roundup_pow_of_two(0) is > + * documented UB (see include/linux/log2.h) and produces a > + * semantically broken seq_list that silently drops every > + * retransmission slot. Reject size = 0 explicitly so the caller > + * (l2cap_ertm_init) tears the channel down cleanly instead. > + */ > + if (!size) > + return -EINVAL; > + > /* Allocated size is a power of 2 to map sequence numbers > * (which may be up to 14 bits) in to a smaller array that is > * sized for the negotiated ERTM transmit windows. > @@ -3593,6 +3604,17 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data > break; > > case L2CAP_MODE_ERTM: > + /* > + * Peer-supplied RFC txwin_size = 0 is out of spec > + * (Core Spec v5.3 Vol 3 Part A 5.4: ERTM tx window > + * range is 1..63, or 1..0x3fff with EWS). Clamp up > + * to the default window so the subsequent > + * l2cap_seq_list_init(remote_tx_win) does not > + * receive a zero size. > + */ > + if (!rfc.txwin_size) > + rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW; > + > if (!test_bit(CONF_EWS_RECV, &chan->conf_state)) > chan->remote_tx_win = rfc.txwin_size; > else > -- > 2.53.0 https://sashiko.dev/#/patchset/20260417221628.1674866-1-michael.bommarito%40gmail.com We should probably fix the double free if it can occur; perhaps the others should be addressed in different patches. -- Luiz Augusto von Dentz ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 0/2] Bluetooth: L2CAP: fix zero txwin_size handling and repeated CONFIG_RSP re-init 2026-04-20 19:06 ` Luiz Augusto von Dentz @ 2026-04-21 13:56 ` Michael Bommarito 2026-04-21 13:56 ` [PATCH v2 1/2] Bluetooth: L2CAP: handle zero txwin_size in ERTM RFC option Michael Bommarito 2026-04-21 13:56 ` [PATCH v2 2/2] Bluetooth: L2CAP: skip ERTM re-init on repeated CONFIG_RSP Michael Bommarito 2 siblings, 0 replies; 5+ messages in thread From: Michael Bommarito @ 2026-04-21 13:56 UTC (permalink / raw) To: Marcel Holtmann, Luiz Augusto von Dentz Cc: Mat Martineau, Hyunwoo Kim, linux-bluetooth, linux-kernel, stable Hi Luiz, Thanks for the review. v1 mixed the original zero-txwin fix with a defensive l2cap_seq_list_init(size == 0) error return. Re-checking that path made it clear the reroll should be split: 1. keep the original report focused on zero txwin_size, but fix it by normalizing zero window values at the actual inputs to the ERTM state machine and by making sequence-list teardown idempotent, rather than by introducing a new init-time failure path 2. handle the separate repeated-CONFIG_RSP ERTM re-init bug in its own patch, matching the BT_CONNECTED guard that commit 25f420a0d4cf already added on the CONFIG_REQ side While auditing the Sashiko comments, I also checked the claimed CONF_EWS_RECV bypass. I did not carry that theory into v2: in this tree CONF_EWS_RECV is declared but never set, so the concrete zero-window paths are the plain RFC option, the local L2CAP_OPTIONS socket setting, and the CONFIG_RSP / conf_rfc_get negotiation state. To make sure the reroll covered all the zero-entry sites (and only the zero-entry sites), I enumerated every assignment to tx_win / ack_win / remote_tx_win / txwin_size in net/bluetooth/l2cap_core.c and confirmed patch 1 normalizes the four reachable input paths -- the local L2CAP_OPTIONS setsockopt, l2cap_txwin_setup() on the outgoing RFC, the L2CAP_MODE_ERTM branch of l2cap_parse_conf_req(), and the EWS / RFC branches of l2cap_parse_conf_rsp() and l2cap_conf_rfc_get(). The only other writers are the channel-create defaults in l2cap_chan_create() (hard-coded to L2CAP_DEFAULT_TX_WINDOW) and the outgoing rfc.txwin_size = 0 assignments in L2CAP_MODE_BASIC / L2CAP_MODE_STREAMING branches, where a zero is spec-correct and never feeds ack_win. l2cap_seq_list_free()'s callers are l2cap_chan_del() (channel teardown) and l2cap_ertm_init()'s error path; clearing the list metadata after kfree() is safe for both and is what makes the partially-initialized re-entry in the failure path no longer a double-free source. For patch 2, the BT_CONNECTED guard added to l2cap_config_rsp() mirrors the existing one in l2cap_config_req() (lines 4339..4348 in this tree) so both sides of the CONFIG exchange now refuse to re-enter l2cap_ertm_init() once the channel is already connected. I did not pin down a single introducing commit for the CONFIG_RSP side during this pass, so patch 2 keeps Cc: stable@ without a speculative Fixes: tag; happy to add one if you'd prefer a specific reference. Changes since v1 ---------------- - Split the reroll into two patches: the zero-txwin fix and the separate repeated-CONFIG_RSP ERTM re-init fix. - Dropped the v1 l2cap_seq_list_init(size == 0) -> -EINVAL defence and instead normalize zero tx window values where they enter negotiated ERTM state. - Clamp the local L2CAP_OPTIONS txwin_size = 0 case back to L2CAP_DEFAULT_TX_WINDOW. - Normalize zero tx window values seen during CONFIG_RSP / RFC parsing so ack_win does not collapse to 0. - Make l2cap_seq_list_free() clear list metadata after kfree so later teardown cannot trip over a previously freed list. Michael Bommarito (2): Bluetooth: L2CAP: handle zero txwin_size in ERTM RFC option Bluetooth: L2CAP: skip ERTM re-init on repeated CONFIG_RSP net/bluetooth/l2cap_core.c | 39 +++++++++++++++++++++++++++----------- net/bluetooth/l2cap_sock.c | 3 +++ 2 files changed, 31 insertions(+), 11 deletions(-) -- 2.53.0 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 1/2] Bluetooth: L2CAP: handle zero txwin_size in ERTM RFC option 2026-04-20 19:06 ` Luiz Augusto von Dentz 2026-04-21 13:56 ` [PATCH v2 0/2] Bluetooth: L2CAP: fix zero txwin_size handling and repeated CONFIG_RSP re-init Michael Bommarito @ 2026-04-21 13:56 ` Michael Bommarito 2026-04-21 13:56 ` [PATCH v2 2/2] Bluetooth: L2CAP: skip ERTM re-init on repeated CONFIG_RSP Michael Bommarito 2 siblings, 0 replies; 5+ messages in thread From: Michael Bommarito @ 2026-04-21 13:56 UTC (permalink / raw) To: Marcel Holtmann, Luiz Augusto von Dentz Cc: Mat Martineau, Hyunwoo Kim, linux-bluetooth, linux-kernel, stable Peer-supplied ERTM RFC txwin_size = 0 can still propagate into the ERTM transmit-window state, and the same invalid value can be introduced locally through L2CAP_OPTIONS. In the request path that zero reaches l2cap_seq_list_init(..., 0); in the response path it can shrink ack_win to 0 and leave ERTM sequencing in a nonsensical state. Normalize zero tx window values back to L2CAP_DEFAULT_TX_WINDOW wherever they enter the ERTM state machine: local socket options, outgoing tx_win setup, incoming config requests, and config-response parsing. Also make l2cap_seq_list_free() clear its metadata after kfree so an init failure after freeing srej_list cannot be freed a second time during later channel teardown. Fixes: 3c588192b5e5 ("Bluetooth: Add the l2cap_seq_list structure for tracking frames") Cc: stable@vger.kernel.org Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com> Assisted-by: Claude:claude-opus-4-7 --- Changes in v2: - drop the v1 `l2cap_seq_list_init(size == 0) -> -EINVAL` approach and instead normalize zero tx window values at the socket / request / response inputs - clamp the local `L2CAP_OPTIONS` txwin_size = 0 case back to `L2CAP_DEFAULT_TX_WINDOW` - make `l2cap_seq_list_free()` clear its metadata after `kfree()` so later teardown cannot trip over a previously freed list - split the repeated `CONFIG_RSP` ERTM re-init fix into patch 2 net/bluetooth/l2cap_core.c | 23 +++++++++++++++++++---- net/bluetooth/l2cap_sock.c | 3 +++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 95c65fece39b..7ffafd117817 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -345,6 +345,10 @@ static int l2cap_seq_list_init(struct l2cap_seq_list *seq_list, u16 size) static inline void l2cap_seq_list_free(struct l2cap_seq_list *seq_list) { kfree(seq_list->list); + seq_list->list = NULL; + seq_list->mask = 0; + seq_list->head = L2CAP_SEQ_LIST_CLEAR; + seq_list->tail = L2CAP_SEQ_LIST_CLEAR; } static inline bool l2cap_seq_list_contains(struct l2cap_seq_list *seq_list, @@ -3234,8 +3238,15 @@ static void __l2cap_set_ertm_timeouts(struct l2cap_chan *chan, rfc->monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); } +static inline u16 l2cap_txwin_default(u16 txwin) +{ + return txwin ? txwin : L2CAP_DEFAULT_TX_WINDOW; +} + static inline void l2cap_txwin_setup(struct l2cap_chan *chan) { + chan->tx_win = l2cap_txwin_default(chan->tx_win); + if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW && __l2cap_ews_supported(chan->conn)) { /* use extended control field */ @@ -3593,6 +3604,8 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data break; case L2CAP_MODE_ERTM: + rfc.txwin_size = l2cap_txwin_default(rfc.txwin_size); + if (!test_bit(CONF_EWS_RECV, &chan->conf_state)) chan->remote_tx_win = rfc.txwin_size; else @@ -3715,7 +3728,8 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, case L2CAP_CONF_EWS: if (olen != 2) break; - chan->ack_win = min_t(u16, val, chan->ack_win); + chan->ack_win = min_t(u16, l2cap_txwin_default(val), + chan->ack_win); l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2, chan->tx_win, endptr - ptr); break; @@ -3756,7 +3770,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, chan->mps = le16_to_cpu(rfc.max_pdu_size); if (!test_bit(FLAG_EXT_CTRL, &chan->flags)) chan->ack_win = min_t(u16, chan->ack_win, - rfc.txwin_size); + l2cap_txwin_default(rfc.txwin_size)); if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) { chan->local_msdu = le16_to_cpu(efs.msdu); @@ -3970,10 +3984,11 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len) chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); chan->mps = le16_to_cpu(rfc.max_pdu_size); if (test_bit(FLAG_EXT_CTRL, &chan->flags)) - chan->ack_win = min_t(u16, chan->ack_win, txwin_ext); + chan->ack_win = min_t(u16, chan->ack_win, + l2cap_txwin_default(txwin_ext)); else chan->ack_win = min_t(u16, chan->ack_win, - rfc.txwin_size); + l2cap_txwin_default(rfc.txwin_size)); break; case L2CAP_MODE_STREAMING: chan->mps = le16_to_cpu(rfc.max_pdu_size); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 71e8c1b45bce..3b53e967bf40 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -765,6 +765,9 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, break; } + if (!opts.txwin_size) + opts.txwin_size = L2CAP_DEFAULT_TX_WINDOW; + if (!l2cap_valid_mtu(chan, opts.imtu)) { err = -EINVAL; break; -- 2.53.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v2 2/2] Bluetooth: L2CAP: skip ERTM re-init on repeated CONFIG_RSP 2026-04-20 19:06 ` Luiz Augusto von Dentz 2026-04-21 13:56 ` [PATCH v2 0/2] Bluetooth: L2CAP: fix zero txwin_size handling and repeated CONFIG_RSP re-init Michael Bommarito 2026-04-21 13:56 ` [PATCH v2 1/2] Bluetooth: L2CAP: handle zero txwin_size in ERTM RFC option Michael Bommarito @ 2026-04-21 13:56 ` Michael Bommarito 2 siblings, 0 replies; 5+ messages in thread From: Michael Bommarito @ 2026-04-21 13:56 UTC (permalink / raw) To: Marcel Holtmann, Luiz Augusto von Dentz Cc: Mat Martineau, Hyunwoo Kim, linux-bluetooth, linux-kernel, stable commit 25f420a0d4cf ("Bluetooth: L2CAP: Fix ERTM re-init and zero pdu_len infinite loop") taught l2cap_config_req() not to call l2cap_ertm_init() again once the channel is already in BT_CONNECTED. l2cap_config_rsp() still lacks the same guard. After the initial ERTM setup, any extra successful CONFIG_RSP re-enters l2cap_ertm_init(), reinitializes tx_q and srej_q, and allocates fresh sequence lists over the existing channel state. Mirror the existing BT_CONNECTED check in l2cap_config_rsp() so response parsing can still update negotiated parameters without reinitializing ERTM state or leaking the old resources. Cc: stable@vger.kernel.org Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com> Assisted-by: Claude:claude-opus-4-7 --- Changes in v2: - split out of the original zero-txwin patch so the repeated `CONFIG_RSP` ERTM re-init bug is reviewed as a distinct issue - mirror the existing `BT_CONNECTED` guard already present on the `CONFIG_REQ` side after commit 25f420a0d4cf net/bluetooth/l2cap_core.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 7ffafd117817..fe98f4821a90 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -4480,14 +4480,16 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) { set_default_fcs(chan); - if (chan->mode == L2CAP_MODE_ERTM || - chan->mode == L2CAP_MODE_STREAMING) - err = l2cap_ertm_init(chan); + if (chan->state != BT_CONNECTED) { + if (chan->mode == L2CAP_MODE_ERTM || + chan->mode == L2CAP_MODE_STREAMING) + err = l2cap_ertm_init(chan); - if (err < 0) - l2cap_send_disconn_req(chan, -err); - else - l2cap_chan_ready(chan); + if (err < 0) + l2cap_send_disconn_req(chan, -err); + else + l2cap_chan_ready(chan); + } } done: -- 2.53.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-04-21 13:56 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-04-17 22:16 [PATCH] Bluetooth: L2CAP: handle zero txwin_size in ERTM RFC option Michael Bommarito 2026-04-20 19:06 ` Luiz Augusto von Dentz 2026-04-21 13:56 ` [PATCH v2 0/2] Bluetooth: L2CAP: fix zero txwin_size handling and repeated CONFIG_RSP re-init Michael Bommarito 2026-04-21 13:56 ` [PATCH v2 1/2] Bluetooth: L2CAP: handle zero txwin_size in ERTM RFC option Michael Bommarito 2026-04-21 13:56 ` [PATCH v2 2/2] Bluetooth: L2CAP: skip ERTM re-init on repeated CONFIG_RSP Michael Bommarito
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox