mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] Bluetooth: L2CAP: Keep credits from completing security upgrades
@ 2026-10-15  5:20 Kyle Pepper
  0 siblings, 0 replies; only message in thread
From: Kyle Pepper @ 2026-10-15  5:20 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Marcel Holtmann, Luiz Augusto von Dentz, linux-kernel

Credit indications can invoke resume on fixed or unready channels.
Connected LE credit-based sockets can also resume during a security
upgrade because credits and security share the socket suspend flag.

Validate the target mode and state for every identifier. Track pending
LE/ECRED security upgrades and retain credits without sending queued
data or resuming the socket until encryption meets the requested level.
Drain queued data after security completes and keep credit-starved
sockets suspended.

Fixes: fad5fc89594d ("Bluetooth: Add LE flow control discipline")
Assisted-by: OpenCode:gpt-6.1-sol
Signed-off-by: Kyle Pepper <cochcoder@proton.me>
---
New standalone security/target-state fix, not a resend of the zero-identifier
interoperability RFC. The zero-ID revision will be submitted separately and
depends on this fix; this patch does not accept identifier zero.

Refreshed without functional changes from the reviewed candidate onto current
bluetooth-next 397464709a20. The referenced Fixes commit's full ID and subject
were verified from its Git object:
fad5fc89594de31388572a26f33caa7c30a23782

On this refreshed base, both security-only and security+compatibility guest
kernels build with KASAN/lockdep and pass all nine focused security controls.
The 14 public credit controls pass 13/14 with this patch alone: the sole failure
is the intentionally unsupported positive zero-ID case. With the separate
compatibility patch they pass 14/14. No skips or captured KASAN/lockdep alerts
occurred in these focused runs. GCC W=1 changed objects and source-extracted
target/security and zero-ID fixtures pass.

The refreshed full-suite attempt is NOT a pass: SCI Fast Mode times out after
an invalid HCI Read Connection Interval response length for opcode 0x20a3, and
the runner reaches its outer timeout without a complete summary. The same SCI
failure reproduces on the unpatched current-base guest. It is not diagnosed as
a credit regression or claimed fixed here. An initial filter containing spaces
was split by the VM runner; corrected space-free filtered runs are reported above.

Earlier reference-base results were security-only 133/134 (the expected zero-ID
failure) and combined 134/134; those are historical, not fresh full-suite results.
The combined Arch integration was built and is reported working on hardware,
but that is not isolated attribution, over-the-air exploit evidence, complete
security/lifetime coverage or a remote-CI pass. No severity/CVE claim is made.
The private reproducer and detailed private regression logs are not included.

 net/bluetooth/l2cap_core.c | 33 +++++++++++++++++++++++++++++++--
 net/bluetooth/l2cap_sock.c |  9 +++++++--
 2 files changed, 38 insertions(+), 4 deletions(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 4dd56e007..7a7f30531 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -5391,6 +5391,11 @@ static inline int l2cap_le_credits(struct l2cap_conn *conn,
 
 	l2cap_chan_lock(chan);
 
+	if (chan->state != BT_CONNECTED ||
+	    (chan->mode != L2CAP_MODE_LE_FLOWCTL &&
+	     chan->mode != L2CAP_MODE_EXT_FLOWCTL))
+		goto unlock;
+
 	max_credits = LE_FLOWCTL_MAX_CREDITS - chan->tx_credits;
 	if (credits > max_credits) {
 		BT_ERR("LE credits overflow");
@@ -5404,6 +5409,9 @@ static inline int l2cap_le_credits(struct l2cap_conn *conn,
 
 	chan->tx_credits += credits;
 
+	if (test_bit(FLAG_PENDING_SECURITY, &chan->flags))
+		goto unlock;
+
 	/* Resume sending */
 	l2cap_le_flowctl_send(chan);
 
@@ -7967,6 +7975,8 @@ static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 	mutex_lock(&conn->lock);
 
 	list_for_each_entry(chan, &conn->chan_l, list) {
+		bool pending_le;
+
 		l2cap_chan_lock(chan);
 
 		lockdep_assert_held(&chan->conn->lock);
@@ -7974,7 +7984,12 @@ static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 		BT_DBG("chan %p scid 0x%4.4x state %s", chan, chan->scid,
 		       state_to_string(chan->state));
 
-		if (!status && encrypt)
+		pending_le = hcon->type == LE_LINK &&
+			     (chan->mode == L2CAP_MODE_LE_FLOWCTL ||
+			      chan->mode == L2CAP_MODE_EXT_FLOWCTL) &&
+			     test_bit(FLAG_PENDING_SECURITY, &chan->flags);
+
+		if (!status && encrypt && !pending_le)
 			chan->sec_level = hcon->sec_level;
 
 		if (!__l2cap_no_conn_pending(chan)) {
@@ -7984,7 +7999,21 @@ static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 
 		if (!status && (chan->state == BT_CONNECTED ||
 				chan->state == BT_CONFIG)) {
-			chan->ops->resume(chan);
+			if (pending_le) {
+				if (!encrypt ||
+				    !smp_sufficient_security(hcon, chan->sec_level,
+							    SMP_ALLOW_STK)) {
+					l2cap_chan_unlock(chan);
+					continue;
+				}
+
+				clear_bit(FLAG_PENDING_SECURITY, &chan->flags);
+				chan->sec_level = hcon->sec_level;
+				l2cap_le_flowctl_send(chan);
+			}
+
+			if (!pending_le || chan->tx_credits)
+				chan->ops->resume(chan);
 			l2cap_check_encryption(chan, encrypt);
 			l2cap_chan_unlock(chan);
 			continue;
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index c396987c5..2d7f2935c 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -993,10 +993,15 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
 		} else if ((sk->sk_state == BT_CONNECT2 &&
 			    test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) ||
 			   sk->sk_state == BT_CONNECTED) {
-			if (!l2cap_chan_check_security(chan, true))
+			if (!l2cap_chan_check_security(chan, true)) {
+				if (conn->hcon->type == LE_LINK &&
+				    (chan->mode == L2CAP_MODE_LE_FLOWCTL ||
+				     chan->mode == L2CAP_MODE_EXT_FLOWCTL))
+					set_bit(FLAG_PENDING_SECURITY, &chan->flags);
 				set_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags);
-			else
+			} else {
 				sk->sk_state_change(sk);
+			}
 		} else {
 			err = -EINVAL;
 		}

base-commit: 397464709a204da9b8dc3b01d6ea42539d951cd2


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-10-15  5:20 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-15  5:20 [PATCH] Bluetooth: L2CAP: Keep credits from completing security upgrades Kyle Pepper

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

all inboxes | Powered by JetHome®