From: Desmond Cheong Zhi Xi desmondcheongzx@gmail.com
stable inclusion from linux-4.19.207 commit bc4b08383046f3282b6fa58cfcef05bd13e52b93
--------------------------------
[ 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 Conflicts: net/bluetooth/sco.c [yyl: adjust context] Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- net/bluetooth/sco.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 9c086ad5f3a78..1a314f5c3fc7e 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -97,7 +97,6 @@ static void sco_sock_timeout(struct work_struct *work) sk->sk_state_change(sk); release_sock(sk);
- sco_sock_kill(sk); sock_put(sk); }
@@ -196,7 +195,6 @@ static void sco_conn_del(struct hci_conn *hcon, int err) sco_sock_clear_timer(sk); sco_chan_del(sk, err); release_sock(sk); - sco_sock_kill(sk); sock_put(sk);
/* Ensure no more work items will run before freeing conn. */ @@ -403,8 +401,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); @@ -456,7 +453,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)