Re: [PATCH v2 2/2] Bluetooth: hci_conn: verify connection is to be aborted before doing it

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Pauli,

On Sat, Sep 30, 2023 at 3:25 PM Pauli Virtanen <pav@xxxxxx> wrote:
>
> There is a race condition where a connection handle is reused, after
> hci_abort_conn but before abort_conn_sync is processed in hci_sync. In
> this case, hci_abort_conn_sync ends up working on the wrong connection,
> which can have abort_reason==0, in which case hci_connect_cfm is called
> with success status and then connection is deleted, which causes various
> use-after-free.
>
> Fix by checking abort_reason is nonzero before calling
> hci_abort_conn_sync. If it's zero, then the connection is probably a
> different one than we expected and should not be aborted.
>
> Also fix some theoretical UAF / races, where something frees the conn
> while hci_abort_conn_sync is working on it.
>
> Fixes: a13f316e90fd ("Bluetooth: hci_conn: Consolidate code for aborting connections")
> Reported-by: syzbot+a0c80b06ae2cb8895bc4@xxxxxxxxxxxxxxxxxxxxxxxxx
> Closes: https://lore.kernel.org/linux-bluetooth/0000000000005ab984060371583e@xxxxxxxxxx/
> Signed-off-by: Pauli Virtanen <pav@xxxxxx>
> ---
>
> Notes:
>     v2: drop one probably not necessary WARN_ON
>
>     Not sure how you'd hit this condition in real controller, but syzbot
>     does end up calling hci_abort_conn_sync with reason == 0 which then
>     causes havoc.
>
>     This can be verified: with a patch that changes abort_conn_sync to
>
>         2874    conn = hci_conn_hash_lookup_handle(hdev, handle);
>         2875    if (!conn || WARN_ON(!conn->abort_reason))
>         2876            return 0;
>
>     https://syzkaller.appspot.com/text?tag=Patch&x=16eff740680000
>
>     it hits that WARN_ON:
>
>     https://syzkaller.appspot.com/x/log.txt?x=10affb97a80000
>
> #syz test git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git master
>
>  net/bluetooth/hci_conn.c | 17 ++++++++++++++++-
>  1 file changed, 16 insertions(+), 1 deletion(-)
>
> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> index e62a5f368a51..22de82071e35 100644
> --- a/net/bluetooth/hci_conn.c
> +++ b/net/bluetooth/hci_conn.c
> @@ -2901,12 +2901,25 @@ static int abort_conn_sync(struct hci_dev *hdev, void *data)
>  {
>         struct hci_conn *conn;
>         u16 handle = PTR_UINT(data);
> +       u8 reason;
> +       int err;
> +
> +       rcu_read_lock();
>
>         conn = hci_conn_hash_lookup_handle(hdev, handle);
> +       if (conn) {
> +               reason = READ_ONCE(conn->abort_reason);
> +               conn = reason ? hci_conn_get(conn) : NULL;
> +       }
> +
> +       rcu_read_unlock();
> +
>         if (!conn)
>                 return 0;
>
> -       return hci_abort_conn_sync(hdev, conn, conn->abort_reason);
> +       err = hci_abort_conn_sync(hdev, conn, reason);
> +       hci_conn_put(conn);
> +       return err;
>  }
>
>  int hci_abort_conn(struct hci_conn *conn, u8 reason)
> @@ -2918,6 +2931,8 @@ int hci_abort_conn(struct hci_conn *conn, u8 reason)
>          */
>         if (conn->abort_reason)
>                 return 0;
> +       if (WARN_ON(!reason))
> +               reason = HCI_ERROR_UNSPECIFIED;
>
>         bt_dev_dbg(hdev, "handle 0x%2.2x reason 0x%2.2x", conn->handle, reason);
>
> --
> 2.41.0

Don't really like where this is going, the culprit here seems that we
are not able to cancel the callback when freeing the hci_conn so it
stays enqueued while the new connection is created with the same
handle, so I think we need to introduce a function that cancel queued
like Ive sent sometime back, that way we don't need to keep trying to
check if it is the same connection or not.


-- 
Luiz Augusto von Dentz




[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux