From: Pauli Virtanen <pav@iki.fi>
To: "Ziyang Xuan (William)" <william.xuanziyang@huawei.com>,
linux-bluetooth <linux-bluetooth@vger.kernel.org>
Subject: Re: [PATCH v2] Bluetooth: Fix UAF for hci_chan
Date: Tue, 10 Oct 2023 21:32:00 +0300 [thread overview]
Message-ID: <a72b89cd520f502d6d384f97fcaf83f92ead147f.camel@iki.fi> (raw)
In-Reply-To: <8f61ef8e-f959-3feb-fb9b-b9b60bf26758@huawei.com>
Hi,
ti, 2023-10-10 kello 20:49 +0800, Ziyang Xuan (William)
kirjoitti:[clip]
> > >
> > > - if (atomic_dec_and_test(&conn->refcnt)) {
> > > + if (atomic_dec_and_test(&conn->refcnt) &&
> > > + !test_bit(HCI_CONN_DISC, &conn->flags)) {
> > > unsigned long timeo;
> >
> > hci_abort_conn already checks if conn->abort_reason was already set, to
> > avoid queuing abort for the same conn again. Does this flag not try to
> > do the same thing?
>
> That is not enough. hci_conn occur UAF in hci_proto_disconn_ind() before enter
> hci_abort_conn().
Thanks, this was not clear to me from the patch.
So the problem is that the cancel_delayed_work_sync(&conn->disc_work)
in hci_conn_del doesn't help in a few cases:
1. [task A] hci_conn_del(conn) entered
2. [A] cancel_delayed_work_sync(conn->disc_work)
3. [B] concurrent hci_conn_drop(conn) queues disc_work again
4. [A] hci_conn_del finishes
5. UAF when disc_work runs
or without needing concurrency
1. hci_conn_del(conn) entered and finishes
2. hci_conn_drop(conn); hci_conn_put(conn); as done in several places
?
The hci_conn_del here is not necessarily from hci_abort_conn. Should
the atomic flag be set in hci_conn_del before
cancel_delayed_work_sync(&conn->disc_work) to catch possible other
cases?
> > There are potential races in hci_sync vs. handle reuse since the queued
> > abort is not canceled if the conn is deleted by something else. But now
> > I'm not sure syzbot hits this race.
>
> Sorry, can you give a specific scenario. I can't understand exactly what you mean.
As noted in the other patch:
1. hci_conn_abort(conn)
2. hci_cmd_sync_queue(hdev,abort_conn_sync,UINT_PTR(conn->handle))
3. something else (e.g. HCI event) deletes conn
4. something else (e.g. HCI event) creates conn2, with same handle
value
5. Queued abort_conn_sync executes. It needs to be delayed enough,
but doesn't need to be concurrent.
6. abort_conn_sync uses queued handle value, finds conn2 (not conn)
7. hci_abort_conn_sync(conn2, conn2->abort_reason)
8. Calling hci_abort_conn_sync with reason == 0 causes UAF
The UAF is because reason==0 is passed to l2cap_disconn_ind which does
not signal disconnection to the L2CAP layer, hci_abort_conn_sync
deletes conn immediately after that, and later on L2CAP tries to access
stale conn pointer.
> > >
> > > switch (conn->type) {
> > > diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> > > index 974631e652c1..f87281b4386f 100644
> > > --- a/net/bluetooth/hci_conn.c
> > > +++ b/net/bluetooth/hci_conn.c
> > > @@ -153,6 +153,9 @@ static void hci_conn_cleanup(struct hci_conn *conn)
> > >
> > >
> > >
> > >
> > > hci_conn_hash_del(hdev, conn);
> > >
> > >
> > >
> > >
> > > + if (HCI_CONN_HANDLE_UNSET(conn->handle))
> > > + ida_free(&hdev->unset_handle_ida, conn->handle);
> > > +
> > > if (conn->cleanup)
> > > conn->cleanup(conn);
> > >
> > >
> > >
> > >
> > > @@ -929,29 +932,17 @@ static void cis_cleanup(struct hci_conn *conn)
> > > hci_le_remove_cig(hdev, conn->iso_qos.ucast.cig);
> > > }
> > >
> > >
> > >
> > >
> > > -static u16 hci_conn_hash_alloc_unset(struct hci_dev *hdev)
> > > +static int hci_conn_hash_alloc_unset(struct hci_dev *hdev)
> > > {
> > > - struct hci_conn_hash *h = &hdev->conn_hash;
> > > - struct hci_conn *c;
> > > - u16 handle = HCI_CONN_HANDLE_MAX + 1;
> > > -
> > > - rcu_read_lock();
> > > -
> > > - list_for_each_entry_rcu(c, &h->list, list) {
> > > - /* Find the first unused handle */
> > > - if (handle == 0xffff || c->handle != handle)
> > > - break;
> > > - handle++;
> > > - }
> > > - rcu_read_unlock();
> >
> > The original hci_conn_hash_alloc_unset seems to have wrong logic. It'll
> > e.g. always return HCI_CONN_HANDLE_MAX+1 except if the first conn in
> > conn_hash (which is not in particular order) has that handle...
> >
> > The code paths adding/deleting conns or entering here / setting handles
> > should be holding hdev->lock, so probably no concurrency issue in it.
> >
> > Is syzbot happy with just this handle allocation fixed?
>
> Just fix handle, hci_conn occur UAF in hci_proto_disconn_ind() within hci_conn_timeout() process.
>
> >
> > > -
> > > - return handle;
> > > + return ida_alloc_range(&hdev->unset_handle_ida, HCI_CONN_HANDLE_MAX + 1,
> > > + U16_MAX, GFP_ATOMIC);
> > > }
> > >
> > >
> > >
> > >
> >
--
Pauli Virtanen
next prev parent reply other threads:[~2023-10-10 18:32 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-10-09 12:30 [PATCH v2] Bluetooth: Fix UAF for hci_chan Ziyang Xuan
2023-10-09 13:19 ` [v2] " bluez.test.bot
2023-10-09 17:31 ` [PATCH v2] " Luiz Augusto von Dentz
2023-10-10 12:31 ` Ziyang Xuan (William)
2023-10-09 20:37 ` Pauli Virtanen
2023-10-10 12:49 ` Ziyang Xuan (William)
2023-10-10 18:32 ` Pauli Virtanen [this message]
2023-10-10 18:51 ` Luiz Augusto von Dentz
2023-10-11 9:31 ` Ziyang Xuan (William)
2023-10-11 19:33 ` 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=a72b89cd520f502d6d384f97fcaf83f92ead147f.camel@iki.fi \
--to=pav@iki.fi \
--cc=linux-bluetooth@vger.kernel.org \
--cc=william.xuanziyang@huawei.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.