Skip to content

Commit

Permalink
Bluetooth: Improve setsockopt() handling of malformed user input
Browse files Browse the repository at this point in the history
The bt_copy_from_sockptr() return value is being misinterpreted by most
users: a non-zero result is mistakenly assumed to represent an error code,
but actually indicates the number of bytes that could not be copied.

Remove bt_copy_from_sockptr() and adapt callers to use
copy_safe_from_sockptr().

For sco_sock_setsockopt() (case BT_CODEC) use copy_struct_from_sockptr() to
scrub parts of uninitialized buffer.

Opportunistically, rename `len` to `optlen` in hci_sock_setsockopt_old()
and hci_sock_setsockopt().

Fixes: 51eda36 ("Bluetooth: SCO: Fix not validating setsockopt user input")
Fixes: a97de7b ("Bluetooth: RFCOMM: Fix not validating setsockopt user input")
Fixes: 4f39512 ("Bluetooth: L2CAP: Fix not validating setsockopt user input")
Fixes: 9e8742c ("Bluetooth: ISO: Fix not validating setsockopt user input")
Fixes: b218606 ("Bluetooth: hci_sock: Fix not validating setsockopt user input")
Reviewed-by: Luiz Augusto von Dentz <[email protected]>
Reviewed-by: David Wei <[email protected]>
Signed-off-by: Michal Luczaj <[email protected]>
Signed-off-by: Luiz Augusto von Dentz <[email protected]>
  • Loading branch information
mmhal authored and Vudentz committed Dec 11, 2024
1 parent 3dd002f commit 3e643e4
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 40 deletions.
9 changes: 0 additions & 9 deletions include/net/bluetooth/bluetooth.h
Original file line number Diff line number Diff line change
Expand Up @@ -590,15 +590,6 @@ static inline struct sk_buff *bt_skb_sendmmsg(struct sock *sk,
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);
__u8 bt_status(int err);

Expand Down
14 changes: 7 additions & 7 deletions net/bluetooth/hci_sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -1926,7 +1926,7 @@ static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg,
}

static int hci_sock_setsockopt_old(struct socket *sock, int level, int optname,
sockptr_t optval, unsigned int len)
sockptr_t optval, unsigned int optlen)
{
struct hci_ufilter uf = { .opcode = 0 };
struct sock *sk = sock->sk;
Expand All @@ -1943,7 +1943,7 @@ static int hci_sock_setsockopt_old(struct socket *sock, int level, int optname,

switch (optname) {
case HCI_DATA_DIR:
err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, len);
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
if (err)
break;

Expand All @@ -1954,7 +1954,7 @@ static int hci_sock_setsockopt_old(struct socket *sock, int level, int optname,
break;

case HCI_TIME_STAMP:
err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, len);
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
if (err)
break;

Expand All @@ -1974,7 +1974,7 @@ static int hci_sock_setsockopt_old(struct socket *sock, int level, int optname,
uf.event_mask[1] = *((u32 *) f->event_mask + 1);
}

err = bt_copy_from_sockptr(&uf, sizeof(uf), optval, len);
err = copy_safe_from_sockptr(&uf, sizeof(uf), optval, optlen);
if (err)
break;

Expand Down Expand Up @@ -2005,7 +2005,7 @@ static int hci_sock_setsockopt_old(struct socket *sock, int level, int optname,
}

static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
sockptr_t optval, unsigned int len)
sockptr_t optval, unsigned int optlen)
{
struct sock *sk = sock->sk;
int err = 0;
Expand All @@ -2015,7 +2015,7 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname,

if (level == SOL_HCI)
return hci_sock_setsockopt_old(sock, level, optname, optval,
len);
optlen);

if (level != SOL_BLUETOOTH)
return -ENOPROTOOPT;
Expand All @@ -2035,7 +2035,7 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
goto done;
}

err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, len);
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
if (err)
break;

Expand Down
10 changes: 5 additions & 5 deletions net/bluetooth/iso.c
Original file line number Diff line number Diff line change
Expand Up @@ -1566,7 +1566,7 @@ static int iso_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}

err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
if (err)
break;

Expand All @@ -1577,7 +1577,7 @@ static int iso_sock_setsockopt(struct socket *sock, int level, int optname,
break;

case BT_PKT_STATUS:
err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
if (err)
break;

Expand All @@ -1596,7 +1596,7 @@ static int iso_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}

