iovec: make sure the caller actually wants anything in memcpy_fromiovecend
[pandora-kernel.git] / net / core / iovec.c
index 72aceb1..66e3f1f 100644 (file)
  *     in any case.
  */
 
-long verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address, int mode)
+int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address, int mode)
 {
-       int size, ct;
-       long err;
+       int size, ct, err;
 
-       if (m->msg_namelen) {
+       if (m->msg_name && m->msg_namelen) {
                if (mode == VERIFY_READ) {
                        void __user *namep;
                        namep = (void __user __force *) m->msg_name;
@@ -52,6 +51,7 @@ long verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address,
                m->msg_name = address;
        } else {
                m->msg_name = NULL;
+               m->msg_namelen = 0;
        }
 
        size = m->msg_iovlen * sizeof(struct iovec);
@@ -62,14 +62,13 @@ long verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address,
        err = 0;
 
        for (ct = 0; ct < m->msg_iovlen; ct++) {
-               err += iov[ct].iov_len;
-               /*
-                * Goal is not to verify user data, but to prevent returning
-                * negative value, which is interpreted as errno.
-                * Overflow is still possible, but it is harmless.
-                */
-               if (err < 0)
-                       return -EMSGSIZE;
+               size_t len = iov[ct].iov_len;
+
+               if (len > INT_MAX - err) {
+                       len = INT_MAX - err;
+                       iov[ct].iov_len = len;
+               }
+               err += len;
        }
 
        return err;
@@ -158,6 +157,10 @@ EXPORT_SYMBOL(memcpy_fromiovec);
 int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov,
                        int offset, int len)
 {
+       /* No data? Done! */
+       if (len == 0)
+               return 0;
+
        /* Skip over the finished iovecs */
        while (offset >= iov->iov_len) {
                offset -= iov->iov_len;