]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
move compat_rw_copy_check_uvector() over to fs/read_write.c
authorAl Viro <viro@zeniv.linux.org.uk>
Sat, 8 Apr 2017 22:18:48 +0000 (18:18 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Mon, 17 Apr 2017 16:52:26 +0000 (12:52 -0400)
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/compat.c
fs/read_write.c

index 3e94559c452e5a0a99a64b135940696fad2eae17..ca2f3ca5dacd0a5a2b80586b8826637cdb5984f0 100644 (file)
 #include <asm/ioctls.h>
 #include "internal.h"
 
-/* A write operation does a read from user space and vice versa */
-#define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ)
-
-ssize_t compat_rw_copy_check_uvector(int type,
-               const struct compat_iovec __user *uvector, unsigned long nr_segs,
-               unsigned long fast_segs, struct iovec *fast_pointer,
-               struct iovec **ret_pointer)
-{
-       compat_ssize_t tot_len;
-       struct iovec *iov = *ret_pointer = fast_pointer;
-       ssize_t ret = 0;
-       int seg;
-
-       /*
-        * SuS says "The readv() function *may* fail if the iovcnt argument
-        * was less than or equal to 0, or greater than {IOV_MAX}.  Linux has
-        * traditionally returned zero for zero segments, so...
-        */
-       if (nr_segs == 0)
-               goto out;
-
-       ret = -EINVAL;
-       if (nr_segs > UIO_MAXIOV)
-               goto out;
-       if (nr_segs > fast_segs) {
-               ret = -ENOMEM;
-               iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
-               if (iov == NULL)
-                       goto out;
-       }
-       *ret_pointer = iov;
-
-       ret = -EFAULT;
-       if (!access_ok(VERIFY_READ, uvector, nr_segs*sizeof(*uvector)))
-               goto out;
-
-       /*
-        * Single unix specification:
-        * We should -EINVAL if an element length is not >= 0 and fitting an
-        * ssize_t.
-        *
-        * In Linux, the total length is limited to MAX_RW_COUNT, there is
-        * no overflow possibility.
-        */
-       tot_len = 0;
-       ret = -EINVAL;
-       for (seg = 0; seg < nr_segs; seg++) {
-               compat_uptr_t buf;
-               compat_ssize_t len;
-
-               if (__get_user(len, &uvector->iov_len) ||
-                  __get_user(buf, &uvector->iov_base)) {
-                       ret = -EFAULT;
-                       goto out;
-               }
-               if (len < 0)    /* size_t not fitting in compat_ssize_t .. */
-                       goto out;
-               if (type >= 0 &&
-                   !access_ok(vrfy_dir(type), compat_ptr(buf), len)) {
-                       ret = -EFAULT;
-                       goto out;
-               }
-               if (len > MAX_RW_COUNT - tot_len)
-                       len = MAX_RW_COUNT - tot_len;
-               tot_len += len;
-               iov->iov_base = compat_ptr(buf);
-               iov->iov_len = (compat_size_t) len;
-               uvector++;
-               iov++;
-       }
-       ret = tot_len;
-
-out:
-       return ret;
-}
-
 struct compat_ncp_mount_data {
        compat_int_t version;
        compat_uint_t ncp_fd;
index c4f88afbc67f49ae9e451e06a81c45c37f8171f5..47c1d4484df9e6b69333215efc10d7a5db64210f 100644 (file)
@@ -841,6 +841,81 @@ out:
        return ret;
 }
 
+#ifdef CONFIG_COMPAT
+ssize_t compat_rw_copy_check_uvector(int type,
+               const struct compat_iovec __user *uvector, unsigned long nr_segs,
+               unsigned long fast_segs, struct iovec *fast_pointer,
+               struct iovec **ret_pointer)
+{
+       compat_ssize_t tot_len;
+       struct iovec *iov = *ret_pointer = fast_pointer;
+       ssize_t ret = 0;
+       int seg;
+
+       /*
+        * SuS says "The readv() function *may* fail if the iovcnt argument
+        * was less than or equal to 0, or greater than {IOV_MAX}.  Linux has
+        * traditionally returned zero for zero segments, so...
+        */
+       if (nr_segs == 0)
+               goto out;
+
+       ret = -EINVAL;
+       if (nr_segs > UIO_MAXIOV)
+               goto out;
+       if (nr_segs > fast_segs) {
+               ret = -ENOMEM;
+               iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
+               if (iov == NULL)
+                       goto out;
+       }
+       *ret_pointer = iov;
+
+       ret = -EFAULT;
+       if (!access_ok(VERIFY_READ, uvector, nr_segs*sizeof(*uvector)))
+               goto out;
+
+       /*
+        * Single unix specification:
+        * We should -EINVAL if an element length is not >= 0 and fitting an
+        * ssize_t.
+        *
+        * In Linux, the total length is limited to MAX_RW_COUNT, there is
+        * no overflow possibility.
+        */
+       tot_len = 0;
+       ret = -EINVAL;
+       for (seg = 0; seg < nr_segs; seg++) {
+               compat_uptr_t buf;
+               compat_ssize_t len;
+
+               if (__get_user(len, &uvector->iov_len) ||
+                  __get_user(buf, &uvector->iov_base)) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+               if (len < 0)    /* size_t not fitting in compat_ssize_t .. */
+                       goto out;
+               if (type >= 0 &&
+                   !access_ok(vrfy_dir(type), compat_ptr(buf), len)) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+               if (len > MAX_RW_COUNT - tot_len)
+                       len = MAX_RW_COUNT - tot_len;
+               tot_len += len;
+               iov->iov_base = compat_ptr(buf);
+               iov->iov_len = (compat_size_t) len;
+               uvector++;
+               iov++;
+       }
+       ret = tot_len;
+
+out:
+       return ret;
+}
+#endif
+
 static ssize_t __do_readv_writev(int type, struct file *file,
                                 struct iov_iter *iter, loff_t *pos, int flags)
 {