From: Hyunwoo Kim <imv4bel@gmail.com>
To: marcel@holtmann.org, johan.hedberg@gmail.com, luiz.dentz@gmail.com
Cc: linux-bluetooth@vger.kernel.org, imv4bel@gmail.com
Subject: [PATCH] Bluetooth: L2CAP: Fix use-after-free in l2cap_chan_timeout()
Date: Fri, 20 Mar 2026 00:14:14 +0900 [thread overview]
Message-ID: <abwSxg_C6n8Avid3@v4bel> (raw)
l2cap_chan_timeout() reads chan->conn without holding any lock and
without taking a reference on the connection. If l2cap_conn_del()
frees the connection concurrently, mutex_lock(&conn->lock) operates
on freed memory. The existing NULL check is insufficient as it cannot
prevent the connection from being freed after the check passes, and
the early return also leaks the channel reference held by the timer.
Fix by reading chan->conn under l2cap_chan_lock() and holding the
connection with l2cap_conn_get(). After acquiring locks in the correct
order (conn->lock then chan->lock), re-verify chan->conn in case
l2cap_conn_del() already cleaned up the channel.
Fixes: 3df91ea20e74 ("Bluetooth: Revert to mutexes from RCU list")
Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com>
---
net/bluetooth/l2cap_core.c | 23 +++++++++++++++++++++--
1 file changed, 21 insertions(+), 2 deletions(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index abd091155d04..a432e94281dc 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -406,13 +406,20 @@ static void l2cap_chan_timeout(struct work_struct *work)
{
struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
chan_timer.work);
- struct l2cap_conn *conn = chan->conn;
+ struct l2cap_conn *conn;
int reason;
BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
- if (!conn)
+ l2cap_chan_lock(chan);
+ conn = chan->conn;
+ if (!conn) {
+ l2cap_chan_unlock(chan);
+ l2cap_chan_put(chan);
return;
+ }
+ l2cap_conn_get(conn);
+ l2cap_chan_unlock(chan);
mutex_lock(&conn->lock);
/* __set_chan_timer() calls l2cap_chan_hold(chan) while scheduling
@@ -420,6 +427,17 @@ static void l2cap_chan_timeout(struct work_struct *work)
*/
l2cap_chan_lock(chan);
+ /* Recheck since l2cap_conn_del() may have cleaned up the channel
+ * while we were waiting for conn->lock.
+ */
+ if (!chan->conn) {
+ l2cap_chan_unlock(chan);
+ l2cap_chan_put(chan);
+ mutex_unlock(&conn->lock);
+ l2cap_conn_put(conn);
+ return;
+ }
+
if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
reason = ECONNREFUSED;
else if (chan->state == BT_CONNECT &&
@@ -436,6 +454,7 @@ static void l2cap_chan_timeout(struct work_struct *work)
l2cap_chan_put(chan);
mutex_unlock(&conn->lock);
+ l2cap_conn_put(conn);
}
struct l2cap_chan *l2cap_chan_create(void)
--
2.43.0
next reply other threads:[~2026-03-19 15:14 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-19 15:14 Hyunwoo Kim [this message]
2026-03-19 15:55 ` [PATCH] Bluetooth: L2CAP: Fix use-after-free in l2cap_chan_timeout() Luiz Augusto von Dentz
2026-03-19 16:36 ` bluez.test.bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=abwSxg_C6n8Avid3@v4bel \
--to=imv4bel@gmail.com \
--cc=johan.hedberg@gmail.com \
--cc=linux-bluetooth@vger.kernel.org \
--cc=luiz.dentz@gmail.com \
--cc=marcel@holtmann.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox