[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20240209070443.3617790-1-iam@sung-woo.kim>
Date: Fri, 9 Feb 2024 02:04:44 -0500
From: Sungwoo Kim <iam@...g-woo.kim>
To:
Cc: daveti@...due.edu,
Sungwoo Kim <iam@...g-woo.kim>,
Marcel Holtmann <marcel@...tmann.org>,
Johan Hedberg <johan.hedberg@...il.com>,
Luiz Augusto von Dentz <luiz.dentz@...il.com>,
linux-bluetooth@...r.kernel.org,
linux-kernel@...r.kernel.org
Subject: [PATCH] Bluetooth: add missing checks in state transitions
When an l2cap channel receives L2CAP_CONN_RSP, it revives from BT_DISCONN
to BT_CONFIG or BT_CONNECTED.
It is very weird, violates the specification, and I cannot see any real
usecase for this.
Similar to this, the L2cap channel has six illegal state transitions:
1. BT_CONNECT2 -> BT_CONFIG by L2CAP_CONN_RSP
2. BT_CONNECT2 -> BT_CONNECTED by L2CAP_CONF_RSP
3. BT_CONNECT2 -> BT_DISCONN by L2CAP_CONF_RSP
4. BT_CONNECTED -> BT_CONFIG by L2CAP_CONN_RSP
5. BT_DISCONN -> BT_CONFIG by L2CAP_CONN_RSP
6. BT_DISCONN -> BT_CONNECTED by L2CAP_CONN_RSP
This patch fixes 2, 3, 5, and 6 by adding checks.
For 1 and 4, I will make an RFC for as it requires some refactoring.
The detaild logs are described in here:
https://lore.kernel.org/lkml/CAJNyHpKpDdps4=QHZ77zu4jfY-NNBcGUrw6UwjuBKfpuSuE__g@mail.gmail.com/
Signed-off-by: Sungwoo Kim <iam@...g-woo.kim>
---
net/bluetooth/l2cap_core.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 60298975d..c5fa2b683 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -4339,6 +4339,14 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
l2cap_chan_lock(chan);
+ switch (chan->state) {
+ case BT_CLOSED:
+ case BT_DISCONN:
+ l2cap_chan_unlock(chan);
+ l2cap_chan_put(chan);
+ goto unlock;
+ }
+
switch (result) {
case L2CAP_CR_SUCCESS:
if (__l2cap_get_chan_by_dcid(conn, dcid)) {
@@ -4552,6 +4560,14 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
if (!chan)
return 0;
+ switch (chan->state) {
+ case BT_CLOSED:
+ case BT_CONNECT:
+ case BT_CONNECT2:
+ case BT_DISCONN:
+ goto done;
+ }
+
switch (result) {
case L2CAP_CONF_SUCCESS:
l2cap_conf_rfc_get(chan, rsp->data, len);
--
2.25.1
Powered by blists - more mailing lists