mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-04-05 04:46:54 -04:00
Bluetooth: L2CAP: Fix use-after-free in l2cap_unregister_user
After commitab4eedb790("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:ab4eedb790("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>
This commit is contained in:
committed by
Luiz Augusto von Dentz
parent
dbf666e4fc
commit
752a6c9596
@@ -1678,17 +1678,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;
|
||||
@@ -1709,16 +1707,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;
|
||||
@@ -1727,7 +1723,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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user