| From: Soheil Hassas Yeganeh <soheil@google.com> |
| Date: Fri, 4 Nov 2016 15:36:49 -0400 |
| Subject: sock: fix sendmmsg for partial sendmsg |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| [ Upstream commit 3023898b7d4aac65987bd2f485cc22390aae6f78 ] |
| |
| Do not send the next message in sendmmsg for partial sendmsg |
| invocations. |
| |
| sendmmsg assumes that it can continue sending the next message |
| when the return value of the individual sendmsg invocations |
| is positive. It results in corrupting the data for TCP, |
| SCTP, and UNIX streams. |
| |
| For example, sendmmsg([["abcd"], ["efgh"]]) can result in a stream |
| of "aefgh" if the first sendmsg invocation sends only the first |
| byte while the second sendmsg goes through. |
| |
| Datagram sockets either send the entire datagram or fail, so |
| this patch affects only sockets of type SOCK_STREAM and |
| SOCK_SEQPACKET. |
| |
| Fixes: 228e548e6020 ("net: Add sendmmsg socket system call") |
| Signed-off-by: Soheil Hassas Yeganeh <soheil@google.com> |
| Signed-off-by: Eric Dumazet <edumazet@google.com> |
| Signed-off-by: Willem de Bruijn <willemb@google.com> |
| Signed-off-by: Neal Cardwell <ncardwell@google.com> |
| Acked-by: Maciej Żenczykowski <maze@google.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| [bwh: Backported to 3.16: we don't have the iov_iter API, so make |
| ___sys_sendmsg() calculate and write back the remaining length] |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| net/socket.c | 2 ++ |
| 1 file changed, 2 insertions(+) |
| |
| --- a/net/socket.c |
| +++ b/net/socket.c |
| @@ -1998,7 +1998,7 @@ static int copy_msghdr_from_user(struct |
| |
| static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg, |
| struct msghdr *msg_sys, unsigned int flags, |
| - struct used_address *used_address) |
| + struct used_address *used_address, int *residue) |
| { |
| struct compat_msghdr __user *msg_compat = |
| (struct compat_msghdr __user *)msg; |
| @@ -2097,6 +2097,8 @@ static int ___sys_sendmsg(struct socket |
| memcpy(&used_address->name, msg_sys->msg_name, |
| used_address->name_len); |
| } |
| + if (residue && err >= 0) |
| + *residue = total_len - err; |
| |
| out_freectl: |
| if (ctl_buf != ctl) |
| @@ -2122,7 +2124,7 @@ long __sys_sendmsg(int fd, struct msghdr |
| if (!sock) |
| goto out; |
| |
| - err = ___sys_sendmsg(sock, msg, &msg_sys, flags, NULL); |
| + err = ___sys_sendmsg(sock, msg, &msg_sys, flags, NULL, NULL); |
| |
| fput_light(sock->file, fput_needed); |
| out: |
| @@ -2149,6 +2151,7 @@ int __sys_sendmmsg(int fd, struct mmsghd |
| struct compat_mmsghdr __user *compat_entry; |
| struct msghdr msg_sys; |
| struct used_address used_address; |
| + int residue; |
| |
| if (vlen > UIO_MAXIOV) |
| vlen = UIO_MAXIOV; |
| @@ -2167,7 +2170,8 @@ int __sys_sendmmsg(int fd, struct mmsghd |
| while (datagrams < vlen) { |
| if (MSG_CMSG_COMPAT & flags) { |
| err = ___sys_sendmsg(sock, (struct msghdr __user *)compat_entry, |
| - &msg_sys, flags, &used_address); |
| + &msg_sys, flags, &used_address, |
| + &residue); |
| if (err < 0) |
| break; |
| err = __put_user(err, &compat_entry->msg_len); |
| @@ -2175,7 +2179,8 @@ int __sys_sendmmsg(int fd, struct mmsghd |
| } else { |
| err = ___sys_sendmsg(sock, |
| (struct msghdr __user *)entry, |
| - &msg_sys, flags, &used_address); |
| + &msg_sys, flags, &used_address, |
| + &residue); |
| if (err < 0) |
| break; |
| err = put_user(err, &entry->msg_len); |
| @@ -2185,6 +2190,8 @@ int __sys_sendmmsg(int fd, struct mmsghd |
| if (err) |
| break; |
| ++datagrams; |
| + if (residue) |
| + break; |
| } |
| |
| fput_light(sock->file, fput_needed); |