]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
Bluetooth: fix repeated calls to sco_sock_kill
authorDesmond Cheong Zhi Xi <desmondcheongzx@gmail.com>
Tue, 10 Aug 2021 04:14:10 +0000 (12:14 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 22 Sep 2021 09:41:20 +0000 (11:41 +0200)
[ Upstream commit e1dee2c1de2b4dd00eb44004a4bda6326ed07b59 ]

In commit 4e1a720d0312 ("Bluetooth: avoid killing an already killed
socket"), a check was added to sco_sock_kill to skip killing a socket
if the SOCK_DEAD flag was set.

This was done after a trace for a use-after-free bug showed that the
same sock pointer was being killed twice.

Unfortunately, this check prevents sco_sock_kill from running on any
socket. sco_sock_kill kills a socket only if it's zapped and orphaned,
however sock_orphan announces that the socket is dead before detaching
it. i.e., orphaned sockets have the SOCK_DEAD flag set.

To fix this, we remove the check for SOCK_DEAD, and avoid repeated
calls to sco_sock_kill by removing incorrect calls in:

1. sco_sock_timeout. The socket should not be killed on timeout as
further processing is expected to be done. For example,
sco_sock_connect sets the timer then waits for the socket to be
connected or for an error to be returned.

2. sco_conn_del. This function should clean up resources for the
connection, but the socket itself should be cleaned up in
sco_sock_release.

3. sco_sock_close. Calls to sco_sock_close in sco_sock_cleanup_listen
and sco_sock_release are followed by sco_sock_kill. Hence the
duplicated call should be removed.

Fixes: 4e1a720d0312 ("Bluetooth: avoid killing an already killed socket")
Signed-off-by: Desmond Cheong Zhi Xi <desmondcheongzx@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
net/bluetooth/sco.c

index cad0d27507357475f71cd88d8dcc566ec840ecdb..701d230fb9cf6d3d6faf87c1865af7ea2d41082d 100644 (file)
@@ -83,7 +83,6 @@ static void sco_sock_timeout(unsigned long arg)
        sk->sk_state_change(sk);
        bh_unlock_sock(sk);
 
-       sco_sock_kill(sk);
        sock_put(sk);
 }
 
@@ -175,7 +174,6 @@ static void sco_conn_del(struct hci_conn *hcon, int err)
                sco_sock_clear_timer(sk);
                sco_chan_del(sk, err);
                bh_unlock_sock(sk);
-               sco_sock_kill(sk);
                sock_put(sk);
        }
 
@@ -392,8 +390,7 @@ static void sco_sock_cleanup_listen(struct sock *parent)
  */
 static void sco_sock_kill(struct sock *sk)
 {
-       if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket ||
-           sock_flag(sk, SOCK_DEAD))
+       if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
                return;
 
        BT_DBG("sk %p state %d", sk, sk->sk_state);
@@ -445,7 +442,6 @@ static void sco_sock_close(struct sock *sk)
        lock_sock(sk);
        __sco_sock_close(sk);
        release_sock(sk);
-       sco_sock_kill(sk);
 }
 
 static void sco_sock_init(struct sock *sk, struct sock *parent)