err = bt_copy_from_sockptr(&qos, sizeof(qos), optval, optlen);
err = copy_safe_from_sockptr(&qos, sizeof(qos), optval, optlen);
if (err)
break;

Expand All @@ -1617,8 +1617,8 @@ static int iso_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}

err = bt_copy_from_sockptr(iso_pi(sk)->base, optlen, optval,
optlen);
err = copy_safe_from_sockptr(iso_pi(sk)->base, optlen, optval,
optlen);
if (err)
break;

Expand Down
20 changes: 11 additions & 9 deletions net/bluetooth/l2cap_sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -755,7 +755,8 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
opts.max_tx = chan->max_tx;
opts.txwin_size = chan->tx_win;

err = bt_copy_from_sockptr(&opts, sizeof(opts), optval, optlen);
err = copy_safe_from_sockptr(&opts, sizeof(opts), optval,
optlen);
if (err)
break;

Expand Down Expand Up @@ -800,7 +801,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
break;

case L2CAP_LM:
err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
if (err)
break;

Expand Down Expand Up @@ -909,7 +910,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,

sec.level = BT_SECURITY_LOW;

err = bt_copy_from_sockptr(&sec, sizeof(sec), optval, optlen);
err = copy_safe_from_sockptr(&sec, sizeof(sec), optval, optlen);
if (err)
break;

Expand Down Expand Up @@ -956,7 +957,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}

err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
if (err)
break;

Expand All @@ -970,7 +971,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
break;

case BT_FLUSHABLE:
err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
if (err)
break;

Expand Down Expand Up @@ -1004,7 +1005,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,

pwr.force_active = BT_POWER_FORCE_ACTIVE_ON;

err = bt_copy_from_sockptr(&pwr, sizeof(pwr), optval, optlen);
err = copy_safe_from_sockptr(&pwr, sizeof(pwr), optval, optlen);
if (err)
break;

Expand All @@ -1015,7 +1016,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
break;

case BT_CHANNEL_POLICY:
err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
if (err)
break;

Expand Down Expand Up @@ -1046,7 +1047,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}

err = bt_copy_from_sockptr(&mtu, sizeof(mtu), optval, optlen);
err = copy_safe_from_sockptr(&mtu, sizeof(mtu), optval, optlen);
if (err)
break;

Expand Down Expand Up @@ -1076,7 +1077,8 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}

err = bt_copy_from_sockptr(&mode, sizeof(mode), optval, optlen);
err = copy_safe_from_sockptr(&mode, sizeof(mode), optval,
optlen);
if (err)
break;

Expand Down
9 changes: 4 additions & 5 deletions net/bluetooth/rfcomm/sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -629,10 +629,9 @@ static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname,

switch (optname) {
case RFCOMM_LM:
if (bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen)) {
err = -EFAULT;
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
if (err)
break;
}

if (opt & RFCOMM_LM_FIPS) {
err = -EINVAL;
Expand Down Expand Up @@ -685,7 +684,7 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname,

sec.level = BT_SECURITY_LOW;

err = bt_copy_from_sockptr(&sec, sizeof(sec), optval, optlen);
err = copy_safe_from_sockptr(&sec, sizeof(sec), optval, optlen);
if (err)
break;

Expand All @@ -703,7 +702,7 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}

err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
if (err)
break;

Expand Down
11 changes: 6 additions & 5 deletions net/bluetooth/sco.c
Original file line number Diff line number Diff line change
Expand Up @@ -896,7 +896,7 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}

err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
if (err)
break;

Expand All @@ -915,8 +915,8 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,

voice.setting = sco_pi(sk)->setting;

err = bt_copy_from_sockptr(&voice, sizeof(voice), optval,
optlen);
err = copy_safe_from_sockptr(&voice, sizeof(voice), optval,
optlen);
if (err)
break;

Expand All @@ -941,7 +941,7 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
break;

case BT_PKT_STATUS:
err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
if (err)
break;

Expand Down Expand Up @@ -984,7 +984,8 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}

err = bt_copy_from_sockptr(buffer, optlen, optval, optlen);
err = copy_struct_from_sockptr(buffer, sizeof(buffer), optval,
optlen);
if (err) {
hci_dev_put(hdev);
break;
Expand Down

0 comments on commit 3e643e4

Please sign in to comment.