From 666547ff591cebdedc4679bf6b1b3f3383a8dea3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 6 Apr 2014 14:03:05 -0400 Subject: separate kernel- and userland-side msghdr Kernel-side struct msghdr is (currently) using the same layout as userland one, but it's not a one-to-one copy - even without considering 32bit compat issues, we have msg_iov, msg_name and msg_control copied to kernel[1]. It's fairly localized, so we get away with a few functions where that knowledge is needed (and we could shrink that set even more). Pretty much everything deals with the kernel-side variant and the few places that want userland one just use a bunch of force-casts to paper over the differences. The thing is, kernel-side definition of struct msghdr is *not* exposed in include/uapi - libc doesn't see it, etc. So we can add struct user_msghdr, with proper annotations and let the few places that ever deal with those beasts use it for userland pointers. Saner typechecking aside, that will allow to change the layout of kernel-side msghdr - e.g. replace msg_iov/msg_iovlen there with struct iov_iter, getting rid of the need to modify the iovec as we copy data to/from it, etc. We could introduce kernel_msghdr instead, but that would create much more noise - the absolute majority of the instances would need to have the type switched to kernel_msghdr and definition of struct msghdr in include/linux/socket.h is not going to be seen by userland anyway. This commit just introduces user_msghdr and switches the few places that are dealing with userland-side msghdr to it. [1] actually, it's even trickier than that - we copy msg_control for sendmsg, but keep the userland address on recvmsg. Signed-off-by: Al Viro --- include/linux/socket.h | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'include/linux/socket.h') diff --git a/include/linux/socket.h b/include/linux/socket.h index bb9b8364007..51bd6668b80 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -53,10 +53,20 @@ struct msghdr { __kernel_size_t msg_controllen; /* ancillary data buffer length */ unsigned int msg_flags; /* flags on received message */ }; + +struct user_msghdr { + void __user *msg_name; /* ptr to socket address structure */ + int msg_namelen; /* size of socket address structure */ + struct iovec __user *msg_iov; /* scatter/gather array */ + __kernel_size_t msg_iovlen; /* # elements in msg_iov */ + void __user *msg_control; /* ancillary data */ + __kernel_size_t msg_controllen; /* ancillary data buffer length */ + unsigned int msg_flags; /* flags on received message */ +}; /* For recvmmsg/sendmmsg */ struct mmsghdr { - struct msghdr msg_hdr; + struct user_msghdr msg_hdr; unsigned int msg_len; }; @@ -319,8 +329,8 @@ extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data); struct timespec; /* The __sys_...msg variants allow MSG_CMSG_COMPAT */ -extern long __sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags); -extern long __sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags); +extern long __sys_recvmsg(int fd, struct user_msghdr __user *msg, unsigned flags); +extern long __sys_sendmsg(int fd, struct user_msghdr __user *msg, unsigned flags); extern int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, unsigned int flags, struct timespec *timeout); extern int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, -- cgit v1.2.3-70-g09d2 From 08adb7dabd4874cc5666b4490653b26534702ce0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 10 Nov 2014 20:23:13 -0500 Subject: fold verify_iovec() into copy_msghdr_from_user() ... and do the same on the compat side of things. Signed-off-by: Al Viro --- include/linux/socket.h | 1 - include/net/compat.h | 5 ++- net/compat.c | 52 ++++++++++++---------------- net/core/iovec.c | 38 --------------------- net/socket.c | 93 ++++++++++++++++++++++++++++---------------------- 5 files changed, 77 insertions(+), 112 deletions(-) (limited to 'include/linux/socket.h') diff --git a/include/linux/socket.h b/include/linux/socket.h index 51bd6668b80..de5222832be 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -322,7 +322,6 @@ extern int csum_partial_copy_fromiovecend(unsigned char *kdata, extern unsigned long iov_pages(const struct iovec *iov, int offset, unsigned long nr_segs); -extern int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *address, int mode); extern int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr); extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data); diff --git a/include/net/compat.h b/include/net/compat.h index 3b603b199c0..42a9c843117 100644 --- a/include/net/compat.h +++ b/include/net/compat.h @@ -40,9 +40,8 @@ int compat_sock_get_timestampns(struct sock *, struct timespec __user *); #define compat_mmsghdr mmsghdr #endif /* defined(CONFIG_COMPAT) */ -int get_compat_msghdr(struct msghdr *, struct compat_msghdr __user *); -int verify_compat_iovec(struct msghdr *, struct iovec *, - struct sockaddr_storage *, int); +ssize_t get_compat_msghdr(struct msghdr *, struct compat_msghdr __user *, + struct sockaddr __user **, struct iovec **); asmlinkage long compat_sys_sendmsg(int, struct compat_msghdr __user *, unsigned int); asmlinkage long compat_sys_sendmmsg(int, struct compat_mmsghdr __user *, diff --git a/net/compat.c b/net/compat.c index 7b4b6ad1323..062f157d2a6 100644 --- a/net/compat.c +++ b/net/compat.c @@ -31,14 +31,18 @@ #include #include -int get_compat_msghdr(struct msghdr *kmsg, struct compat_msghdr __user *umsg) +ssize_t get_compat_msghdr(struct msghdr *kmsg, + struct compat_msghdr __user *umsg, + struct sockaddr __user **save_addr, + struct iovec **iov) { - compat_uptr_t tmp1, tmp2, tmp3; + compat_uptr_t uaddr, uiov, tmp3; + ssize_t err; if (!access_ok(VERIFY_READ, umsg, sizeof(*umsg)) || - __get_user(tmp1, &umsg->msg_name) || + __get_user(uaddr, &umsg->msg_name) || __get_user(kmsg->msg_namelen, &umsg->msg_namelen) || - __get_user(tmp2, &umsg->msg_iov) || + __get_user(uiov, &umsg->msg_iov) || __get_user(kmsg->msg_iovlen, &umsg->msg_iovlen) || __get_user(tmp3, &umsg->msg_control) || __get_user(kmsg->msg_controllen, &umsg->msg_controllen) || @@ -46,44 +50,32 @@ int get_compat_msghdr(struct msghdr *kmsg, struct compat_msghdr __user *umsg) return -EFAULT; if (kmsg->msg_namelen > sizeof(struct sockaddr_storage)) kmsg->msg_namelen = sizeof(struct sockaddr_storage); - kmsg->msg_name = compat_ptr(tmp1); - kmsg->msg_iov = compat_ptr(tmp2); kmsg->msg_control = compat_ptr(tmp3); - return 0; -} -/* I've named the args so it is easy to tell whose space the pointers are in. */ -int verify_compat_iovec(struct msghdr *kern_msg, struct iovec *iov, - struct sockaddr_storage *kern_address, int mode) -{ - struct compat_iovec __user *p; - struct iovec *res; - int err; + if (save_addr) + *save_addr = compat_ptr(uaddr); - if (kern_msg->msg_name && kern_msg->msg_namelen) { - if (mode == WRITE) { - int err = move_addr_to_kernel(kern_msg->msg_name, - kern_msg->msg_namelen, - kern_address); + if (uaddr && kmsg->msg_namelen) { + if (!save_addr) { + err = move_addr_to_kernel(compat_ptr(uaddr), + kmsg->msg_namelen, + kmsg->msg_name); if (err < 0) return err; } - kern_msg->msg_name = kern_address; } else { - kern_msg->msg_name = NULL; - kern_msg->msg_namelen = 0; + kmsg->msg_name = NULL; + kmsg->msg_namelen = 0; } - if (kern_msg->msg_iovlen > UIO_MAXIOV) + if (kmsg->msg_iovlen > UIO_MAXIOV) return -EMSGSIZE; - p = (struct compat_iovec __user *)kern_msg->msg_iov; - err = compat_rw_copy_check_uvector(mode, p, kern_msg->msg_iovlen, - UIO_FASTIOV, iov, &res); + err = compat_rw_copy_check_uvector(save_addr ? READ : WRITE, + compat_ptr(uiov), kmsg->msg_iovlen, + UIO_FASTIOV, *iov, iov); if (err >= 0) - kern_msg->msg_iov = res; - else if (res != iov) - kfree(res); + kmsg->msg_iov = *iov; return err; } diff --git a/net/core/iovec.c b/net/core/iovec.c index 86beeea61d7..dcbe98b3726 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c @@ -27,44 +27,6 @@ #include #include -/* - * Verify iovec. The caller must ensure that the iovec is big enough - * to hold the message iovec. - * - * Save time not doing access_ok. copy_*_user will make this work - * in any case. - */ - -int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *address, int mode) -{ - struct iovec *res; - int err; - - if (m->msg_name && m->msg_namelen) { - if (mode == WRITE) { - void __user *namep = (void __user __force *)m->msg_name; - int err = move_addr_to_kernel(namep, m->msg_namelen, - address); - if (err < 0) - return err; - } - m->msg_name = address; - } else { - m->msg_name = NULL; - m->msg_namelen = 0; - } - if (m->msg_iovlen > UIO_MAXIOV) - return -EMSGSIZE; - - err = rw_copy_check_uvector(mode, (void __user __force *)m->msg_iov, - m->msg_iovlen, UIO_FASTIOV, iov, &res); - if (err >= 0) - m->msg_iov = res; - else if (res != iov) - kfree(res); - return err; -} - /* * And now for the all-in-one: copy and checksum from a user iovec * directly to a datagram diff --git a/net/socket.c b/net/socket.c index 59020f0b583..ee3ee39eefa 100644 --- a/net/socket.c +++ b/net/socket.c @@ -1988,16 +1988,26 @@ struct used_address { unsigned int name_len; }; -static int copy_msghdr_from_user(struct msghdr *kmsg, - struct user_msghdr __user *umsg) +static ssize_t copy_msghdr_from_user(struct msghdr *kmsg, + struct user_msghdr __user *umsg, + struct sockaddr __user **save_addr, + struct iovec **iov) { - /* We are relying on the (currently) identical layouts. Once - * the kernel-side changes, this place will need to be updated - */ - if (copy_from_user(kmsg, umsg, sizeof(struct msghdr))) + struct sockaddr __user *uaddr; + struct iovec __user *uiov; + ssize_t err; + + if (!access_ok(VERIFY_READ, umsg, sizeof(*umsg)) || + __get_user(uaddr, &umsg->msg_name) || + __get_user(kmsg->msg_namelen, &umsg->msg_namelen) || + __get_user(uiov, &umsg->msg_iov) || + __get_user(kmsg->msg_iovlen, &umsg->msg_iovlen) || + __get_user(kmsg->msg_control, &umsg->msg_control) || + __get_user(kmsg->msg_controllen, &umsg->msg_controllen) || + __get_user(kmsg->msg_flags, &umsg->msg_flags)) return -EFAULT; - if (kmsg->msg_name == NULL) + if (!uaddr) kmsg->msg_namelen = 0; if (kmsg->msg_namelen < 0) @@ -2005,7 +2015,31 @@ static int copy_msghdr_from_user(struct msghdr *kmsg, if (kmsg->msg_namelen > sizeof(struct sockaddr_storage)) kmsg->msg_namelen = sizeof(struct sockaddr_storage); - return 0; + + if (save_addr) + *save_addr = uaddr; + + if (uaddr && kmsg->msg_namelen) { + if (!save_addr) { + err = move_addr_to_kernel(uaddr, kmsg->msg_namelen, + kmsg->msg_name); + if (err < 0) + return err; + } + } else { + kmsg->msg_name = NULL; + kmsg->msg_namelen = 0; + } + + if (kmsg->msg_iovlen > UIO_MAXIOV) + return -EMSGSIZE; + + err = rw_copy_check_uvector(save_addr ? READ : WRITE, + uiov, kmsg->msg_iovlen, + UIO_FASTIOV, *iov, iov); + if (err >= 0) + kmsg->msg_iov = *iov; + return err; } static int ___sys_sendmsg(struct socket *sock, struct user_msghdr __user *msg, @@ -2020,26 +2054,17 @@ static int ___sys_sendmsg(struct socket *sock, struct user_msghdr __user *msg, __attribute__ ((aligned(sizeof(__kernel_size_t)))); /* 20 is size of ipv6_pktinfo */ unsigned char *ctl_buf = ctl; - int err, ctl_len, total_len; + int ctl_len, total_len; + ssize_t err; - err = -EFAULT; - if (MSG_CMSG_COMPAT & flags) { - if (get_compat_msghdr(msg_sys, msg_compat)) - return -EFAULT; - } else { - err = copy_msghdr_from_user(msg_sys, msg); - if (err) - return err; - } + msg_sys->msg_name = &address; - /* This will also move the address data into kernel space */ if (MSG_CMSG_COMPAT & flags) - err = verify_compat_iovec(msg_sys, iovstack, &address, WRITE); + err = get_compat_msghdr(msg_sys, msg_compat, NULL, &iov); else - err = verify_iovec(msg_sys, iovstack, &address, WRITE); + err = copy_msghdr_from_user(msg_sys, msg, NULL, &iov); if (err < 0) goto out_freeiov; - iov = msg_sys->msg_iov; total_len = err; err = -ENOBUFS; @@ -2215,36 +2240,24 @@ static int ___sys_recvmsg(struct socket *sock, struct user_msghdr __user *msg, struct iovec iovstack[UIO_FASTIOV]; struct iovec *iov = iovstack; unsigned long cmsg_ptr; - int err, total_len, len; + int total_len, len; + ssize_t err; /* kernel mode address */ struct sockaddr_storage addr; /* user mode address pointers */ struct sockaddr __user *uaddr; - int __user *uaddr_len; + int __user *uaddr_len = COMPAT_NAMELEN(msg); - if (MSG_CMSG_COMPAT & flags) { - if (get_compat_msghdr(msg_sys, msg_compat)) - return -EFAULT; - } else { - err = copy_msghdr_from_user(msg_sys, msg); - if (err) - return err; - } + msg_sys->msg_name = &addr; - /* Save the user-mode address (verify_iovec will change the - * kernel msghdr to use the kernel address space) - */ - uaddr = (__force void __user *)msg_sys->msg_name; - uaddr_len = COMPAT_NAMELEN(msg); if (MSG_CMSG_COMPAT & flags) - err = verify_compat_iovec(msg_sys, iovstack, &addr, READ); + err = get_compat_msghdr(msg_sys, msg_compat, &uaddr, &iov); else - err = verify_iovec(msg_sys, iovstack, &addr, READ); + err = copy_msghdr_from_user(msg_sys, msg, &uaddr, &iov); if (err < 0) goto out_freeiov; - iov = msg_sys->msg_iov; total_len = err; cmsg_ptr = (unsigned long)msg_sys->msg_control; -- cgit v1.2.3-70-g09d2 From c0371da6047abd261bc483c744dbc7d81a116172 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 24 Nov 2014 10:42:55 -0500 Subject: put iov_iter into msghdr Note that the code _using_ ->msg_iter at that point will be very unhappy with anything other than unshifted iovec-backed iov_iter. We still need to convert users to proper primitives. Signed-off-by: Al Viro --- crypto/algif_hash.c | 4 ++-- crypto/algif_skcipher.c | 4 ++-- drivers/net/macvtap.c | 8 ++------ drivers/net/tun.c | 8 ++------ drivers/vhost/net.c | 8 +++----- fs/afs/rxrpc.c | 14 ++++++-------- include/linux/skbuff.h | 16 ++++++++++------ include/linux/socket.h | 3 +-- include/net/bluetooth/l2cap.h | 2 +- include/net/udplite.h | 3 ++- net/atm/common.c | 5 +---- net/bluetooth/6lowpan.c | 6 +++--- net/bluetooth/a2mp.c | 3 +-- net/bluetooth/smp.c | 3 +-- net/caif/caif_socket.c | 2 +- net/compat.c | 10 ++++++---- net/ipv4/ip_output.c | 6 ++++-- net/ipv4/ping.c | 3 ++- net/ipv4/raw.c | 3 ++- net/ipv4/tcp.c | 6 +++--- net/ipv4/tcp_output.c | 2 +- net/ipv6/ping.c | 3 ++- net/ipv6/raw.c | 3 ++- net/netlink/af_netlink.c | 2 +- net/packet/af_packet.c | 7 ++----- net/rds/recv.c | 7 ++++--- net/rds/send.c | 4 +--- net/rxrpc/ar-output.c | 8 +++----- net/sctp/socket.c | 5 +---- net/socket.c | 27 ++++++++++++--------------- net/tipc/msg.c | 4 ++-- net/unix/af_unix.c | 10 ++-------- net/vmw_vsock/vmci_transport.c | 3 ++- 33 files changed, 90 insertions(+), 112 deletions(-) (limited to 'include/linux/socket.h') diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c index 35c93ff11f3..83cd2cc49c9 100644 --- a/crypto/algif_hash.c +++ b/crypto/algif_hash.c @@ -42,7 +42,7 @@ static int hash_sendmsg(struct kiocb *unused, struct socket *sock, struct alg_sock *ask = alg_sk(sk); struct hash_ctx *ctx = ask->private; unsigned long iovlen; - struct iovec *iov; + const struct iovec *iov; long copied = 0; int err; @@ -58,7 +58,7 @@ static int hash_sendmsg(struct kiocb *unused, struct socket *sock, ctx->more = 0; - for (iov = msg->msg_iov, iovlen = msg->msg_iovlen; iovlen > 0; + for (iov = msg->msg_iter.iov, iovlen = msg->msg_iter.nr_segs; iovlen > 0; iovlen--, iov++) { unsigned long seglen = iov->iov_len; char __user *from = iov->iov_base; diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index c3b482bee20..4f45dab2464 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -429,13 +429,13 @@ static int skcipher_recvmsg(struct kiocb *unused, struct socket *sock, struct skcipher_sg_list *sgl; struct scatterlist *sg; unsigned long iovlen; - struct iovec *iov; + const struct iovec *iov; int err = -EAGAIN; int used; long copied = 0; lock_sock(sk); - for (iov = msg->msg_iov, iovlen = msg->msg_iovlen; iovlen > 0; + for (iov = msg->msg_iter.iov, iovlen = msg->msg_iter.nr_segs; iovlen > 0; iovlen--, iov++) { unsigned long seglen = iov->iov_len; char __user *from = iov->iov_base; diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index ba1e5db2152..2c157cced81 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -1095,9 +1095,7 @@ static int macvtap_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t total_len) { struct macvtap_queue *q = container_of(sock, struct macvtap_queue, sock); - struct iov_iter from; - iov_iter_init(&from, WRITE, m->msg_iov, m->msg_iovlen, total_len); - return macvtap_get_user(q, m, &from, m->msg_flags & MSG_DONTWAIT); + return macvtap_get_user(q, m, &m->msg_iter, m->msg_flags & MSG_DONTWAIT); } static int macvtap_recvmsg(struct kiocb *iocb, struct socket *sock, @@ -1105,12 +1103,10 @@ static int macvtap_recvmsg(struct kiocb *iocb, struct socket *sock, int flags) { struct macvtap_queue *q = container_of(sock, struct macvtap_queue, sock); - struct iov_iter to; int ret; if (flags & ~(MSG_DONTWAIT|MSG_TRUNC)) return -EINVAL; - iov_iter_init(&to, READ, m->msg_iov, m->msg_iovlen, total_len); - ret = macvtap_do_read(q, &to, flags & MSG_DONTWAIT); + ret = macvtap_do_read(q, &m->msg_iter, flags & MSG_DONTWAIT); if (ret > total_len) { m->msg_flags |= MSG_TRUNC; ret = flags & MSG_TRUNC ? ret : total_len; diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 9c58286b8a4..f3e992ed87a 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1449,13 +1449,11 @@ static int tun_sendmsg(struct kiocb *iocb, struct socket *sock, int ret; struct tun_file *tfile = container_of(sock, struct tun_file, socket); struct tun_struct *tun = __tun_get(tfile); - struct iov_iter from; if (!tun) return -EBADFD; - iov_iter_init(&from, WRITE, m->msg_iov, m->msg_iovlen, total_len); - ret = tun_get_user(tun, tfile, m->msg_control, &from, + ret = tun_get_user(tun, tfile, m->msg_control, &m->msg_iter, m->msg_flags & MSG_DONTWAIT); tun_put(tun); return ret; @@ -1467,7 +1465,6 @@ static int tun_recvmsg(struct kiocb *iocb, struct socket *sock, { struct tun_file *tfile = container_of(sock, struct tun_file, socket); struct tun_struct *tun = __tun_get(tfile); - struct iov_iter to; int ret; if (!tun) @@ -1482,8 +1479,7 @@ static int tun_recvmsg(struct kiocb *iocb, struct socket *sock, SOL_PACKET, TUN_TX_TIMESTAMP); goto out; } - iov_iter_init(&to, READ, m->msg_iov, m->msg_iovlen, total_len); - ret = tun_do_read(tun, tfile, &to, flags & MSG_DONTWAIT); + ret = tun_do_read(tun, tfile, &m->msg_iter, flags & MSG_DONTWAIT); if (ret > total_len) { m->msg_flags |= MSG_TRUNC; ret = flags & MSG_TRUNC ? ret : total_len; diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 8dae2f724a3..9f06e70a263 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -342,7 +342,6 @@ static void handle_tx(struct vhost_net *net) .msg_namelen = 0, .msg_control = NULL, .msg_controllen = 0, - .msg_iov = vq->iov, .msg_flags = MSG_DONTWAIT, }; size_t len, total_len = 0; @@ -396,8 +395,8 @@ static void handle_tx(struct vhost_net *net) } /* Skip header. TODO: support TSO. */ s = move_iovec_hdr(vq->iov, nvq->hdr, hdr_size, out); - msg.msg_iovlen = out; len = iov_length(vq->iov, out); + iov_iter_init(&msg.msg_iter, WRITE, vq->iov, out, len); /* Sanity check */ if (!len) { vq_err(vq, "Unexpected header len for TX: " @@ -562,7 +561,6 @@ static void handle_rx(struct vhost_net *net) .msg_namelen = 0, .msg_control = NULL, /* FIXME: get and handle RX aux data. */ .msg_controllen = 0, - .msg_iov = vq->iov, .msg_flags = MSG_DONTWAIT, }; struct virtio_net_hdr_mrg_rxbuf hdr = { @@ -600,7 +598,7 @@ static void handle_rx(struct vhost_net *net) break; /* On overrun, truncate and discard */ if (unlikely(headcount > UIO_MAXIOV)) { - msg.msg_iovlen = 1; + iov_iter_init(&msg.msg_iter, READ, vq->iov, 1, 1); err = sock->ops->recvmsg(NULL, sock, &msg, 1, MSG_DONTWAIT | MSG_TRUNC); pr_debug("Discarded rx packet: len %zd\n", sock_len); @@ -626,7 +624,7 @@ static void handle_rx(struct vhost_net *net) /* Copy the header for use in VIRTIO_NET_F_MRG_RXBUF: * needed because recvmsg can modify msg_iov. */ copy_iovec_hdr(vq->iov, nvq->hdr, sock_hlen, in); - msg.msg_iovlen = in; + iov_iter_init(&msg.msg_iter, READ, vq->iov, in, sock_len); err = sock->ops->recvmsg(NULL, sock, &msg, sock_len, MSG_DONTWAIT | MSG_TRUNC); /* Userspace might have consumed the packet meanwhile: diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index 03a3beb1700..06e14bfb349 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c @@ -306,8 +306,8 @@ static int afs_send_pages(struct afs_call *call, struct msghdr *msg, _debug("- range %u-%u%s", offset, to, msg->msg_flags ? " [more]" : ""); - msg->msg_iov = (struct iovec *) iov; - msg->msg_iovlen = 1; + iov_iter_init(&msg->msg_iter, WRITE, + (struct iovec *) iov, 1, to - offset); /* have to change the state *before* sending the last * packet as RxRPC might give us the reply before it @@ -384,8 +384,8 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, msg.msg_name = NULL; msg.msg_namelen = 0; - msg.msg_iov = (struct iovec *) iov; - msg.msg_iovlen = 1; + iov_iter_init(&msg.msg_iter, WRITE, (struct iovec *)iov, 1, + call->request_size); msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_flags = (call->send_pages ? MSG_MORE : 0); @@ -778,8 +778,7 @@ void afs_send_empty_reply(struct afs_call *call) iov[0].iov_len = 0; msg.msg_name = NULL; msg.msg_namelen = 0; - msg.msg_iov = iov; - msg.msg_iovlen = 0; + iov_iter_init(&msg.msg_iter, WRITE, iov, 0, 0); /* WTF? */ msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_flags = 0; @@ -815,8 +814,7 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len) iov[0].iov_len = len; msg.msg_name = NULL; msg.msg_namelen = 0; - msg.msg_iov = iov; - msg.msg_iovlen = 1; + iov_iter_init(&msg.msg_iter, WRITE, iov, 1, len); msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_flags = 0; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index ef64cec4280..52cf1bdac0d 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -2646,22 +2646,24 @@ unsigned int datagram_poll(struct file *file, struct socket *sock, struct poll_table_struct *wait); int skb_copy_datagram_iovec(const struct sk_buff *from, int offset, struct iovec *to, int size); +int skb_copy_datagram_iter(const struct sk_buff *from, int offset, + struct iov_iter *to, int size); static inline int skb_copy_datagram_msg(const struct sk_buff *from, int offset, struct msghdr *msg, int size) { - return skb_copy_datagram_iovec(from, offset, msg->msg_iov, size); + /* XXX: stripping const */ + return skb_copy_datagram_iovec(from, offset, (struct iovec *)msg->msg_iter.iov, size); } int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb, int hlen, struct iovec *iov); static inline int skb_copy_and_csum_datagram_msg(struct sk_buff *skb, int hlen, struct msghdr *msg) { - return skb_copy_and_csum_datagram_iovec(skb, hlen, msg->msg_iov); + /* XXX: stripping const */ + return skb_copy_and_csum_datagram_iovec(skb, hlen, (struct iovec *)msg->msg_iter.iov); } int skb_copy_datagram_from_iter(struct sk_buff *skb, int offset, struct iov_iter *from, int len); -int skb_copy_datagram_iter(const struct sk_buff *from, int offset, - struct iov_iter *to, int size); int zerocopy_sg_from_iter(struct sk_buff *skb, struct iov_iter *frm); void skb_free_datagram(struct sock *sk, struct sk_buff *skb); void skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb); @@ -2689,12 +2691,14 @@ int skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci); static inline int memcpy_from_msg(void *data, struct msghdr *msg, int len) { - return memcpy_fromiovec(data, msg->msg_iov, len); + /* XXX: stripping const */ + return memcpy_fromiovec(data, (struct iovec *)msg->msg_iter.iov, len); } static inline int memcpy_to_msg(struct msghdr *msg, void *data, int len) { - return memcpy_toiovec(msg->msg_iov, data, len); + /* XXX: stripping const */ + return memcpy_toiovec((struct iovec *)msg->msg_iter.iov, data, len); } struct skb_checksum_ops { diff --git a/include/linux/socket.h b/include/linux/socket.h index de5222832be..048d6d6eed6 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -47,8 +47,7 @@ struct linger { struct msghdr { void *msg_name; /* ptr to socket address structure */ int msg_namelen; /* size of socket address structure */ - struct iovec *msg_iov; /* scatter/gather array */ - __kernel_size_t msg_iovlen; /* # elements in msg_iov */ + struct iov_iter msg_iter; /* data */ void *msg_control; /* ancillary data */ __kernel_size_t msg_controllen; /* ancillary data buffer length */ unsigned int msg_flags; /* flags on received message */ diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 4e23674d364..bca6fc0a319 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -911,7 +911,7 @@ static inline int l2cap_chan_no_memcpy_fromiovec(struct l2cap_chan *chan, /* Following is safe since for compiler definitions of kvec and * iovec are identical, yielding the same in-core layout and alignment */ - struct kvec *vec = (struct kvec *)msg->msg_iov; + struct kvec *vec = (struct kvec *)msg->msg_iter.iov; while (len > 0) { if (vec->iov_len) { diff --git a/include/net/udplite.h b/include/net/udplite.h index d5baaba65b4..ae7c8d1fbca 100644 --- a/include/net/udplite.h +++ b/include/net/udplite.h @@ -20,7 +20,8 @@ static __inline__ int udplite_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb) { struct msghdr *msg = from; - return memcpy_fromiovecend(to, msg->msg_iov, offset, len); + /* XXX: stripping const */ + return memcpy_fromiovecend(to, (struct iovec *)msg->msg_iter.iov, offset, len); } /* Designate sk as UDP-Lite socket */ diff --git a/net/atm/common.c b/net/atm/common.c index f59112944c9..b84057e41bd 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -577,9 +577,6 @@ int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, struct atm_vcc *vcc; struct sk_buff *skb; int eff, error; - struct iov_iter from; - - iov_iter_init(&from, WRITE, m->msg_iov, m->msg_iovlen, size); lock_sock(sk); if (sock->state != SS_CONNECTED) { @@ -634,7 +631,7 @@ int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, goto out; skb->dev = NULL; /* for paths shared with net_device interfaces */ ATM_SKB(skb)->atm_options = vcc->atm_options; - if (copy_from_iter(skb_put(skb, size), size, &from) != size) { + if (copy_from_iter(skb_put(skb, size), size, &m->msg_iter) != size) { kfree_skb(skb); error = -EFAULT; goto out; diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index bdcaefd2db1..d8c67a5e7a0 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -537,12 +537,12 @@ static int send_pkt(struct l2cap_chan *chan, struct sk_buff *skb, */ chan->data = skb; - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = (struct iovec *) &iv; - msg.msg_iovlen = 1; iv.iov_base = skb->data; iv.iov_len = skb->len; + memset(&msg, 0, sizeof(msg)); + iov_iter_init(&msg.msg_iter, WRITE, (struct iovec *) &iv, 1, skb->len); + err = l2cap_chan_send(chan, &msg, skb->len); if (err > 0) { netdev->stats.tx_bytes += err; diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index 5dcade511fd..716d2a38885 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -60,8 +60,7 @@ void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data) memset(&msg, 0, sizeof(msg)); - msg.msg_iov = (struct iovec *) &iv; - msg.msg_iovlen = 1; + iov_iter_init(&msg.msg_iter, WRITE, (struct iovec *)&iv, 1, total_len); l2cap_chan_send(chan, &msg, total_len); diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 069b76e03b5..21f555b4df1 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -268,8 +268,7 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data) memset(&msg, 0, sizeof(msg)); - msg.msg_iov = (struct iovec *) &iv; - msg.msg_iovlen = 2; + iov_iter_init(&msg.msg_iter, WRITE, (struct iovec *)iv, 2, 1 + len); l2cap_chan_send(chan, &msg, 1 + len); diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c index ac618b0b8a4..769b185fefb 100644 --- a/net/caif/caif_socket.c +++ b/net/caif/caif_socket.c @@ -535,7 +535,7 @@ static int caif_seqpkt_sendmsg(struct kiocb *kiocb, struct socket *sock, goto err; ret = -EINVAL; - if (unlikely(msg->msg_iov->iov_base == NULL)) + if (unlikely(msg->msg_iter.iov->iov_base == NULL)) goto err; noblock = msg->msg_flags & MSG_DONTWAIT; diff --git a/net/compat.c b/net/compat.c index 062f157d2a6..3236b4167a3 100644 --- a/net/compat.c +++ b/net/compat.c @@ -37,13 +37,14 @@ ssize_t get_compat_msghdr(struct msghdr *kmsg, struct iovec **iov) { compat_uptr_t uaddr, uiov, tmp3; + compat_size_t nr_segs; ssize_t err; if (!access_ok(VERIFY_READ, umsg, sizeof(*umsg)) || __get_user(uaddr, &umsg->msg_name) || __get_user(kmsg->msg_namelen, &umsg->msg_namelen) || __get_user(uiov, &umsg->msg_iov) || - __get_user(kmsg->msg_iovlen, &umsg->msg_iovlen) || + __get_user(nr_segs, &umsg->msg_iovlen) || __get_user(tmp3, &umsg->msg_control) || __get_user(kmsg->msg_controllen, &umsg->msg_controllen) || __get_user(kmsg->msg_flags, &umsg->msg_flags)) @@ -68,14 +69,15 @@ ssize_t get_compat_msghdr(struct msghdr *kmsg, kmsg->msg_namelen = 0; } - if (kmsg->msg_iovlen > UIO_MAXIOV) + if (nr_segs > UIO_MAXIOV) return -EMSGSIZE; err = compat_rw_copy_check_uvector(save_addr ? READ : WRITE, - compat_ptr(uiov), kmsg->msg_iovlen, + compat_ptr(uiov), nr_segs, UIO_FASTIOV, *iov, iov); if (err >= 0) - kmsg->msg_iov = *iov; + iov_iter_init(&kmsg->msg_iter, save_addr ? READ : WRITE, + *iov, nr_segs, err); return err; } diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index cdedcf14446..b50861b22b6 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -755,11 +755,13 @@ ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk struct msghdr *msg = from; if (skb->ip_summed == CHECKSUM_PARTIAL) { - if (memcpy_fromiovecend(to, msg->msg_iov, offset, len) < 0) + /* XXX: stripping const */ + if (memcpy_fromiovecend(to, (struct iovec *)msg->msg_iter.iov, offset, len) < 0) return -EFAULT; } else { __wsum csum = 0; - if (csum_partial_copy_fromiovecend(to, msg->msg_iov, offset, len, &csum) < 0) + /* XXX: stripping const */ + if (csum_partial_copy_fromiovecend(to, (struct iovec *)msg->msg_iter.iov, offset, len, &csum) < 0) return -EFAULT; skb->csum = csum_block_add(skb->csum, csum, odd); } diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 8dd4ae0424f..c0d82f78d36 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -811,7 +811,8 @@ back_from_confirm: pfh.icmph.checksum = 0; pfh.icmph.un.echo.id = inet->inet_sport; pfh.icmph.un.echo.sequence = user_icmph.un.echo.sequence; - pfh.iov = msg->msg_iov; + /* XXX: stripping const */ + pfh.iov = (struct iovec *)msg->msg_iter.iov; pfh.wcheck = 0; pfh.family = AF_INET; diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 5d83bd2fced..0bb68df5055 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -625,7 +625,8 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, back_from_confirm: if (inet->hdrincl) - err = raw_send_hdrinc(sk, &fl4, msg->msg_iov, len, + /* XXX: stripping const */ + err = raw_send_hdrinc(sk, &fl4, (struct iovec *)msg->msg_iter.iov, len, &rt, msg->msg_flags); else { diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 4a96f373017..54ba6209eea 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1085,7 +1085,7 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t size) { - struct iovec *iov; + const struct iovec *iov; struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *skb; int iovlen, flags, err, copied = 0; @@ -1136,8 +1136,8 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, mss_now = tcp_send_mss(sk, &size_goal, flags); /* Ok commence sending. */ - iovlen = msg->msg_iovlen; - iov = msg->msg_iov; + iovlen = msg->msg_iter.nr_segs; + iov = msg->msg_iter.iov; copied = 0; err = -EPIPE; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index f5bd4bd3f7e..3e225b03eb9 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -3050,7 +3050,7 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) syn_data->ip_summed = CHECKSUM_PARTIAL; memcpy(syn_data->cb, syn->cb, sizeof(syn->cb)); if (unlikely(memcpy_fromiovecend(skb_put(syn_data, space), - fo->data->msg_iov, 0, space))) { + fo->data->msg_iter.iov, 0, space))) { kfree_skb(syn_data); goto fallback; } diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c index 5b7a1ed2aba..2d3148378a1 100644 --- a/net/ipv6/ping.c +++ b/net/ipv6/ping.c @@ -163,7 +163,8 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, pfh.icmph.checksum = 0; pfh.icmph.un.echo.id = inet->inet_sport; pfh.icmph.un.echo.sequence = user_icmph.icmp6_sequence; - pfh.iov = msg->msg_iov; + /* XXX: stripping const */ + pfh.iov = (struct iovec *)msg->msg_iter.iov; pfh.wcheck = 0; pfh.family = AF_INET6; diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 11a9283fda5..ee25631f8c2 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -886,7 +886,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, back_from_confirm: if (inet->hdrincl) - err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl6, &dst, msg->msg_flags); + /* XXX: stripping const */ + err = rawv6_send_hdrinc(sk, (struct iovec *)msg->msg_iter.iov, len, &fl6, &dst, msg->msg_flags); else { lock_sock(sk); err = ip6_append_data(sk, raw6_getfrag, &rfv, diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 63aa5c8acf1..cc9bcf008b0 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -2305,7 +2305,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, } if (netlink_tx_is_mmaped(sk) && - msg->msg_iov->iov_base == NULL) { + msg->msg_iter.iov->iov_base == NULL) { err = netlink_mmap_sendmsg(sk, msg, dst_portid, dst_group, siocb); goto out; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index efa84450113..ed2e620b61d 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2408,11 +2408,8 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) unsigned short gso_type = 0; int hlen, tlen; int extra_len = 0; - struct iov_iter from; ssize_t n; - iov_iter_init(&from, WRITE, msg->msg_iov, msg->msg_iovlen, len); - /* * Get and verify the address. */ @@ -2451,7 +2448,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) len -= vnet_hdr_len; err = -EFAULT; - n = copy_from_iter(&vnet_hdr, vnet_hdr_len, &from); + n = copy_from_iter(&vnet_hdr, vnet_hdr_len, &msg->msg_iter); if (n != vnet_hdr_len) goto out_unlock; @@ -2522,7 +2519,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) } /* Returns -EFAULT on error */ - err = skb_copy_datagram_from_iter(skb, offset, &from, len); + err = skb_copy_datagram_from_iter(skb, offset, &msg->msg_iter, len); if (err) goto out_free; diff --git a/net/rds/recv.c b/net/rds/recv.c index 47d7b1029b3..f9ec1acd801 100644 --- a/net/rds/recv.c +++ b/net/rds/recv.c @@ -404,7 +404,6 @@ int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, int ret = 0, nonblock = msg_flags & MSG_DONTWAIT; DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name); struct rds_incoming *inc = NULL; - struct iov_iter to; /* udp_recvmsg()->sock_recvtimeo() gets away without locking too.. */ timeo = sock_rcvtimeo(sk, nonblock); @@ -415,6 +414,7 @@ int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, goto out; while (1) { + struct iov_iter save; /* If there are pending notifications, do those - and nothing else */ if (!list_empty(&rs->rs_notify_queue)) { ret = rds_notify_queue_get(rs, msg); @@ -450,8 +450,8 @@ int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, rdsdebug("copying inc %p from %pI4:%u to user\n", inc, &inc->i_conn->c_faddr, ntohs(inc->i_hdr.h_sport)); - iov_iter_init(&to, READ, msg->msg_iov, msg->msg_iovlen, size); - ret = inc->i_conn->c_trans->inc_copy_to_user(inc, &to); + save = msg->msg_iter; + ret = inc->i_conn->c_trans->inc_copy_to_user(inc, &msg->msg_iter); if (ret < 0) break; @@ -464,6 +464,7 @@ int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, rds_inc_put(inc); inc = NULL; rds_stats_inc(s_recv_deliver_raced); + msg->msg_iter = save; continue; } diff --git a/net/rds/send.c b/net/rds/send.c index 4de62ead1c7..40a5629a0a1 100644 --- a/net/rds/send.c +++ b/net/rds/send.c @@ -934,9 +934,7 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, int queued = 0, allocated_mr = 0; int nonblock = msg->msg_flags & MSG_DONTWAIT; long timeo = sock_sndtimeo(sk, nonblock); - struct iov_iter from; - iov_iter_init(&from, WRITE, msg->msg_iov, msg->msg_iovlen, payload_len); /* Mirror Linux UDP mirror of BSD error message compatibility */ /* XXX: Perhaps MSG_MORE someday */ if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_CMSG_COMPAT)) { @@ -984,7 +982,7 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, ret = -ENOMEM; goto out; } - ret = rds_message_copy_from_user(rm, &from); + ret = rds_message_copy_from_user(rm, &msg->msg_iter); if (ret) goto out; } diff --git a/net/rxrpc/ar-output.c b/net/rxrpc/ar-output.c index 0b4b9a79f5a..86e0f10aa2c 100644 --- a/net/rxrpc/ar-output.c +++ b/net/rxrpc/ar-output.c @@ -531,14 +531,12 @@ static int rxrpc_send_data(struct kiocb *iocb, struct rxrpc_skb_priv *sp; unsigned char __user *from; struct sk_buff *skb; - struct iovec *iov; + const struct iovec *iov; struct sock *sk = &rx->sk; long timeo; bool more; int ret, ioc, segment, copied; - _enter(",,,{%zu},%zu", msg->msg_iovlen, len); - timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); /* this should be in poll */ @@ -547,8 +545,8 @@ static int rxrpc_send_data(struct kiocb *iocb, if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN)) return -EPIPE; - iov = msg->msg_iov; - ioc = msg->msg_iovlen - 1; + iov = msg->msg_iter.iov; + ioc = msg->msg_iter.nr_segs - 1; from = iov->iov_base; segment = iov->iov_len; iov++; diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 0397ac9fd98..c92f96cda69 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1609,9 +1609,6 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, __u16 sinfo_flags = 0; long timeo; int err; - struct iov_iter from; - - iov_iter_init(&from, WRITE, msg->msg_iov, msg->msg_iovlen, msg_len); err = 0; sp = sctp_sk(sk); @@ -1950,7 +1947,7 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, } /* Break the message into multiple chunks of maximum size. */ - datamsg = sctp_datamsg_from_user(asoc, sinfo, &from); + datamsg = sctp_datamsg_from_user(asoc, sinfo, &msg->msg_iter); if (IS_ERR(datamsg)) { err = PTR_ERR(datamsg); goto out_free; diff --git a/net/socket.c b/net/socket.c index f676ac4a370..8809afccf7f 100644 --- a/net/socket.c +++ b/net/socket.c @@ -689,8 +689,7 @@ int kernel_sendmsg(struct socket *sock, struct msghdr *msg, * the following is safe, since for compiler definitions of kvec and * iovec are identical, yielding the same in-core layout and alignment */ - msg->msg_iov = (struct iovec *)vec; - msg->msg_iovlen = num; + iov_iter_init(&msg->msg_iter, WRITE, (struct iovec *)vec, num, size); result = sock_sendmsg(sock, msg, size); set_fs(oldfs); return result; @@ -853,7 +852,7 @@ int kernel_recvmsg(struct socket *sock, struct msghdr *msg, * the following is safe, since for compiler definitions of kvec and * iovec are identical, yielding the same in-core layout and alignment */ - msg->msg_iov = (struct iovec *)vec, msg->msg_iovlen = num; + iov_iter_init(&msg->msg_iter, READ, (struct iovec *)vec, num, size); result = sock_recvmsg(sock, msg, size, flags); set_fs(oldfs); return result; @@ -913,8 +912,7 @@ static ssize_t do_sock_read(struct msghdr *msg, struct kiocb *iocb, msg->msg_namelen = 0; msg->msg_control = NULL; msg->msg_controllen = 0; - msg->msg_iov = (struct iovec *)iov; - msg->msg_iovlen = nr_segs; + iov_iter_init(&msg->msg_iter, READ, iov, nr_segs, size); msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; return __sock_recvmsg(iocb, sock, msg, size, msg->msg_flags); @@ -953,8 +951,7 @@ static ssize_t do_sock_write(struct msghdr *msg, struct kiocb *iocb, msg->msg_namelen = 0; msg->msg_control = NULL; msg->msg_controllen = 0; - msg->msg_iov = (struct iovec *)iov; - msg->msg_iovlen = nr_segs; + iov_iter_init(&msg->msg_iter, WRITE, iov, nr_segs, size); msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; if (sock->type == SOCK_SEQPACKET) msg->msg_flags |= MSG_EOR; @@ -1798,8 +1795,7 @@ SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len, iov.iov_base = buff; iov.iov_len = len; msg.msg_name = NULL; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; + iov_iter_init(&msg.msg_iter, WRITE, &iov, 1, len); msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_namelen = 0; @@ -1856,10 +1852,9 @@ SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size, msg.msg_control = NULL; msg.msg_controllen = 0; - msg.msg_iovlen = 1; - msg.msg_iov = &iov; iov.iov_len = size; iov.iov_base = ubuf; + iov_iter_init(&msg.msg_iter, READ, &iov, 1, size); /* Save some cycles and don't copy the address if not needed */ msg.msg_name = addr ? (struct sockaddr *)&address : NULL; /* We assume all kernel code knows the size of sockaddr_storage */ @@ -1993,13 +1988,14 @@ static ssize_t copy_msghdr_from_user(struct msghdr *kmsg, { struct sockaddr __user *uaddr; struct iovec __user *uiov; + size_t nr_segs; ssize_t err; if (!access_ok(VERIFY_READ, umsg, sizeof(*umsg)) || __get_user(uaddr, &umsg->msg_name) || __get_user(kmsg->msg_namelen, &umsg->msg_namelen) || __get_user(uiov, &umsg->msg_iov) || - __get_user(kmsg->msg_iovlen, &umsg->msg_iovlen) || + __get_user(nr_segs, &umsg->msg_iovlen) || __get_user(kmsg->msg_control, &umsg->msg_control) || __get_user(kmsg->msg_controllen, &umsg->msg_controllen) || __get_user(kmsg->msg_flags, &umsg->msg_flags)) @@ -2029,14 +2025,15 @@ static ssize_t copy_msghdr_from_user(struct msghdr *kmsg, kmsg->msg_namelen = 0; } - if (kmsg->msg_iovlen > UIO_MAXIOV) + if (nr_segs > UIO_MAXIOV) return -EMSGSIZE; err = rw_copy_check_uvector(save_addr ? READ : WRITE, - uiov, kmsg->msg_iovlen, + uiov, nr_segs, UIO_FASTIOV, *iov, iov); if (err >= 0) - kmsg->msg_iov = *iov; + iov_iter_init(&kmsg->msg_iter, save_addr ? READ : WRITE, + *iov, nr_segs, err); return err; } diff --git a/net/tipc/msg.c b/net/tipc/msg.c index 5b0659791c0..a687b30a699 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -194,7 +194,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m, int offset, __skb_queue_tail(list, skb); skb_copy_to_linear_data(skb, mhdr, mhsz); pktpos = skb->data + mhsz; - if (!dsz || !memcpy_fromiovecend(pktpos, m->msg_iov, offset, + if (!dsz || !memcpy_fromiovecend(pktpos, m->msg_iter.iov, offset, dsz)) return dsz; rc = -EFAULT; @@ -224,7 +224,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m, int offset, if (drem < pktrem) pktrem = drem; - if (memcpy_fromiovecend(pktpos, m->msg_iov, offset, pktrem)) { + if (memcpy_fromiovecend(pktpos, m->msg_iter.iov, offset, pktrem)) { rc = -EFAULT; goto error; } diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 4450d622660..8e1b10274b0 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1459,9 +1459,6 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, struct scm_cookie tmp_scm; int max_level; int data_len = 0; - struct iov_iter from; - - iov_iter_init(&from, WRITE, msg->msg_iov, msg->msg_iovlen, len); if (NULL == siocb->scm) siocb->scm = &tmp_scm; @@ -1519,7 +1516,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, skb_put(skb, len - data_len); skb->data_len = data_len; skb->len = len; - err = skb_copy_datagram_from_iter(skb, 0, &from, len); + err = skb_copy_datagram_from_iter(skb, 0, &msg->msg_iter, len); if (err) goto out_free; @@ -1641,9 +1638,6 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, bool fds_sent = false; int max_level; int data_len; - struct iov_iter from; - - iov_iter_init(&from, WRITE, msg->msg_iov, msg->msg_iovlen, len); if (NULL == siocb->scm) siocb->scm = &tmp_scm; @@ -1700,7 +1694,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, skb_put(skb, size - data_len); skb->data_len = data_len; skb->len = size; - err = skb_copy_datagram_from_iter(skb, 0, &from, size); + err = skb_copy_datagram_from_iter(skb, 0, &msg->msg_iter, size); if (err) { kfree_skb(skb); goto out_err; diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c index 20a0ba3bfff..02d2e522924 100644 --- a/net/vmw_vsock/vmci_transport.c +++ b/net/vmw_vsock/vmci_transport.c @@ -1850,7 +1850,8 @@ static ssize_t vmci_transport_stream_enqueue( struct msghdr *msg, size_t len) { - return vmci_qpair_enquev(vmci_trans(vsk)->qpair, msg->msg_iov, len, 0); + /* XXX: stripping const */ + return vmci_qpair_enquev(vmci_trans(vsk)->qpair, (struct iovec *)msg->msg_iter.iov, len, 0); } static s64 vmci_transport_stream_has_data(struct vsock_sock *vsk) -- cgit v1.2.3-70-g09d2 From f95b414edb18de59940dcebbefb49cf25c6d505c Mon Sep 17 00:00:00 2001 From: Gu Zheng Date: Thu, 11 Dec 2014 11:22:04 +0800 Subject: net: introduce helper macro for_each_cmsghdr Introduce helper macro for_each_cmsghdr as a wrapper of the enumerating cmsghdr from msghdr, just cleanup. Signed-off-by: Gu Zheng Signed-off-by: David S. Miller --- crypto/af_alg.c | 2 +- include/linux/socket.h | 4 ++++ net/core/scm.c | 3 +-- net/dccp/proto.c | 5 ++--- net/ipv4/ip_sockglue.c | 2 +- net/ipv6/datagram.c | 2 +- net/iucv/af_iucv.c | 4 +--- net/rds/send.c | 4 ++-- net/rxrpc/ar-output.c | 2 +- net/sctp/socket.c | 3 +-- 10 files changed, 15 insertions(+), 16 deletions(-) (limited to 'include/linux/socket.h') diff --git a/crypto/af_alg.c b/crypto/af_alg.c index 6a3ad801158..bc21f520d48 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -399,7 +399,7 @@ int af_alg_cmsg_send(struct msghdr *msg, struct af_alg_control *con) { struct cmsghdr *cmsg; - for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { + for_each_cmsghdr(cmsg, msg) { if (!CMSG_OK(msg, cmsg)) return -EINVAL; if (cmsg->cmsg_level != SOL_ALG) diff --git a/include/linux/socket.h b/include/linux/socket.h index 048d6d6eed6..6e49a14365d 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -103,6 +103,10 @@ struct cmsghdr { (cmsg)->cmsg_len <= (unsigned long) \ ((mhdr)->msg_controllen - \ ((char *)(cmsg) - (char *)(mhdr)->msg_control))) +#define for_each_cmsghdr(cmsg, msg) \ + for (cmsg = CMSG_FIRSTHDR(msg); \ + cmsg; \ + cmsg = CMSG_NXTHDR(msg, cmsg)) /* * Get the next cmsg header diff --git a/net/core/scm.c b/net/core/scm.c index b442e7e25e6..3b6899b7d81 100644 --- a/net/core/scm.c +++ b/net/core/scm.c @@ -129,8 +129,7 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p) struct cmsghdr *cmsg; int err; - for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) - { + for_each_cmsghdr(cmsg, msg) { err = -EINVAL; /* Verify that cmsg_len is at least sizeof(struct cmsghdr) */ diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 19f03873908..e171b780b49 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -703,7 +703,7 @@ EXPORT_SYMBOL_GPL(compat_dccp_getsockopt); static int dccp_msghdr_parse(struct msghdr *msg, struct sk_buff *skb) { - struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg); + struct cmsghdr *cmsg; /* * Assign an (opaque) qpolicy priority value to skb->priority. @@ -717,8 +717,7 @@ static int dccp_msghdr_parse(struct msghdr *msg, struct sk_buff *skb) */ skb->priority = 0; - for (; cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) { - + for_each_cmsghdr(cmsg, msg) { if (!CMSG_OK(msg, cmsg)) return -EINVAL; diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 640f26c6a9f..8a89c738b7a 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -192,7 +192,7 @@ int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc, int err, val; struct cmsghdr *cmsg; - for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { + for_each_cmsghdr(cmsg, msg) { if (!CMSG_OK(msg, cmsg)) return -EINVAL; #if IS_ENABLED(CONFIG_IPV6) diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 2464a00e36a..100c589a2a6 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -657,7 +657,7 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk, int len; int err = 0; - for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { + for_each_cmsghdr(cmsg, msg) { int addr_type; if (!CMSG_OK(msg, cmsg)) { diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 1cd3f810723..2e9953b2db8 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -1070,9 +1070,7 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, txmsg.class = 0; /* iterate over control messages */ - for (cmsg = CMSG_FIRSTHDR(msg); cmsg; - cmsg = CMSG_NXTHDR(msg, cmsg)) { - + for_each_cmsghdr(cmsg, msg) { if (!CMSG_OK(msg, cmsg)) { err = -EINVAL; goto out; diff --git a/net/rds/send.c b/net/rds/send.c index 40a5629a0a1..42f65d4305c 100644 --- a/net/rds/send.c +++ b/net/rds/send.c @@ -826,7 +826,7 @@ static int rds_rm_size(struct msghdr *msg, int data_len) int cmsg_groups = 0; int retval; - for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { + for_each_cmsghdr(cmsg, msg) { if (!CMSG_OK(msg, cmsg)) return -EINVAL; @@ -878,7 +878,7 @@ static int rds_cmsg_send(struct rds_sock *rs, struct rds_message *rm, struct cmsghdr *cmsg; int ret = 0; - for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { + for_each_cmsghdr(cmsg, msg) { if (!CMSG_OK(msg, cmsg)) return -EINVAL; diff --git a/net/rxrpc/ar-output.c b/net/rxrpc/ar-output.c index 86e0f10aa2c..e1a9373e597 100644 --- a/net/rxrpc/ar-output.c +++ b/net/rxrpc/ar-output.c @@ -45,7 +45,7 @@ static int rxrpc_sendmsg_cmsg(struct rxrpc_sock *rx, struct msghdr *msg, if (msg->msg_controllen == 0) return -EINVAL; - for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { + for_each_cmsghdr(cmsg, msg) { if (!CMSG_OK(msg, cmsg)) return -EINVAL; diff --git a/net/sctp/socket.c b/net/sctp/socket.c index c92f96cda69..2625eccb77d 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -6592,8 +6592,7 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) struct cmsghdr *cmsg; struct msghdr *my_msg = (struct msghdr *)msg; - for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; - cmsg = CMSG_NXTHDR(my_msg, cmsg)) { + for_each_cmsghdr(cmsg, my_msg) { if (!CMSG_OK(my_msg, cmsg)) return -EINVAL; -- cgit v1.2.3-70-g09d2