summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2017-04-08 18:18:48 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2017-04-17 12:52:26 -0400
commitf50298556436ef0f32257b8ea19b112f9028b0a5 (patch)
tree32c3e7022475150ad1cbfb87f9d29c23f446ee05 /fs
parent2b8910264a7fec4599b620e5206eb877a207f40a (diff)
move compat_rw_copy_check_uvector() over to fs/read_write.c
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/compat.c76
-rw-r--r--fs/read_write.c75
2 files changed, 75 insertions, 76 deletions
diff --git a/fs/compat.c b/fs/compat.c
index 3e94559c452e..ca2f3ca5dacd 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -54,82 +54,6 @@
54#include <asm/ioctls.h> 54#include <asm/ioctls.h>
55#include "internal.h" 55#include "internal.h"
56 56
57/* A write operation does a read from user space and vice versa */
58#define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ)
59
60ssize_t compat_rw_copy_check_uvector(int type,
61 const struct compat_iovec __user *uvector, unsigned long nr_segs,
62 unsigned long fast_segs, struct iovec *fast_pointer,
63 struct iovec **ret_pointer)
64{
65 compat_ssize_t tot_len;
66 struct iovec *iov = *ret_pointer = fast_pointer;
67 ssize_t ret = 0;
68 int seg;
69
70 /*
71 * SuS says "The readv() function *may* fail if the iovcnt argument
72 * was less than or equal to 0, or greater than {IOV_MAX}. Linux has
73 * traditionally returned zero for zero segments, so...
74 */
75 if (nr_segs == 0)
76 goto out;
77
78 ret = -EINVAL;
79 if (nr_segs > UIO_MAXIOV)
80 goto out;
81 if (nr_segs > fast_segs) {
82 ret = -ENOMEM;
83 iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
84 if (iov == NULL)
85 goto out;
86 }
87 *ret_pointer = iov;
88
89 ret = -EFAULT;
90 if (!access_ok(VERIFY_READ, uvector, nr_segs*sizeof(*uvector)))
91 goto out;
92
93 /*
94 * Single unix specification:
95 * We should -EINVAL if an element length is not >= 0 and fitting an
96 * ssize_t.
97 *
98 * In Linux, the total length is limited to MAX_RW_COUNT, there is
99 * no overflow possibility.
100 */
101 tot_len = 0;
102 ret = -EINVAL;
103 for (seg = 0; seg < nr_segs; seg++) {
104 compat_uptr_t buf;
105 compat_ssize_t len;
106
107 if (__get_user(len, &uvector->iov_len) ||
108 __get_user(buf, &uvector->iov_base)) {
109 ret = -EFAULT;
110 goto out;
111 }
112 if (len < 0) /* size_t not fitting in compat_ssize_t .. */
113 goto out;
114 if (type >= 0 &&
115 !access_ok(vrfy_dir(type), compat_ptr(buf), len)) {
116 ret = -EFAULT;
117 goto out;
118 }
119 if (len > MAX_RW_COUNT - tot_len)
120 len = MAX_RW_COUNT - tot_len;
121 tot_len += len;
122 iov->iov_base = compat_ptr(buf);
123 iov->iov_len = (compat_size_t) len;
124 uvector++;
125 iov++;
126 }
127 ret = tot_len;
128
129out:
130 return ret;
131}
132
133struct compat_ncp_mount_data { 57struct compat_ncp_mount_data {
134 compat_int_t version; 58 compat_int_t version;
135 compat_uint_t ncp_fd; 59 compat_uint_t ncp_fd;
diff --git a/fs/read_write.c b/fs/read_write.c
index c4f88afbc67f..47c1d4484df9 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -841,6 +841,81 @@ out:
841 return ret; 841 return ret;
842} 842}
843 843
844#ifdef CONFIG_COMPAT
845ssize_t compat_rw_copy_check_uvector(int type,
846 const struct compat_iovec __user *uvector, unsigned long nr_segs,
847 unsigned long fast_segs, struct iovec *fast_pointer,
848 struct iovec **ret_pointer)
849{
850 compat_ssize_t tot_len;
851 struct iovec *iov = *ret_pointer = fast_pointer;
852 ssize_t ret = 0;
853 int seg;
854
855 /*
856 * SuS says "The readv() function *may* fail if the iovcnt argument
857 * was less than or equal to 0, or greater than {IOV_MAX}. Linux has
858 * traditionally returned zero for zero segments, so...
859 */
860 if (nr_segs == 0)
861 goto out;
862
863 ret = -EINVAL;
864 if (nr_segs > UIO_MAXIOV)
865 goto out;
866 if (nr_segs > fast_segs) {
867 ret = -ENOMEM;
868 iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
869 if (iov == NULL)
870 goto out;
871 }
872 *ret_pointer = iov;
873
874 ret = -EFAULT;
875 if (!access_ok(VERIFY_READ, uvector, nr_segs*sizeof(*uvector)))
876 goto out;
877
878 /*
879 * Single unix specification:
880 * We should -EINVAL if an element length is not >= 0 and fitting an
881 * ssize_t.
882 *
883 * In Linux, the total length is limited to MAX_RW_COUNT, there is
884 * no overflow possibility.
885 */
886 tot_len = 0;
887 ret = -EINVAL;
888 for (seg = 0; seg < nr_segs; seg++) {
889 compat_uptr_t buf;
890 compat_ssize_t len;
891
892 if (__get_user(len, &uvector->iov_len) ||
893 __get_user(buf, &uvector->iov_base)) {
894 ret = -EFAULT;
895 goto out;
896 }
897 if (len < 0) /* size_t not fitting in compat_ssize_t .. */
898 goto out;
899 if (type >= 0 &&
900 !access_ok(vrfy_dir(type), compat_ptr(buf), len)) {
901 ret = -EFAULT;
902 goto out;
903 }
904 if (len > MAX_RW_COUNT - tot_len)
905 len = MAX_RW_COUNT - tot_len;
906 tot_len += len;
907 iov->iov_base = compat_ptr(buf);
908 iov->iov_len = (compat_size_t) len;
909 uvector++;
910 iov++;
911 }
912 ret = tot_len;
913
914out:
915 return ret;
916}
917#endif
918
844static ssize_t __do_readv_writev(int type, struct file *file, 919static ssize_t __do_readv_writev(int type, struct file *file,
845 struct iov_iter *iter, loff_t *pos, int flags) 920 struct iov_iter *iter, loff_t *pos, int flags)
846{ 921{