| From 51eda36d33e43201e7a4fd35232e069b2c850b01 Mon Sep 17 00:00:00 2001 |
| From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> |
| Date: Fri, 5 Apr 2024 15:41:52 -0400 |
| Subject: Bluetooth: SCO: Fix not validating setsockopt user input |
| |
| From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> |
| |
| commit 51eda36d33e43201e7a4fd35232e069b2c850b01 upstream. |
| |
| syzbot reported sco_sock_setsockopt() is copying data without |
| checking user input length. |
| |
| BUG: KASAN: slab-out-of-bounds in copy_from_sockptr_offset |
| include/linux/sockptr.h:49 [inline] |
| BUG: KASAN: slab-out-of-bounds in copy_from_sockptr |
| include/linux/sockptr.h:55 [inline] |
| BUG: KASAN: slab-out-of-bounds in sco_sock_setsockopt+0xc0b/0xf90 |
| net/bluetooth/sco.c:893 |
| Read of size 4 at addr ffff88805f7b15a3 by task syz-executor.5/12578 |
| |
| Fixes: ad10b1a48754 ("Bluetooth: Add Bluetooth socket voice option") |
| Fixes: b96e9c671b05 ("Bluetooth: Add BT_DEFER_SETUP option to sco socket") |
| Fixes: 00398e1d5183 ("Bluetooth: Add support for BT_PKT_STATUS CMSG data for SCO connections") |
| Fixes: f6873401a608 ("Bluetooth: Allow setting of codec for HFP offload use case") |
| Reported-by: syzbot <syzkaller@googlegroups.com> |
| Signed-off-by: Eric Dumazet <edumazet@google.com> |
| Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| Signed-off-by: Keerthana K <keerthana.kalyanasundaram@broadcom.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| include/net/bluetooth/bluetooth.h | 9 +++++++++ |
| net/bluetooth/sco.c | 19 ++++++++----------- |
| 2 files changed, 17 insertions(+), 11 deletions(-) |
| |
| --- a/include/net/bluetooth/bluetooth.h |
| +++ b/include/net/bluetooth/bluetooth.h |
| @@ -487,6 +487,15 @@ static inline struct sk_buff *bt_skb_sen |
| return skb; |
| } |
| |
| +static inline int bt_copy_from_sockptr(void *dst, size_t dst_size, |
| + sockptr_t src, size_t src_size) |
| +{ |
| + if (dst_size > src_size) |
| + return -EINVAL; |
| + |
| + return copy_from_sockptr(dst, src, dst_size); |
| +} |
| + |
| int bt_to_errno(u16 code); |
| |
| void hci_sock_set_flag(struct sock *sk, int nr); |
| --- a/net/bluetooth/sco.c |
| +++ b/net/bluetooth/sco.c |
| @@ -829,7 +829,7 @@ static int sco_sock_setsockopt(struct so |
| sockptr_t optval, unsigned int optlen) |
| { |
| struct sock *sk = sock->sk; |
| - int len, err = 0; |
| + int err = 0; |
| struct bt_voice voice; |
| u32 opt; |
| |
| @@ -845,10 +845,9 @@ static int sco_sock_setsockopt(struct so |
| break; |
| } |
| |
| - if (copy_from_sockptr(&opt, optval, sizeof(u32))) { |
| - err = -EFAULT; |
| + err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen); |
| + if (err) |
| break; |
| - } |
| |
| if (opt) |
| set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); |
| @@ -865,11 +864,10 @@ static int sco_sock_setsockopt(struct so |
| |
| voice.setting = sco_pi(sk)->setting; |
| |
| - len = min_t(unsigned int, sizeof(voice), optlen); |
| - if (copy_from_sockptr(&voice, optval, len)) { |
| - err = -EFAULT; |
| + err = bt_copy_from_sockptr(&voice, sizeof(voice), optval, |
| + optlen); |
| + if (err) |
| break; |
| - } |
| |
| /* Explicitly check for these values */ |
| if (voice.setting != BT_VOICE_TRANSPARENT && |
| @@ -882,10 +880,9 @@ static int sco_sock_setsockopt(struct so |
| break; |
| |
| case BT_PKT_STATUS: |
| - if (copy_from_sockptr(&opt, optval, sizeof(u32))) { |
| - err = -EFAULT; |
| + err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen); |
| + if (err) |
| break; |
| - } |
| |
| if (opt) |
| sco_pi(sk)->cmsg_mask |= SCO_CMSG_PKT_STATUS; |