Bluetooth: Fix bt_sock_recvmsg return value
If recvmsg is called with a destination buffer that is too small to
receive the contents of skb in its entirety, the return value from
recvmsg was inconsistent with common SOCK_SEQPACKET or SOCK_DGRAM
semantics.
If destination buffer provided by userspace is too small (e.g. len <
copied), then MSG_TRUNC flag is set and copied is returned. Instead, it
should return the length of the message, which is consistent with how
other datagram based sockets act. Quoting 'man recv':
"All three calls return the length of the message on successful comple‐
tion. If a message is too long to fit in the supplied buffer, excess
bytes may be discarded depending on the type of socket the message is
received from."
and
"MSG_TRUNC (since Linux 2.2)
For raw (AF_PACKET), Internet datagram (since Linux
2.4.27/2.6.8), netlink (since Linux 2.6.22), and UNIX datagram
(since Linux 3.4) sockets: return the real length of the packet
or datagram, even when it was longer than the passed buffer."
Signed-off-by: Denis Kenzior <denkenz@gmail.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
committed by
Marcel Holtmann
parent
1c5bf998b3
commit
b5f34f9420
@@ -215,6 +215,7 @@ int bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
|
|||||||
struct sock *sk = sock->sk;
|
struct sock *sk = sock->sk;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
size_t copied;
|
size_t copied;
|
||||||
|
size_t skblen;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
BT_DBG("sock %p sk %p len %zu", sock, sk, len);
|
BT_DBG("sock %p sk %p len %zu", sock, sk, len);
|
||||||
@@ -230,6 +231,7 @@ int bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
skblen = skb->len;
|
||||||
copied = skb->len;
|
copied = skb->len;
|
||||||
if (len < copied) {
|
if (len < copied) {
|
||||||
msg->msg_flags |= MSG_TRUNC;
|
msg->msg_flags |= MSG_TRUNC;
|
||||||
@@ -248,6 +250,9 @@ int bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
|
|||||||
|
|
||||||
skb_free_datagram(sk, skb);
|
skb_free_datagram(sk, skb);
|
||||||
|
|
||||||
|
if (msg->msg_flags & MSG_TRUNC)
|
||||||
|
copied = skblen;
|
||||||
|
|
||||||
return err ? : copied;
|
return err ? : copied;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(bt_sock_recvmsg);
|
EXPORT_SYMBOL(bt_sock_recvmsg);
|
||||||
|
|||||||
Reference in New Issue
Block a user