All of lore.kernel.org
 help / color / mirror / Atom feed
From: Hojun Choi <ghwns6743@gmail.com>
To: Marcel Holtmann <marcel@holtmann.org>,
	Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Cc: linux-bluetooth@vger.kernel.org, linux-kernel@vger.kernel.org,
	syzkaller-bugs@googlegroups.com, Hojun Choi <ghwns6743@gmail.com>,
	syzbot+9c40ad7c6ed7165e46e8@syzkaller.appspotmail.com,
	stable@vger.kernel.org
Subject: [PATCH] Bluetooth: L2CAP: Fix slab-use-after-free in l2cap_disconn_ind
Date: Mon, 29 Jun 2026 20:05:15 +0900	[thread overview]
Message-ID: <20260629110515.29689-1-ghwns6743@gmail.com> (raw)
In-Reply-To: <6a043270.a00a0220.3890a0.0006.GAE@google.com>

l2cap_disconn_ind() runs from the hci_conn_timeout() worker without
hci_dev_lock, and reads conn->disc_reason via hcon->l2cap_data. It races
the teardown path: hci_conn_failed() frees the l2cap_conn via
hci_connect_cfm() -> l2cap_conn_del() and only afterwards drains the
worker via hci_conn_del(), so the worker can read disc_reason after the
l2cap_conn has been freed:

| BUG: KASAN: slab-use-after-free in l2cap_disconn_ind+0xd7/0xf0
| Read of size 1 at addr ffff88807ee53278 by task kworker/u9:1/4933
|  l2cap_disconn_ind net/bluetooth/l2cap_core.c:7430
|  hci_conn_timeout net/bluetooth/hci_conn.c:646

l2cap_conn_del() is always called under hci_dev_lock(), so hold it while
dereferencing hcon->l2cap_data and reading disc_reason. A blocking lock
cannot be used here: hci_conn_del() drains this worker with
disable_delayed_work_sync() while holding hci_dev_lock(), so the worker
would deadlock against the drain. Use a trylock; on contention return the
default HCI_ERROR_REMOTE_USER_TERM, the same reason the !conn path already
returns.

Fixes: 2950f21acb0f ("Bluetooth: Ask upper layers for HCI disconnect reason")
Reported-by: syzbot+9c40ad7c6ed7165e46e8@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=9c40ad7c6ed7165e46e8
Cc: <stable@vger.kernel.org>
Signed-off-by: Hojun Choi <ghwns6743@gmail.com>
---
 include/net/bluetooth/hci_core.h |  1 +
 net/bluetooth/l2cap_core.c       | 24 ++++++++++++++++++++----
 2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index aa600fbf9a53..a5d82f9f3871 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1733,6 +1733,7 @@ static inline struct hci_dev *hci_dev_hold(struct hci_dev *d)
 }
 
 #define hci_dev_lock(d)		mutex_lock(&d->lock)
+#define hci_dev_trylock(d)	mutex_trylock(&d->lock)
 #define hci_dev_unlock(d)	mutex_unlock(&d->lock)
 
 #define to_hci_dev(d) container_of(d, struct hci_dev, dev)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 1fbd52165fb2..1666601ebd1f 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -7498,13 +7498,29 @@ static void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
 
 int l2cap_disconn_ind(struct hci_conn *hcon)
 {
-	struct l2cap_conn *conn = hcon->l2cap_data;
+	struct hci_dev *hdev = hcon->hdev;
+	struct l2cap_conn *conn;
+	u8 reason = HCI_ERROR_REMOTE_USER_TERM;
 
 	BT_DBG("hcon %p", hcon);
 
-	if (!conn)
-		return HCI_ERROR_REMOTE_USER_TERM;
-	return conn->disc_reason;
+	/* l2cap_conn_del() is always called under hci_dev_lock(), so hold
+	 * it while dereferencing hcon->l2cap_data and reading disc_reason
+	 * to serialize against the free. trylock because hci_conn_del()
+	 * drains this worker with disable_delayed_work_sync() under
+	 * hci_dev_lock(), so a blocking lock here would deadlock against
+	 * that drain.
+	 */
+	if (!hci_dev_trylock(hdev))
+		return reason;
+
+	conn = hcon->l2cap_data;
+	if (conn)
+		reason = conn->disc_reason;
+
+	hci_dev_unlock(hdev);
+
+	return reason;
 }
 
 static void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
-- 
2.54.0


  reply	other threads:[~2026-06-29 11:04 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-13  8:12 [syzbot] [bluetooth?] KASAN: slab-use-after-free Read in l2cap_disconn_ind (3) syzbot
2026-06-29 11:05 ` Hojun Choi [this message]
2026-06-29 12:29   ` Bluetooth: L2CAP: Fix slab-use-after-free in l2cap_disconn_ind 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=20260629110515.29689-1-ghwns6743@gmail.com \
    --to=ghwns6743@gmail.com \
    --cc=linux-bluetooth@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=luiz.dentz@gmail.com \
    --cc=marcel@holtmann.org \
    --cc=stable@vger.kernel.org \
    --cc=syzbot+9c40ad7c6ed7165e46e8@syzkaller.appspotmail.com \
    --cc=syzkaller-bugs@googlegroups.com \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.