FAILED: patch "[PATCH] Bluetooth: fix UAF in l2cap_sock_cleanup_listen() vs" failed to apply to 5.10-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.10-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.10.y
git checkout FETCH_HEAD
git cherry-pick -x ab1513597c6cf17cd1ad2a21e3b045421b48e022
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026052809-colt-unlearned-fe00@gregkh' --subject-prefix 'PATCH 5.10.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From ab1513597c6cf17cd1ad2a21e3b045421b48e022 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Safa=20Karaku=C5=9F?= <[email protected]>
Date: Sat, 16 May 2026 21:15:04 +0300
Subject: [PATCH] Bluetooth: fix UAF in l2cap_sock_cleanup_listen() vs
l2cap_conn_del()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
bt_accept_dequeue() unlinks a not-yet-accepted child from the parent accept queue and release_sock()s it before returning, so the returned sk has no caller reference and is unlocked.
l2cap_sock_cleanup_listen() walks these children on listening-socket close. A concurrent HCI disconnect drives hci_rx_work -> l2cap_conn_del() which runs l2cap_chan_del() + l2cap_sock_kill() and frees the child sk and its l2cap_chan; cleanup_listen() then uses both:
BUG: KASAN: slab-use-after-free in l2cap_sock_kill
l2cap_sock_kill / l2cap_sock_cleanup_listen / __x64_sys_close
Freed by: l2cap_conn_del -> l2cap_sock_close_cb -> l2cap_sock_killThis is distinct from the two fixes already in this area: commit e83f5e24da741 ("Bluetooth: serialize accept_q access") serialises the accept_q list/poll and takes temporary refs inside bt_accept_dequeue(), and CVE-2025-39860 serialises the userspace close()/accept() race by calling cleanup_listen() under lock_sock() in l2cap_sock_release(). Neither covers l2cap_conn_del() running from hci_rx_work, so this UAF still reproduces on current bluetooth/master.
Take the reference at the source: bt_accept_dequeue() does sock_hold() while sk is still locked, before release_sock(); callers sock_put(). cleanup_listen() pins the chan with l2cap_chan_hold_unless_zero() under a brief child sk lock (serialising vs l2cap_sock_teardown_cb()), drops it before l2cap_chan_lock(), and skips a duplicate l2cap_sock_kill() on SOCK_DEAD. conn->lock is not taken here: cleanup_listen() runs under the parent sk lock and that would invertconn->lock -> chan->lock -> sk_lock (lockdep).
KASAN/SMP: an unprivileged listen/close vs HCI-disconnect race produced 12 use-after-free reports per run before this change; 0, and no lockdep report, over 1600+ raced iterations after it on bluetooth/master.
net/bluetooth/af_bluetooth.c +10 -0
@@ -340,6 +340,16 @@ restart:if (newsock)sock_graft (sk, newsock); +/* Hand the caller a reference taken while sk is +* still locked. bt_accept_unlink() just dropped +* the accept-queue reference; without this hold a +* concurrent teardown (e.g. l2cap_conn_del() -> +* l2cap_sock_kill()) could free sk between +* release_sock() and the caller using it. Every +* caller drops this with sock_put() when done. +*/ +sock_hold (sk); +release_sock (sk);if (next)sock_put (next);
net/bluetooth/iso.c +8 -1
@@ -751,6 +751,8 @@ static void iso_sock_cleanup_listen(struct sock *parent)while ((sk =bt_accept_dequeue (parent,NULL ))) {iso_sock_close (sk);iso_sock_kill (sk); +/* Drop the reference handed back by bt_accept_dequeue(). */ +sock_put (sk); }/* If listening socket has a hcon, properly disconnect it */
@@ -1356,8 +1358,13 @@ static int iso_sock_accept(struct socket *sock, struct socket *newsock, } ch =bt_accept_dequeue (sk, newsock); -if (ch) +if (ch) { +/* Drop the bridging ref from bt_accept_dequeue(); +* the grafted socket keeps ch alive from here. +*/ +sock_put (ch);break ; + }if (!timeo) { err = -EAGAIN ;
net/bluetooth/l2cap_sock.c +44 -7
74 lines not on this page · raw message
net/bluetooth/rfcomm/sock.c +8 -1
@@ -180,6 +180,8 @@ static void rfcomm_sock_cleanup_listen(struct sock *parent)while ((sk =bt_accept_dequeue (parent,NULL ))) {rfcomm_sock_close (sk);rfcomm_sock_kill (sk); +/* Drop the reference handed back by bt_accept_dequeue(). */ +sock_put (sk); } parent->sk_state =BT_CLOSED ;
@@ -497,8 +499,13 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, } nsk =bt_accept_dequeue (sk, newsock); -if (nsk) +if (nsk) { +/* Drop the bridging ref from bt_accept_dequeue(); +* the grafted socket keeps nsk alive from here. +*/ +sock_put (nsk);break ; + }if (!timeo) { err = -EAGAIN ;
net/bluetooth/sco.c +8 -1
@@ -502,6 +502,8 @@ static void sco_sock_cleanup_listen(struct sock *parent)while ((sk =bt_accept_dequeue (parent,NULL ))) {sco_sock_close (sk);sco_sock_kill (sk); +/* Drop the reference handed back by bt_accept_dequeue(). */ +sock_put (sk); } parent->sk_state =BT_CLOSED ;
@@ -765,8 +767,13 @@ static int sco_sock_accept(struct socket *sock, struct socket *newsock, } ch =bt_accept_dequeue (sk, newsock); -if (ch) +if (ch) { +/* Drop the bridging ref from bt_accept_dequeue(); +* the grafted socket keeps ch alive from here. +*/ +sock_put (ch);break ; + }if (!timeo) { err = -EAGAIN ;
Sasha Levin
maintainerPATCH 1/1 Bluetooth: fix UAF in l2cap_sock_cleanup_listen() vs l2cap_conn_del()
From: Safa Karakuş <[email protected]>
[ Upstream commit ab1513597c6cf17cd1ad2a21e3b045421b48e022 ]
bt_accept_dequeue() unlinks a not-yet-accepted child from the parent accept queue and release_sock()s it before returning, so the returned sk has no caller reference and is unlocked.
l2cap_sock_cleanup_listen() walks these children on listening-socket close. A concurrent HCI disconnect drives hci_rx_work -> l2cap_conn_del() which runs l2cap_chan_del() + l2cap_sock_kill() and frees the child sk and its l2cap_chan; cleanup_listen() then uses both:
BUG: KASAN: slab-use-after-free in l2cap_sock_kill
l2cap_sock_kill / l2cap_sock_cleanup_listen / __x64_sys_close
Freed by: l2cap_conn_del -> l2cap_sock_close_cb -> l2cap_sock_killThis is distinct from the two fixes already in this area: commit e83f5e24da741 ("Bluetooth: serialize accept_q access") serialises the accept_q list/poll and takes temporary refs inside bt_accept_dequeue(), and CVE-2025-39860 serialises the userspace close()/accept() race by calling cleanup_listen() under lock_sock() in l2cap_sock_release(). Neither covers l2cap_conn_del() running from hci_rx_work, so this UAF still reproduces on current bluetooth/master.
Take the reference at the source: bt_accept_dequeue() does sock_hold() while sk is still locked, before release_sock(); callers sock_put(). cleanup_listen() pins the chan with l2cap_chan_hold_unless_zero() under a brief child sk lock (serialising vs l2cap_sock_teardown_cb()), drops it before l2cap_chan_lock(), and skips a duplicate l2cap_sock_kill() on SOCK_DEAD. conn->lock is not taken here: cleanup_listen() runs under the parent sk lock and that would invertconn->lock -> chan->lock -> sk_lock (lockdep).
KASAN/SMP: an unprivileged listen/close vs HCI-disconnect race produced 12 use-after-free reports per run before this change; 0, and no lockdep report, over 1600+ raced iterations after it on bluetooth/master.
--- net/bluetooth/af_bluetooth.c | 10 +++++++ net/bluetooth/l2cap_sock.c | 51 +++++++++++++++++++++++++++++++----- net/bluetooth/rfcomm/sock.c | 9 ++++++- net/bluetooth/sco.c | 9 ++++++- 4 files changed, 70 insertions(+), 9 deletions(-)
net/bluetooth/af_bluetooth.c +10 -0
@@ -237,6 +237,16 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)if (newsock)sock_graft (sk, newsock); +/* Hand the caller a reference taken while sk is +* still locked. bt_accept_unlink() just dropped +* the accept-queue reference; without this hold a +* concurrent teardown (e.g. l2cap_conn_del() -> +* l2cap_sock_kill()) could free sk between +* release_sock() and the caller using it. Every +* caller drops this with sock_put() when done. +*/ +sock_hold (sk); +release_sock (sk);return sk; }
net/bluetooth/l2cap_sock.c +44 -7
74 lines not on this page · raw message
net/bluetooth/rfcomm/sock.c +8 -1
@@ -180,6 +180,8 @@ static void rfcomm_sock_cleanup_listen(struct sock *parent)while ((sk =bt_accept_dequeue (parent,NULL ))) {rfcomm_sock_close (sk);rfcomm_sock_kill (sk); +/* Drop the reference handed back by bt_accept_dequeue(). */ +sock_put (sk); } parent->sk_state =BT_CLOSED ;
@@ -498,8 +500,13 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f } nsk =bt_accept_dequeue (sk, newsock); -if (nsk) +if (nsk) { +/* Drop the bridging ref from bt_accept_dequeue(); +* the grafted socket keeps nsk alive from here. +*/ +sock_put (nsk);break ; + }if (!timeo) { err = -EAGAIN ;
net/bluetooth/sco.c +8 -1
@@ -384,6 +384,8 @@ static void sco_sock_cleanup_listen(struct sock *parent)while ((sk =bt_accept_dequeue (parent,NULL ))) {sco_sock_close (sk);sco_sock_kill (sk); +/* Drop the reference handed back by bt_accept_dequeue(). */ +sock_put (sk); } parent->sk_state =BT_CLOSED ;
@@ -677,8 +679,13 @@ static int sco_sock_accept(struct socket *sock, struct socket *newsock, } ch =bt_accept_dequeue (sk, newsock); -if (ch) +if (ch) { +/* Drop the bridging ref from bt_accept_dequeue(); +* the grafted socket keeps ch alive from here. +*/ +sock_put (ch);break ; + }if (!timeo) { err = -EAGAIN ;
Signature · 1 line
2.53.0