Bluetooth: af_bluetooth: Fix deadlock
BugLink: https://bugs.launchpad.net/bugs/2060097
[ Upstream commit f7b94bdc1ec107c92262716b073b3e816d4784fb ]
Attemting to do sock_lock on .recvmsg may cause a deadlock as shown
bellow, so instead of using sock_sock this uses sk_receive_queue.lock
on bt_sock_ioctl to avoid the UAF:
INFO: task kworker/u9:1:121 blocked for more than 30 seconds.
Not tainted 6.7.6-lemon #183
Workqueue: hci0 hci_rx_work
Call Trace:
<TASK>
__schedule+0x37d/0xa00
schedule+0x32/0xe0
__lock_sock+0x68/0xa0
? __pfx_autoremove_wake_function+0x10/0x10
lock_sock_nested+0x43/0x50
l2cap_sock_recv_cb+0x21/0xa0
l2cap_recv_frame+0x55b/0x30a0
? psi_task_switch+0xeb/0x270
? finish_task_switch.isra.0+0x93/0x2a0
hci_rx_work+0x33a/0x3f0
process_one_work+0x13a/0x2f0
worker_thread+0x2f0/0x410
? __pfx_worker_thread+0x10/0x10
kthread+0xe0/0x110
? __pfx_kthread+0x10/0x10
ret_from_fork+0x2c/0x50
? __pfx_kthread+0x10/0x10
ret_from_fork_asm+0x1b/0x30
</TASK>
Fixes: 2e07e8348e ("Bluetooth: af_bluetooth: Fix Use-After-Free in bt_sock_recvmsg")
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
(cherry picked from commit 2c9e2df022ef8b9d7fac58a04a2ef4ed25288955)
Signed-off-by: Paolo Pisati <paolo.pisati@canonical.com>
This commit is contained in:
committed by
Roxana Nicolescu
parent
1eab9360bc
commit
2eb6b3ea12
@@ -309,14 +309,11 @@ int bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
|
||||
if (flags & MSG_OOB)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
skb = skb_recv_datagram(sk, flags, &err);
|
||||
if (!skb) {
|
||||
if (sk->sk_shutdown & RCV_SHUTDOWN)
|
||||
err = 0;
|
||||
|
||||
release_sock(sk);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -346,8 +343,6 @@ int bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
|
||||
|
||||
skb_free_datagram(sk, skb);
|
||||
|
||||
release_sock(sk);
|
||||
|
||||
if (flags & MSG_TRUNC)
|
||||
copied = skblen;
|
||||
|
||||
@@ -570,10 +565,11 @@ int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
|
||||
if (sk->sk_state == BT_LISTEN)
|
||||
return -EINVAL;
|
||||
|
||||
lock_sock(sk);
|
||||
spin_lock(&sk->sk_receive_queue.lock);
|
||||
skb = skb_peek(&sk->sk_receive_queue);
|
||||
amount = skb ? skb->len : 0;
|
||||
release_sock(sk);
|
||||
spin_unlock(&sk->sk_receive_queue.lock);
|
||||
|
||||
err = put_user(amount, (int __user *)arg);
|
||||
break;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user