aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2014-11-09 22:33:45 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2014-11-19 16:23:16 -0500
commit0844932009e1656726c6e9c369e694017b129378 (patch)
tree4de5bd394278e3cdf5f53c9cbc9513d1dc6fb469
parent666547ff591cebdedc4679bf6b1b3f3383a8dea3 (diff)
{compat_,}verify_iovec(): switch to generic copying of iovecs
use {compat_,}rw_copy_check_uvector(). As the result, we are guaranteed that all iovecs seen in ->msg_iov by ->sendmsg() and ->recvmsg() will pass access_ok(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--net/compat.c51
-rw-r--r--net/core/iovec.c37
-rw-r--r--net/socket.c38
3 files changed, 37 insertions, 89 deletions
diff --git a/net/compat.c b/net/compat.c
index 562e920b07f0..7b4b6ad13235 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -31,33 +31,6 @@
31#include <asm/uaccess.h> 31#include <asm/uaccess.h>
32#include <net/compat.h> 32#include <net/compat.h>
33 33
34static inline int iov_from_user_compat_to_kern(struct iovec *kiov,
35 struct compat_iovec __user *uiov32,
36 int niov)
37{
38 int tot_len = 0;
39
40 while (niov > 0) {
41 compat_uptr_t buf;
42 compat_size_t len;
43
44 if (get_user(len, &uiov32->iov_len) ||
45 get_user(buf, &uiov32->iov_base))
46 return -EFAULT;
47
48 if (len > INT_MAX - tot_len)
49 len = INT_MAX - tot_len;
50
51 tot_len += len;
52 kiov->iov_base = compat_ptr(buf);
53 kiov->iov_len = (__kernel_size_t) len;
54 uiov32++;
55 kiov++;
56 niov--;
57 }
58 return tot_len;
59}
60
61int get_compat_msghdr(struct msghdr *kmsg, struct compat_msghdr __user *umsg) 34int get_compat_msghdr(struct msghdr *kmsg, struct compat_msghdr __user *umsg)
62{ 35{
63 compat_uptr_t tmp1, tmp2, tmp3; 36 compat_uptr_t tmp1, tmp2, tmp3;
@@ -80,13 +53,15 @@ int get_compat_msghdr(struct msghdr *kmsg, struct compat_msghdr __user *umsg)
80} 53}
81 54
82/* I've named the args so it is easy to tell whose space the pointers are in. */ 55/* I've named the args so it is easy to tell whose space the pointers are in. */
83int verify_compat_iovec(struct msghdr *kern_msg, struct iovec *kern_iov, 56int verify_compat_iovec(struct msghdr *kern_msg, struct iovec *iov,
84 struct sockaddr_storage *kern_address, int mode) 57 struct sockaddr_storage *kern_address, int mode)
85{ 58{
86 int tot_len; 59 struct compat_iovec __user *p;
60 struct iovec *res;
61 int err;
87 62
88 if (kern_msg->msg_name && kern_msg->msg_namelen) { 63 if (kern_msg->msg_name && kern_msg->msg_namelen) {
89 if (mode == VERIFY_READ) { 64 if (mode == WRITE) {
90 int err = move_addr_to_kernel(kern_msg->msg_name, 65 int err = move_addr_to_kernel(kern_msg->msg_name,
91 kern_msg->msg_namelen, 66 kern_msg->msg_namelen,
92 kern_address); 67 kern_address);
@@ -99,13 +74,17 @@ int verify_compat_iovec(struct msghdr *kern_msg, struct iovec *kern_iov,
99 kern_msg->msg_namelen = 0; 74 kern_msg->msg_namelen = 0;
100 } 75 }
101 76
102 tot_len = iov_from_user_compat_to_kern(kern_iov, 77 if (kern_msg->msg_iovlen > UIO_MAXIOV)
103 (struct compat_iovec __user *)kern_msg->msg_iov, 78 return -EMSGSIZE;
104 kern_msg->msg_iovlen);
105 if (tot_len >= 0)
106 kern_msg->msg_iov = kern_iov;
107 79
108 return tot_len; 80 p = (struct compat_iovec __user *)kern_msg->msg_iov;
81 err = compat_rw_copy_check_uvector(mode, p, kern_msg->msg_iovlen,
82 UIO_FASTIOV, iov, &res);
83 if (err >= 0)
84 kern_msg->msg_iov = res;
85 else if (res != iov)
86 kfree(res);
87 return err;
109} 88}
110 89
111/* Bleech... */ 90/* Bleech... */
diff --git a/net/core/iovec.c b/net/core/iovec.c
index e1ec45ab1e63..86beeea61d72 100644
--- a/net/core/iovec.c
+++ b/net/core/iovec.c
@@ -37,13 +37,13 @@
37 37
38int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *address, int mode) 38int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *address, int mode)
39{ 39{
40 int size, ct, err; 40 struct iovec *res;
41 int err;
41 42
42 if (m->msg_name && m->msg_namelen) { 43 if (m->msg_name && m->msg_namelen) {
43 if (mode == VERIFY_READ) { 44 if (mode == WRITE) {
44 void __user *namep; 45 void __user *namep = (void __user __force *)m->msg_name;
45 namep = (void __user __force *) m->msg_name; 46 int err = move_addr_to_kernel(namep, m->msg_namelen,
46 err = move_addr_to_kernel(namep, m->msg_namelen,
47 address); 47 address);
48 if (err < 0) 48 if (err < 0)
49 return err; 49 return err;
@@ -53,24 +53,15 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *a
53 m->msg_name = NULL; 53 m->msg_name = NULL;
54 m->msg_namelen = 0; 54 m->msg_namelen = 0;
55 } 55 }
56 56 if (m->msg_iovlen > UIO_MAXIOV)
57 size = m->msg_iovlen * sizeof(struct iovec); 57 return -EMSGSIZE;
58 if (copy_from_user(iov, (void __user __force *) m->msg_iov, size)) 58
59 return -EFAULT; 59 err = rw_copy_check_uvector(mode, (void __user __force *)m->msg_iov,
60 60 m->msg_iovlen, UIO_FASTIOV, iov, &res);
61 m->msg_iov = iov; 61 if (err >= 0)
62 err = 0; 62 m->msg_iov = res;
63 63 else if (res != iov)
64 for (ct = 0; ct < m->msg_iovlen; ct++) { 64 kfree(res);
65 size_t len = iov[ct].iov_len;
66
67 if (len > INT_MAX - err) {
68 len = INT_MAX - err;
69 iov[ct].iov_len = len;
70 }
71 err += len;
72 }
73
74 return err; 65 return err;
75} 66}
76 67
diff --git a/net/socket.c b/net/socket.c
index 0ae8147e3acc..59020f0b583b 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -2032,24 +2032,14 @@ static int ___sys_sendmsg(struct socket *sock, struct user_msghdr __user *msg,
2032 return err; 2032 return err;
2033 } 2033 }
2034 2034
2035 if (msg_sys->msg_iovlen > UIO_FASTIOV) {
2036 err = -EMSGSIZE;
2037 if (msg_sys->msg_iovlen > UIO_MAXIOV)
2038 goto out;
2039 err = -ENOMEM;
2040 iov = kmalloc(msg_sys->msg_iovlen * sizeof(struct iovec),
2041 GFP_KERNEL);
2042 if (!iov)
2043 goto out;
2044 }
2045
2046 /* This will also move the address data into kernel space */ 2035 /* This will also move the address data into kernel space */
2047 if (MSG_CMSG_COMPAT & flags) { 2036 if (MSG_CMSG_COMPAT & flags)
2048 err = verify_compat_iovec(msg_sys, iov, &address, VERIFY_READ); 2037 err = verify_compat_iovec(msg_sys, iovstack, &address, WRITE);
2049 } else 2038 else
2050 err = verify_iovec(msg_sys, iov, &address, VERIFY_READ); 2039 err = verify_iovec(msg_sys, iovstack, &address, WRITE);
2051 if (err < 0) 2040 if (err < 0)
2052 goto out_freeiov; 2041 goto out_freeiov;
2042 iov = msg_sys->msg_iov;
2053 total_len = err; 2043 total_len = err;
2054 2044
2055 err = -ENOBUFS; 2045 err = -ENOBUFS;
@@ -2118,7 +2108,6 @@ out_freectl:
2118out_freeiov: 2108out_freeiov:
2119 if (iov != iovstack) 2109 if (iov != iovstack)
2120 kfree(iov); 2110 kfree(iov);
2121out:
2122 return err; 2111 return err;
2123} 2112}
2124 2113
@@ -2244,28 +2233,18 @@ static int ___sys_recvmsg(struct socket *sock, struct user_msghdr __user *msg,
2244 return err; 2233 return err;
2245 } 2234 }
2246 2235
2247 if (msg_sys->msg_iovlen > UIO_FASTIOV) {
2248 err = -EMSGSIZE;
2249 if (msg_sys->msg_iovlen > UIO_MAXIOV)
2250 goto out;
2251 err = -ENOMEM;
2252 iov = kmalloc(msg_sys->msg_iovlen * sizeof(struct iovec),
2253 GFP_KERNEL);
2254 if (!iov)
2255 goto out;
2256 }
2257
2258 /* Save the user-mode address (verify_iovec will change the 2236 /* Save the user-mode address (verify_iovec will change the
2259 * kernel msghdr to use the kernel address space) 2237 * kernel msghdr to use the kernel address space)
2260 */ 2238 */
2261 uaddr = (__force void __user *)msg_sys->msg_name; 2239 uaddr = (__force void __user *)msg_sys->msg_name;
2262 uaddr_len = COMPAT_NAMELEN(msg); 2240 uaddr_len = COMPAT_NAMELEN(msg);
2263 if (MSG_CMSG_COMPAT & flags) 2241 if (MSG_CMSG_COMPAT & flags)
2264 err = verify_compat_iovec(msg_sys, iov, &addr, VERIFY_WRITE); 2242 err = verify_compat_iovec(msg_sys, iovstack, &addr, READ);
2265 else 2243 else
2266 err = verify_iovec(msg_sys, iov, &addr, VERIFY_WRITE); 2244 err = verify_iovec(msg_sys, iovstack, &addr, READ);
2267 if (err < 0) 2245 if (err < 0)
2268 goto out_freeiov; 2246 goto out_freeiov;
2247 iov = msg_sys->msg_iov;
2269 total_len = err; 2248 total_len = err;
2270 2249
2271 cmsg_ptr = (unsigned long)msg_sys->msg_control; 2250 cmsg_ptr = (unsigned long)msg_sys->msg_control;
@@ -2306,7 +2285,6 @@ static int ___sys_recvmsg(struct socket *sock, struct user_msghdr __user *msg,
2306out_freeiov: 2285out_freeiov:
2307 if (iov != iovstack) 2286 if (iov != iovstack)
2308 kfree(iov); 2287 kfree(iov);
2309out:
2310 return err; 2288 return err;
2311} 2289}
2312 2290