diff options
-rw-r--r-- | include/linux/socket.h | 2 | ||||
-rw-r--r-- | net/compat.c | 10 | ||||
-rw-r--r-- | net/core/iovec.c | 20 |
3 files changed, 16 insertions, 16 deletions
diff --git a/include/linux/socket.h b/include/linux/socket.h index 5146b50202ce..86b652fabf6e 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h | |||
@@ -322,7 +322,7 @@ extern int csum_partial_copy_fromiovecend(unsigned char *kdata, | |||
322 | int offset, | 322 | int offset, |
323 | unsigned int len, __wsum *csump); | 323 | unsigned int len, __wsum *csump); |
324 | 324 | ||
325 | extern long verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address, int mode); | 325 | extern int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address, int mode); |
326 | extern int memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len); | 326 | extern int memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len); |
327 | extern int memcpy_toiovecend(const struct iovec *v, unsigned char *kdata, | 327 | extern int memcpy_toiovecend(const struct iovec *v, unsigned char *kdata, |
328 | int offset, int len); | 328 | int offset, int len); |
diff --git a/net/compat.c b/net/compat.c index 63d260e81472..3649d5895361 100644 --- a/net/compat.c +++ b/net/compat.c | |||
@@ -41,10 +41,12 @@ static inline int iov_from_user_compat_to_kern(struct iovec *kiov, | |||
41 | compat_size_t len; | 41 | compat_size_t len; |
42 | 42 | ||
43 | if (get_user(len, &uiov32->iov_len) || | 43 | if (get_user(len, &uiov32->iov_len) || |
44 | get_user(buf, &uiov32->iov_base)) { | 44 | get_user(buf, &uiov32->iov_base)) |
45 | tot_len = -EFAULT; | 45 | return -EFAULT; |
46 | break; | 46 | |
47 | } | 47 | if (len > INT_MAX - tot_len) |
48 | len = INT_MAX - tot_len; | ||
49 | |||
48 | tot_len += len; | 50 | tot_len += len; |
49 | kiov->iov_base = compat_ptr(buf); | 51 | kiov->iov_base = compat_ptr(buf); |
50 | kiov->iov_len = (__kernel_size_t) len; | 52 | kiov->iov_len = (__kernel_size_t) len; |
diff --git a/net/core/iovec.c b/net/core/iovec.c index 72aceb1fe4fa..c40f27e7d208 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c | |||
@@ -35,10 +35,9 @@ | |||
35 | * in any case. | 35 | * in any case. |
36 | */ | 36 | */ |
37 | 37 | ||
38 | long verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address, int mode) | 38 | int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address, int mode) |
39 | { | 39 | { |
40 | int size, ct; | 40 | int size, ct, err; |
41 | long err; | ||
42 | 41 | ||
43 | if (m->msg_namelen) { | 42 | if (m->msg_namelen) { |
44 | if (mode == VERIFY_READ) { | 43 | if (mode == VERIFY_READ) { |
@@ -62,14 +61,13 @@ long verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address, | |||
62 | err = 0; | 61 | err = 0; |
63 | 62 | ||
64 | for (ct = 0; ct < m->msg_iovlen; ct++) { | 63 | for (ct = 0; ct < m->msg_iovlen; ct++) { |
65 | err += iov[ct].iov_len; | 64 | size_t len = iov[ct].iov_len; |
66 | /* | 65 | |
67 | * Goal is not to verify user data, but to prevent returning | 66 | if (len > INT_MAX - err) { |
68 | * negative value, which is interpreted as errno. | 67 | len = INT_MAX - err; |
69 | * Overflow is still possible, but it is harmless. | 68 | iov[ct].iov_len = len; |
70 | */ | 69 | } |
71 | if (err < 0) | 70 | err += len; |
72 | return -EMSGSIZE; | ||
73 | } | 71 | } |
74 | 72 | ||
75 | return err; | 73 | return err; |