| From 49c0ffcaea7420f0af7e7c1ff8922dd0e0036d27 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Sat, 28 Aug 2021 18:18:18 +0200 |
| Subject: Bluetooth: sco: Fix lock_sock() blockage by memcpy_from_msg() |
| |
| From: Takashi Iwai <tiwai@suse.de> |
| |
| [ Upstream commit 99c23da0eed4fd20cae8243f2b51e10e66aa0951 ] |
| |
| The sco_send_frame() also takes lock_sock() during memcpy_from_msg() |
| call that may be endlessly blocked by a task with userfaultd |
| technique, and this will result in a hung task watchdog trigger. |
| |
| Just like the similar fix for hci_sock_sendmsg() in commit |
| 92c685dc5de0 ("Bluetooth: reorganize functions..."), this patch moves |
| the memcpy_from_msg() out of lock_sock() for addressing the hang. |
| |
| This should be the last piece for fixing CVE-2021-3640 after a few |
| already queued fixes. |
| |
| Signed-off-by: Takashi Iwai <tiwai@suse.de> |
| Signed-off-by: Marcel Holtmann <marcel@holtmann.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/bluetooth/sco.c | 24 ++++++++++++++++-------- |
| 1 file changed, 16 insertions(+), 8 deletions(-) |
| |
| diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c |
| index 1915943bb646a..cc5a1d2545679 100644 |
| --- a/net/bluetooth/sco.c |
| +++ b/net/bluetooth/sco.c |
| @@ -280,7 +280,8 @@ static int sco_connect(struct hci_dev *hdev, struct sock *sk) |
| return err; |
| } |
| |
| -static int sco_send_frame(struct sock *sk, struct msghdr *msg, int len) |
| +static int sco_send_frame(struct sock *sk, void *buf, int len, |
| + unsigned int msg_flags) |
| { |
| struct sco_conn *conn = sco_pi(sk)->conn; |
| struct sk_buff *skb; |
| @@ -292,15 +293,11 @@ static int sco_send_frame(struct sock *sk, struct msghdr *msg, int len) |
| |
| BT_DBG("sk %p len %d", sk, len); |
| |
| - skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err); |
| + skb = bt_skb_send_alloc(sk, len, msg_flags & MSG_DONTWAIT, &err); |
| if (!skb) |
| return err; |
| |
| - if (memcpy_from_msg(skb_put(skb, len), msg, len)) { |
| - kfree_skb(skb); |
| - return -EFAULT; |
| - } |
| - |
| + memcpy(skb_put(skb, len), buf, len); |
| hci_send_sco(conn->hcon, skb); |
| |
| return len; |
| @@ -714,6 +711,7 @@ static int sco_sock_sendmsg(struct socket *sock, struct msghdr *msg, |
| size_t len) |
| { |
| struct sock *sk = sock->sk; |
| + void *buf; |
| int err; |
| |
| BT_DBG("sock %p, sk %p", sock, sk); |
| @@ -725,14 +723,24 @@ static int sco_sock_sendmsg(struct socket *sock, struct msghdr *msg, |
| if (msg->msg_flags & MSG_OOB) |
| return -EOPNOTSUPP; |
| |
| + buf = kmalloc(len, GFP_KERNEL); |
| + if (!buf) |
| + return -ENOMEM; |
| + |
| + if (memcpy_from_msg(buf, msg, len)) { |
| + kfree(buf); |
| + return -EFAULT; |
| + } |
| + |
| lock_sock(sk); |
| |
| if (sk->sk_state == BT_CONNECTED) |
| - err = sco_send_frame(sk, msg, len); |
| + err = sco_send_frame(sk, buf, len, msg->msg_flags); |
| else |
| err = -ENOTCONN; |
| |
| release_sock(sk); |
| + kfree(buf); |
| return err; |
| } |
| |
| -- |
| 2.33.0 |
| |