]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
Bluetooth: L2CAP: Fix use-after-free in l2cap_unregister_user
authorShaurya Rane <ssrane_b23@ee.vjti.ac.in>
Thu, 6 Nov 2025 18:20:16 +0000 (23:50 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 25 Mar 2026 10:08:52 +0000 (11:08 +0100)
[ Upstream commit 752a6c9596dd25efd6978a73ff21f3b592668f4a ]

After commit ab4eedb790ca ("Bluetooth: L2CAP: Fix corrupted list in
hci_chan_del"), l2cap_conn_del() uses conn->lock to protect access to
conn->users. However, l2cap_register_user() and l2cap_unregister_user()
don't use conn->lock, creating a race condition where these functions can
access conn->users and conn->hchan concurrently with l2cap_conn_del().

This can lead to use-after-free and list corruption bugs, as reported
by syzbot.

Fix this by changing l2cap_register_user() and l2cap_unregister_user()
to use conn->lock instead of hci_dev_lock(), ensuring consistent locking
for the l2cap_conn structure.

Reported-by: syzbot+14b6d57fb728e27ce23c@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=14b6d57fb728e27ce23c
Fixes: ab4eedb790ca ("Bluetooth: L2CAP: Fix corrupted list in hci_chan_del")
Signed-off-by: Shaurya Rane <ssrane_b23@ee.vjti.ac.in>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
net/bluetooth/l2cap_core.c

index 560a17d36f7fa4239d81ecae3cedc3ada532e9f1..7c131e4640b7529c1dd3786e59cea304cf00714e 100644 (file)
@@ -1686,17 +1686,15 @@ static void l2cap_info_timeout(struct work_struct *work)
 
 int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user)
 {
-       struct hci_dev *hdev = conn->hcon->hdev;
        int ret;
 
        /* We need to check whether l2cap_conn is registered. If it is not, we
-        * must not register the l2cap_user. l2cap_conn_del() is unregisters
-        * l2cap_conn objects, but doesn't provide its own locking. Instead, it
-        * relies on the parent hci_conn object to be locked. This itself relies
-        * on the hci_dev object to be locked. So we must lock the hci device
-        * here, too. */
+        * must not register the l2cap_user. l2cap_conn_del() unregisters
+        * l2cap_conn objects under conn->lock, and we use the same lock here
+        * to protect access to conn->users and conn->hchan.
+        */
 
-       hci_dev_lock(hdev);
+       mutex_lock(&conn->lock);
 
        if (!list_empty(&user->list)) {
                ret = -EINVAL;
@@ -1717,16 +1715,14 @@ int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user)
        ret = 0;
 
 out_unlock:
-       hci_dev_unlock(hdev);
+       mutex_unlock(&conn->lock);
        return ret;
 }
 EXPORT_SYMBOL(l2cap_register_user);
 
 void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user)
 {
-       struct hci_dev *hdev = conn->hcon->hdev;
-
-       hci_dev_lock(hdev);
+       mutex_lock(&conn->lock);
 
        if (list_empty(&user->list))
                goto out_unlock;
@@ -1735,7 +1731,7 @@ void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user)
        user->remove(conn, user);
 
 out_unlock:
-       hci_dev_unlock(hdev);
+       mutex_unlock(&conn->lock);
 }
 EXPORT_SYMBOL(l2cap_unregister_user);