From: Hillf Danton <hdanton@sina.com>
To: Pauli Virtanen <pav@iki.fi>
Cc: linux-bluetooth@vger.kernel.org, marcel@holtmann.org,
luiz.dentz@gmail.com, linux-kernel@vger.kernel.org,
syzbot+e6382a2f53f5fc7453ac@syzkaller.appspotmail.com,
syzkaller-bugs@googlegroups.com
Subject: Re: [PATCH] Bluetooth: L2CAP: fix race l2cap_sock_cleanup_listen() vs. put_chan
Date: Tue, 4 Aug 2026 08:47:13 +0800 [thread overview]
Message-ID: <20260804004717.919-1-hdanton@sina.com> (raw)
In-Reply-To: <192fb711930f4f0b7d06266f78d638664e982318.camel@iki.fi>
On Mon, 03 Aug 2026 19:53:31 +0300 Pauli Virtanen wrote:
> ma, 2026-08-03 kello 14:13 +0800, Hillf Danton kirjoitti:
> > On Sun, 2 Aug 2026 15:12:28 +0300 Pauli Virtanen wrote:
> > > For L2CAP sockets without owning sk->sk_socket, reading
> > > l2cap_pi(sk)->chan may race against concurrent l2cap_sock_kill() ->
> > > l2cap_sock_put_chan(). This excludes simultaneous proto_ops callbacks,
> > > but access in l2cap_sock_cleanup_listen() has unsafe lockless read.
> > >
> > > Fix the race by taking lock_sock() in l2cap_sock_kill() to
> > > synchronize with l2cap_sock_cleanup_listen(). hold_unless_zero() is not
> > > needed here, l2cap_pi(sk)->chan owns reference if it is non-NULL.
> > >
> > > Fixes: 0e2c0392b9dc ("Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()")
> > > Reported-by: syzbot+e6382a2f53f5fc7453ac@syzkaller.appspotmail.com
> > > Closes: https://syzkaller.appspot.com/bug?extid=e6382a2f53f5fc7453ac
> > > Signed-off-by: Pauli Virtanen <pav@iki.fi>
> > > ---
> > > include/net/bluetooth/l2cap.h | 5 +++++
> > > net/bluetooth/l2cap_sock.c | 23 +++++++++++++----------
> > > 2 files changed, 18 insertions(+), 10 deletions(-)
> > >
> > > diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> > > index ef6ce1c20a4f..3d9a32094347 100644
> > > --- a/include/net/bluetooth/l2cap.h
> > > +++ b/include/net/bluetooth/l2cap.h
> > > @@ -699,7 +699,12 @@ struct l2cap_rx_busy {
> > >
> > > struct l2cap_pinfo {
> > > struct bt_sock bt;
> > > +
> > > + /* With owning sk_socket chan may be read without lock, other access
> > > + * should hold lock_sock.
> > > + */
> > > struct l2cap_chan *chan;
> > > +
> > > struct list_head rx_busy;
> > > };
> > >
> > > diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
> > > index 735167f73f31..9540617a0e6c 100644
> > > --- a/net/bluetooth/l2cap_sock.c
> > > +++ b/net/bluetooth/l2cap_sock.c
> > > @@ -1312,7 +1312,12 @@ static void l2cap_sock_kill(struct sock *sk)
> > >
> > > BT_DBG("sk %p state %s", sk, state_to_string(sk->sk_state));
> > >
> > > + /* Take lock to synchronize against access without owning sk->sk_socket,
> > > + * eg. in l2cap_sock_cleanup_listen(). proto_ops etc. don't need lock.
> > > + */
> > > + lock_sock(sk);
> > > l2cap_sock_put_chan(sk);
> > > + release_sock(sk);
> > >
> > > /* Kill poor orphan */
> > > sock_set_flag(sk, SOCK_DEAD);
> >
> > In l2cap_sock_teardown_cb(), sock is only zapped after cleanup including unlink,
> > so why do you see a linked and zapped sock in l2cap_sock_cleanup_listen()?
>
> l2cap_sock_cleanup_listen() is not a single critical section.
>
> There is the following race:
>
> [Task 1] [Task 2 (hdev->workqueue)]
> l2cap_sock_release(parent) l2cap_disconn_cfm
> l2cap_sock_cleanup_listen l2cap_conn_del
> bt_accept_dequeue l2cap_chan_del
> lock_sock(sk) l2cap_sock_teardown_cb
> bt_accept_unlink
> bt_sk(sk)->parent = NULL
> release_sock(sk) ----------------> lock_sock(sk)
> parent = bt_sk(sk)->parent /* == NULL */
> lock_sock(sk) <--------------------- release_sock(sk)
> sock_set_flag(sk, SOCK_ZAPPED)
> l2cap_sock_close_cb
> l2cap_sock_kill(sk)
> l2cap_sock_put_chan
> chan = READ l2cap_pi(sk)->chan l2cap_pi(sk)->chan = NULL
> l2cap_chan_hold_unless_zero l2cap_put_chan(chan)
> kref_get_unless_zero(&chan->ref)
>
The race window is still open after this work.
release_sock(sk)
sock_set_flag(sk, SOCK_ZAPPED)
l2cap_sock_close_cb
l2cap_sock_kill(sk)
l2cap_sock_put_chan
l2cap_pi(sk)->chan = NULL
l2cap_put_chan(chan)
sock_set_flag(sk, SOCK_DEAD);
sock_put(sk); // free sk
lock_sock(sk) // uaf
chan = READ l2cap_pi(sk)->chan
l2cap_chan_hold_unless_zero
next prev parent reply other threads:[~2026-08-04 0:47 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-02 12:12 [PATCH] Bluetooth: L2CAP: fix race l2cap_sock_cleanup_listen() vs. put_chan Pauli Virtanen
2026-08-02 13:42 ` bluez.test.bot
2026-08-03 6:13 ` [PATCH] " Hillf Danton
2026-08-03 16:53 ` Pauli Virtanen
2026-08-04 0:47 ` Hillf Danton [this message]
2026-08-04 5:40 ` Pauli Virtanen
2026-08-04 8:16 ` Hillf Danton
2026-08-04 16:06 ` Pauli Virtanen
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=20260804004717.919-1-hdanton@sina.com \
--to=hdanton@sina.com \
--cc=linux-bluetooth@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=luiz.dentz@gmail.com \
--cc=marcel@holtmann.org \
--cc=pav@iki.fi \
--cc=syzbot+e6382a2f53f5fc7453ac@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox