Commit 8acfe468b0384e834a303f08ebc4953d72fb690a

Authored by David S. Miller
1 parent 349f6c5c5d

net: Limit socket I/O iovec total length to INT_MAX.

This helps protect us from overflow issues down in the
individual protocol sendmsg/recvmsg handlers.  Once
we hit INT_MAX we truncate out the rest of the iovec
by setting the iov_len members to zero.

This works because:

1) For SOCK_STREAM and SOCK_SEQPACKET sockets, partial
   writes are allowed and the application will just continue
   with another write to send the rest of the data.

2) For datagram oriented sockets, where there must be a
   one-to-one correspondance between write() calls and
   packets on the wire, INT_MAX is going to be far larger
   than the packet size limit the protocol is going to
   check for and signal with -EMSGSIZE.

Based upon a patch by Linus Torvalds.

Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 3 changed files with 16 additions and 16 deletions Side-by-side Diff

include/linux/socket.h
... ... @@ -322,7 +322,7 @@
322 322 int offset,
323 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 326 extern int memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len);
327 327 extern int memcpy_toiovecend(const struct iovec *v, unsigned char *kdata,
328 328 int offset, int len);
... ... @@ -41,10 +41,12 @@
41 41 compat_size_t len;
42 42  
43 43 if (get_user(len, &uiov32->iov_len) ||
44   - get_user(buf, &uiov32->iov_base)) {
45   - tot_len = -EFAULT;
46   - break;
47   - }
  44 + get_user(buf, &uiov32->iov_base))
  45 + return -EFAULT;
  46 +
  47 + if (len > INT_MAX - tot_len)
  48 + len = INT_MAX - tot_len;
  49 +
48 50 tot_len += len;
49 51 kiov->iov_base = compat_ptr(buf);
50 52 kiov->iov_len = (__kernel_size_t) len;
... ... @@ -35,10 +35,9 @@
35 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;
41   - long err;
  40 + int size, ct, err;
42 41  
43 42 if (m->msg_namelen) {
44 43 if (mode == VERIFY_READ) {
... ... @@ -62,14 +61,13 @@
62 61 err = 0;
63 62  
64 63 for (ct = 0; ct < m->msg_iovlen; ct++) {
65   - err += iov[ct].iov_len;
66   - /*
67   - * Goal is not to verify user data, but to prevent returning
68   - * negative value, which is interpreted as errno.
69   - * Overflow is still possible, but it is harmless.
70   - */
71   - if (err < 0)
72   - return -EMSGSIZE;
  64 + size_t len = iov[ct].iov_len;
  65 +
  66 + if (len > INT_MAX - err) {
  67 + len = INT_MAX - err;
  68 + iov[ct].iov_len = len;
  69 + }
  70 + err += len;
73 71 }
74 72  
75 73 return err;