diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2014-11-10 20:23:13 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2014-11-19 16:23:49 -0500 |
commit | 08adb7dabd4874cc5666b4490653b26534702ce0 (patch) | |
tree | 8848933c57ef03c59e52ace937103c91c4e32607 /net/socket.c | |
parent | 0844932009e1656726c6e9c369e694017b129378 (diff) |
fold verify_iovec() into copy_msghdr_from_user()
... and do the same on the compat side of things.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'net/socket.c')
-rw-r--r-- | net/socket.c | 93 |
1 files changed, 53 insertions, 40 deletions
diff --git a/net/socket.c b/net/socket.c index 59020f0b583b..ee3ee39eefa5 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -1988,16 +1988,26 @@ struct used_address { | |||
1988 | unsigned int name_len; | 1988 | unsigned int name_len; |
1989 | }; | 1989 | }; |
1990 | 1990 | ||
1991 | static int copy_msghdr_from_user(struct msghdr *kmsg, | 1991 | static ssize_t copy_msghdr_from_user(struct msghdr *kmsg, |
1992 | struct user_msghdr __user *umsg) | 1992 | struct user_msghdr __user *umsg, |
1993 | struct sockaddr __user **save_addr, | ||
1994 | struct iovec **iov) | ||
1993 | { | 1995 | { |
1994 | /* We are relying on the (currently) identical layouts. Once | 1996 | struct sockaddr __user *uaddr; |
1995 | * the kernel-side changes, this place will need to be updated | 1997 | struct iovec __user *uiov; |
1996 | */ | 1998 | ssize_t err; |
1997 | if (copy_from_user(kmsg, umsg, sizeof(struct msghdr))) | 1999 | |
2000 | if (!access_ok(VERIFY_READ, umsg, sizeof(*umsg)) || | ||
2001 | __get_user(uaddr, &umsg->msg_name) || | ||
2002 | __get_user(kmsg->msg_namelen, &umsg->msg_namelen) || | ||
2003 | __get_user(uiov, &umsg->msg_iov) || | ||
2004 | __get_user(kmsg->msg_iovlen, &umsg->msg_iovlen) || | ||
2005 | __get_user(kmsg->msg_control, &umsg->msg_control) || | ||
2006 | __get_user(kmsg->msg_controllen, &umsg->msg_controllen) || | ||
2007 | __get_user(kmsg->msg_flags, &umsg->msg_flags)) | ||
1998 | return -EFAULT; | 2008 | return -EFAULT; |
1999 | 2009 | ||
2000 | if (kmsg->msg_name == NULL) | 2010 | if (!uaddr) |
2001 | kmsg->msg_namelen = 0; | 2011 | kmsg->msg_namelen = 0; |
2002 | 2012 | ||
2003 | if (kmsg->msg_namelen < 0) | 2013 | if (kmsg->msg_namelen < 0) |
@@ -2005,7 +2015,31 @@ static int copy_msghdr_from_user(struct msghdr *kmsg, | |||
2005 | 2015 | ||
2006 | if (kmsg->msg_namelen > sizeof(struct sockaddr_storage)) | 2016 | if (kmsg->msg_namelen > sizeof(struct sockaddr_storage)) |
2007 | kmsg->msg_namelen = sizeof(struct sockaddr_storage); | 2017 | kmsg->msg_namelen = sizeof(struct sockaddr_storage); |
2008 | return 0; | 2018 | |
2019 | if (save_addr) | ||
2020 | *save_addr = uaddr; | ||
2021 | |||
2022 | if (uaddr && kmsg->msg_namelen) { | ||
2023 | if (!save_addr) { | ||
2024 | err = move_addr_to_kernel(uaddr, kmsg->msg_namelen, | ||
2025 | kmsg->msg_name); | ||
2026 | if (err < 0) | ||
2027 | return err; | ||
2028 | } | ||
2029 | } else { | ||
2030 | kmsg->msg_name = NULL; | ||
2031 | kmsg->msg_namelen = 0; | ||
2032 | } | ||
2033 | |||
2034 | if (kmsg->msg_iovlen > UIO_MAXIOV) | ||
2035 | return -EMSGSIZE; | ||
2036 | |||
2037 | err = rw_copy_check_uvector(save_addr ? READ : WRITE, | ||
2038 | uiov, kmsg->msg_iovlen, | ||
2039 | UIO_FASTIOV, *iov, iov); | ||
2040 | if (err >= 0) | ||
2041 | kmsg->msg_iov = *iov; | ||
2042 | return err; | ||
2009 | } | 2043 | } |
2010 | 2044 | ||
2011 | static int ___sys_sendmsg(struct socket *sock, struct user_msghdr __user *msg, | 2045 | 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, | |||
2020 | __attribute__ ((aligned(sizeof(__kernel_size_t)))); | 2054 | __attribute__ ((aligned(sizeof(__kernel_size_t)))); |
2021 | /* 20 is size of ipv6_pktinfo */ | 2055 | /* 20 is size of ipv6_pktinfo */ |
2022 | unsigned char *ctl_buf = ctl; | 2056 | unsigned char *ctl_buf = ctl; |
2023 | int err, ctl_len, total_len; | 2057 | int ctl_len, total_len; |
2058 | ssize_t err; | ||
2024 | 2059 | ||
2025 | err = -EFAULT; | 2060 | msg_sys->msg_name = &address; |
2026 | if (MSG_CMSG_COMPAT & flags) { | ||
2027 | if (get_compat_msghdr(msg_sys, msg_compat)) | ||
2028 | return -EFAULT; | ||
2029 | } else { | ||
2030 | err = copy_msghdr_from_user(msg_sys, msg); | ||
2031 | if (err) | ||
2032 | return err; | ||
2033 | } | ||
2034 | 2061 | ||
2035 | /* This will also move the address data into kernel space */ | ||
2036 | if (MSG_CMSG_COMPAT & flags) | 2062 | if (MSG_CMSG_COMPAT & flags) |
2037 | err = verify_compat_iovec(msg_sys, iovstack, &address, WRITE); | 2063 | err = get_compat_msghdr(msg_sys, msg_compat, NULL, &iov); |
2038 | else | 2064 | else |
2039 | err = verify_iovec(msg_sys, iovstack, &address, WRITE); | 2065 | err = copy_msghdr_from_user(msg_sys, msg, NULL, &iov); |
2040 | if (err < 0) | 2066 | if (err < 0) |
2041 | goto out_freeiov; | 2067 | goto out_freeiov; |
2042 | iov = msg_sys->msg_iov; | ||
2043 | total_len = err; | 2068 | total_len = err; |
2044 | 2069 | ||
2045 | err = -ENOBUFS; | 2070 | err = -ENOBUFS; |
@@ -2215,36 +2240,24 @@ static int ___sys_recvmsg(struct socket *sock, struct user_msghdr __user *msg, | |||
2215 | struct iovec iovstack[UIO_FASTIOV]; | 2240 | struct iovec iovstack[UIO_FASTIOV]; |
2216 | struct iovec *iov = iovstack; | 2241 | struct iovec *iov = iovstack; |
2217 | unsigned long cmsg_ptr; | 2242 | unsigned long cmsg_ptr; |
2218 | int err, total_len, len; | 2243 | int total_len, len; |
2244 | ssize_t err; | ||
2219 | 2245 | ||
2220 | /* kernel mode address */ | 2246 | /* kernel mode address */ |
2221 | struct sockaddr_storage addr; | 2247 | struct sockaddr_storage addr; |
2222 | 2248 | ||
2223 | /* user mode address pointers */ | 2249 | /* user mode address pointers */ |
2224 | struct sockaddr __user *uaddr; | 2250 | struct sockaddr __user *uaddr; |
2225 | int __user *uaddr_len; | 2251 | int __user *uaddr_len = COMPAT_NAMELEN(msg); |
2226 | 2252 | ||
2227 | if (MSG_CMSG_COMPAT & flags) { | 2253 | msg_sys->msg_name = &addr; |
2228 | if (get_compat_msghdr(msg_sys, msg_compat)) | ||
2229 | return -EFAULT; | ||
2230 | } else { | ||
2231 | err = copy_msghdr_from_user(msg_sys, msg); | ||
2232 | if (err) | ||
2233 | return err; | ||
2234 | } | ||
2235 | 2254 | ||
2236 | /* Save the user-mode address (verify_iovec will change the | ||
2237 | * kernel msghdr to use the kernel address space) | ||
2238 | */ | ||
2239 | uaddr = (__force void __user *)msg_sys->msg_name; | ||
2240 | uaddr_len = COMPAT_NAMELEN(msg); | ||
2241 | if (MSG_CMSG_COMPAT & flags) | 2255 | if (MSG_CMSG_COMPAT & flags) |
2242 | err = verify_compat_iovec(msg_sys, iovstack, &addr, READ); | 2256 | err = get_compat_msghdr(msg_sys, msg_compat, &uaddr, &iov); |
2243 | else | 2257 | else |
2244 | err = verify_iovec(msg_sys, iovstack, &addr, READ); | 2258 | err = copy_msghdr_from_user(msg_sys, msg, &uaddr, &iov); |
2245 | if (err < 0) | 2259 | if (err < 0) |
2246 | goto out_freeiov; | 2260 | goto out_freeiov; |
2247 | iov = msg_sys->msg_iov; | ||
2248 | total_len = err; | 2261 | total_len = err; |
2249 | 2262 | ||
2250 | cmsg_ptr = (unsigned long)msg_sys->msg_control; | 2263 | cmsg_ptr = (unsigned long)msg_sys->msg_control; |