diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-02 14:54:26 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-02 14:54:26 -0400 |
commit | 204f144c9fcac355843412b6ba1150086488a208 (patch) | |
tree | 7c06bcb63f2caf961855d2cea968d9fd94b325d7 | |
parent | da7b66ffb2815800440d9e1649282a27c805304f (diff) | |
parent | 801b25f104647d44dc5b5cce2c72e2283b3757de (diff) |
Merge branch 'work.compat' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull fs/compat.c cleanups from Al Viro:
"More moving of compat syscalls from fs/compat.c to fs/*.c where the
native counterparts live.
And death to compat_sys_getdents64() - the only architecture that used
to need it was ia64, and _that_ has lost biarch support quite a few
years ago"
* 'work.compat' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
fs/compat.c: trim unused includes
move compat_rw_copy_check_uvector() over to fs/read_write.c
fhandle: move compat syscalls from compat.c
open: move compat syscalls from compat.c
stat: move compat syscalls from compat.c
fcntl: move compat syscalls from compat.c
readdir: move compat syscalls from compat.c
statfs: move compat syscalls from compat.c
utimes: move compat syscalls from compat.c
move compat select-related syscalls to fs/select.c
Remove compat_sys_getdents64()
-rw-r--r-- | arch/arm64/include/asm/unistd.h | 1 | ||||
-rw-r--r-- | arch/arm64/include/asm/unistd32.h | 2 | ||||
-rw-r--r-- | arch/x86/entry/syscalls/syscall_32.tbl | 2 | ||||
-rw-r--r-- | arch/x86/include/asm/unistd.h | 1 | ||||
-rw-r--r-- | fs/compat.c | 1191 | ||||
-rw-r--r-- | fs/fcntl.c | 157 | ||||
-rw-r--r-- | fs/fhandle.c | 13 | ||||
-rw-r--r-- | fs/internal.h | 2 | ||||
-rw-r--r-- | fs/open.c | 20 | ||||
-rw-r--r-- | fs/read_write.c | 75 | ||||
-rw-r--r-- | fs/readdir.c | 165 | ||||
-rw-r--r-- | fs/select.c | 421 | ||||
-rw-r--r-- | fs/stat.c | 86 | ||||
-rw-r--r-- | fs/statfs.c | 140 | ||||
-rw-r--r-- | fs/utimes.c | 66 | ||||
-rw-r--r-- | include/linux/compat.h | 5 | ||||
-rw-r--r-- | include/linux/poll.h | 56 | ||||
-rw-r--r-- | include/uapi/asm-generic/unistd.h | 3 |
18 files changed, 1139 insertions, 1267 deletions
diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h index bdbeb06dc11e..a0baa9af5487 100644 --- a/arch/arm64/include/asm/unistd.h +++ b/arch/arm64/include/asm/unistd.h | |||
@@ -14,7 +14,6 @@ | |||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
15 | */ | 15 | */ |
16 | #ifdef CONFIG_COMPAT | 16 | #ifdef CONFIG_COMPAT |
17 | #define __ARCH_WANT_COMPAT_SYS_GETDENTS64 | ||
18 | #define __ARCH_WANT_COMPAT_STAT64 | 17 | #define __ARCH_WANT_COMPAT_STAT64 |
19 | #define __ARCH_WANT_SYS_GETHOSTNAME | 18 | #define __ARCH_WANT_SYS_GETHOSTNAME |
20 | #define __ARCH_WANT_SYS_PAUSE | 19 | #define __ARCH_WANT_SYS_PAUSE |
diff --git a/arch/arm64/include/asm/unistd32.h b/arch/arm64/include/asm/unistd32.h index c66b51aab195..ef292160748c 100644 --- a/arch/arm64/include/asm/unistd32.h +++ b/arch/arm64/include/asm/unistd32.h | |||
@@ -456,7 +456,7 @@ __SYSCALL(__NR_setfsuid32, sys_setfsuid) | |||
456 | #define __NR_setfsgid32 216 | 456 | #define __NR_setfsgid32 216 |
457 | __SYSCALL(__NR_setfsgid32, sys_setfsgid) | 457 | __SYSCALL(__NR_setfsgid32, sys_setfsgid) |
458 | #define __NR_getdents64 217 | 458 | #define __NR_getdents64 217 |
459 | __SYSCALL(__NR_getdents64, compat_sys_getdents64) | 459 | __SYSCALL(__NR_getdents64, sys_getdents64) |
460 | #define __NR_pivot_root 218 | 460 | #define __NR_pivot_root 218 |
461 | __SYSCALL(__NR_pivot_root, sys_pivot_root) | 461 | __SYSCALL(__NR_pivot_root, sys_pivot_root) |
462 | #define __NR_mincore 219 | 462 | #define __NR_mincore 219 |
diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl index 0af59fa789ea..448ac2161112 100644 --- a/arch/x86/entry/syscalls/syscall_32.tbl +++ b/arch/x86/entry/syscalls/syscall_32.tbl | |||
@@ -226,7 +226,7 @@ | |||
226 | 217 i386 pivot_root sys_pivot_root | 226 | 217 i386 pivot_root sys_pivot_root |
227 | 218 i386 mincore sys_mincore | 227 | 218 i386 mincore sys_mincore |
228 | 219 i386 madvise sys_madvise | 228 | 219 i386 madvise sys_madvise |
229 | 220 i386 getdents64 sys_getdents64 compat_sys_getdents64 | 229 | 220 i386 getdents64 sys_getdents64 |
230 | 221 i386 fcntl64 sys_fcntl64 compat_sys_fcntl64 | 230 | 221 i386 fcntl64 sys_fcntl64 compat_sys_fcntl64 |
231 | # 222 is unused | 231 | # 222 is unused |
232 | # 223 is unused | 232 | # 223 is unused |
diff --git a/arch/x86/include/asm/unistd.h b/arch/x86/include/asm/unistd.h index 32712a925f26..1ba1536f627e 100644 --- a/arch/x86/include/asm/unistd.h +++ b/arch/x86/include/asm/unistd.h | |||
@@ -23,7 +23,6 @@ | |||
23 | # include <asm/unistd_64.h> | 23 | # include <asm/unistd_64.h> |
24 | # include <asm/unistd_64_x32.h> | 24 | # include <asm/unistd_64_x32.h> |
25 | # define __ARCH_WANT_COMPAT_SYS_TIME | 25 | # define __ARCH_WANT_COMPAT_SYS_TIME |
26 | # define __ARCH_WANT_COMPAT_SYS_GETDENTS64 | ||
27 | # define __ARCH_WANT_COMPAT_SYS_PREADV64 | 26 | # define __ARCH_WANT_COMPAT_SYS_PREADV64 |
28 | # define __ARCH_WANT_COMPAT_SYS_PWRITEV64 | 27 | # define __ARCH_WANT_COMPAT_SYS_PWRITEV64 |
29 | # define __ARCH_WANT_COMPAT_SYS_PREADV64V2 | 28 | # define __ARCH_WANT_COMPAT_SYS_PREADV64V2 |
diff --git a/fs/compat.c b/fs/compat.c index c61b506f5bc9..190b38b39d9e 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
@@ -15,555 +15,14 @@ | |||
15 | * published by the Free Software Foundation. | 15 | * published by the Free Software Foundation. |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/stddef.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/linkage.h> | ||
21 | #include <linux/compat.h> | 18 | #include <linux/compat.h> |
22 | #include <linux/errno.h> | ||
23 | #include <linux/time.h> | ||
24 | #include <linux/cred.h> | ||
25 | #include <linux/fs.h> | ||
26 | #include <linux/fcntl.h> | ||
27 | #include <linux/namei.h> | ||
28 | #include <linux/file.h> | ||
29 | #include <linux/fdtable.h> | ||
30 | #include <linux/vfs.h> | ||
31 | #include <linux/ioctl.h> | ||
32 | #include <linux/init.h> | ||
33 | #include <linux/ncp_mount.h> | 19 | #include <linux/ncp_mount.h> |
34 | #include <linux/nfs4_mount.h> | 20 | #include <linux/nfs4_mount.h> |
35 | #include <linux/syscalls.h> | 21 | #include <linux/syscalls.h> |
36 | #include <linux/ctype.h> | ||
37 | #include <linux/dirent.h> | ||
38 | #include <linux/fsnotify.h> | ||
39 | #include <linux/highuid.h> | ||
40 | #include <linux/personality.h> | ||
41 | #include <linux/rwsem.h> | ||
42 | #include <linux/tsacct_kern.h> | ||
43 | #include <linux/security.h> | ||
44 | #include <linux/highmem.h> | ||
45 | #include <linux/signal.h> | ||
46 | #include <linux/poll.h> | ||
47 | #include <linux/mm.h> | ||
48 | #include <linux/fs_struct.h> | ||
49 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
50 | #include <linux/pagemap.h> | ||
51 | #include <linux/aio.h> | ||
52 | |||
53 | #include <linux/uaccess.h> | 23 | #include <linux/uaccess.h> |
54 | #include <asm/mmu_context.h> | ||
55 | #include <asm/ioctls.h> | ||
56 | #include "internal.h" | 24 | #include "internal.h" |
57 | 25 | ||
58 | /* | ||
59 | * Not all architectures have sys_utime, so implement this in terms | ||
60 | * of sys_utimes. | ||
61 | */ | ||
62 | COMPAT_SYSCALL_DEFINE2(utime, const char __user *, filename, | ||
63 | struct compat_utimbuf __user *, t) | ||
64 | { | ||
65 | struct timespec tv[2]; | ||
66 | |||
67 | if (t) { | ||
68 | if (get_user(tv[0].tv_sec, &t->actime) || | ||
69 | get_user(tv[1].tv_sec, &t->modtime)) | ||
70 | return -EFAULT; | ||
71 | tv[0].tv_nsec = 0; | ||
72 | tv[1].tv_nsec = 0; | ||
73 | } | ||
74 | return do_utimes(AT_FDCWD, filename, t ? tv : NULL, 0); | ||
75 | } | ||
76 | |||
77 | COMPAT_SYSCALL_DEFINE4(utimensat, unsigned int, dfd, const char __user *, filename, struct compat_timespec __user *, t, int, flags) | ||
78 | { | ||
79 | struct timespec tv[2]; | ||
80 | |||
81 | if (t) { | ||
82 | if (compat_get_timespec(&tv[0], &t[0]) || | ||
83 | compat_get_timespec(&tv[1], &t[1])) | ||
84 | return -EFAULT; | ||
85 | |||
86 | if (tv[0].tv_nsec == UTIME_OMIT && tv[1].tv_nsec == UTIME_OMIT) | ||
87 | return 0; | ||
88 | } | ||
89 | return do_utimes(dfd, filename, t ? tv : NULL, flags); | ||
90 | } | ||
91 | |||
92 | COMPAT_SYSCALL_DEFINE3(futimesat, unsigned int, dfd, const char __user *, filename, struct compat_timeval __user *, t) | ||
93 | { | ||
94 | struct timespec tv[2]; | ||
95 | |||
96 | if (t) { | ||
97 | if (get_user(tv[0].tv_sec, &t[0].tv_sec) || | ||
98 | get_user(tv[0].tv_nsec, &t[0].tv_usec) || | ||
99 | get_user(tv[1].tv_sec, &t[1].tv_sec) || | ||
100 | get_user(tv[1].tv_nsec, &t[1].tv_usec)) | ||
101 | return -EFAULT; | ||
102 | if (tv[0].tv_nsec >= 1000000 || tv[0].tv_nsec < 0 || | ||
103 | tv[1].tv_nsec >= 1000000 || tv[1].tv_nsec < 0) | ||
104 | return -EINVAL; | ||
105 | tv[0].tv_nsec *= 1000; | ||
106 | tv[1].tv_nsec *= 1000; | ||
107 | } | ||
108 | return do_utimes(dfd, filename, t ? tv : NULL, 0); | ||
109 | } | ||
110 | |||
111 | COMPAT_SYSCALL_DEFINE2(utimes, const char __user *, filename, struct compat_timeval __user *, t) | ||
112 | { | ||
113 | return compat_sys_futimesat(AT_FDCWD, filename, t); | ||
114 | } | ||
115 | |||
116 | static int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf) | ||
117 | { | ||
118 | struct compat_stat tmp; | ||
119 | |||
120 | if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev)) | ||
121 | return -EOVERFLOW; | ||
122 | |||
123 | memset(&tmp, 0, sizeof(tmp)); | ||
124 | tmp.st_dev = old_encode_dev(stat->dev); | ||
125 | tmp.st_ino = stat->ino; | ||
126 | if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) | ||
127 | return -EOVERFLOW; | ||
128 | tmp.st_mode = stat->mode; | ||
129 | tmp.st_nlink = stat->nlink; | ||
130 | if (tmp.st_nlink != stat->nlink) | ||
131 | return -EOVERFLOW; | ||
132 | SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid)); | ||
133 | SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid)); | ||
134 | tmp.st_rdev = old_encode_dev(stat->rdev); | ||
135 | if ((u64) stat->size > MAX_NON_LFS) | ||
136 | return -EOVERFLOW; | ||
137 | tmp.st_size = stat->size; | ||
138 | tmp.st_atime = stat->atime.tv_sec; | ||
139 | tmp.st_atime_nsec = stat->atime.tv_nsec; | ||
140 | tmp.st_mtime = stat->mtime.tv_sec; | ||
141 | tmp.st_mtime_nsec = stat->mtime.tv_nsec; | ||
142 | tmp.st_ctime = stat->ctime.tv_sec; | ||
143 | tmp.st_ctime_nsec = stat->ctime.tv_nsec; | ||
144 | tmp.st_blocks = stat->blocks; | ||
145 | tmp.st_blksize = stat->blksize; | ||
146 | return copy_to_user(ubuf, &tmp, sizeof(tmp)) ? -EFAULT : 0; | ||
147 | } | ||
148 | |||
149 | COMPAT_SYSCALL_DEFINE2(newstat, const char __user *, filename, | ||
150 | struct compat_stat __user *, statbuf) | ||
151 | { | ||
152 | struct kstat stat; | ||
153 | int error; | ||
154 | |||
155 | error = vfs_stat(filename, &stat); | ||
156 | if (error) | ||
157 | return error; | ||
158 | return cp_compat_stat(&stat, statbuf); | ||
159 | } | ||
160 | |||
161 | COMPAT_SYSCALL_DEFINE2(newlstat, const char __user *, filename, | ||
162 | struct compat_stat __user *, statbuf) | ||
163 | { | ||
164 | struct kstat stat; | ||
165 | int error; | ||
166 | |||
167 | error = vfs_lstat(filename, &stat); | ||
168 | if (error) | ||
169 | return error; | ||
170 | return cp_compat_stat(&stat, statbuf); | ||
171 | } | ||
172 | |||
173 | #ifndef __ARCH_WANT_STAT64 | ||
174 | COMPAT_SYSCALL_DEFINE4(newfstatat, unsigned int, dfd, | ||
175 | const char __user *, filename, | ||
176 | struct compat_stat __user *, statbuf, int, flag) | ||
177 | { | ||
178 | struct kstat stat; | ||
179 | int error; | ||
180 | |||
181 | error = vfs_fstatat(dfd, filename, &stat, flag); | ||
182 | if (error) | ||
183 | return error; | ||
184 | return cp_compat_stat(&stat, statbuf); | ||
185 | } | ||
186 | #endif | ||
187 | |||
188 | COMPAT_SYSCALL_DEFINE2(newfstat, unsigned int, fd, | ||
189 | struct compat_stat __user *, statbuf) | ||
190 | { | ||
191 | struct kstat stat; | ||
192 | int error = vfs_fstat(fd, &stat); | ||
193 | |||
194 | if (!error) | ||
195 | error = cp_compat_stat(&stat, statbuf); | ||
196 | return error; | ||
197 | } | ||
198 | |||
199 | static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *kbuf) | ||
200 | { | ||
201 | |||
202 | if (sizeof ubuf->f_blocks == 4) { | ||
203 | if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail | | ||
204 | kbuf->f_bsize | kbuf->f_frsize) & 0xffffffff00000000ULL) | ||
205 | return -EOVERFLOW; | ||
206 | /* f_files and f_ffree may be -1; it's okay | ||
207 | * to stuff that into 32 bits */ | ||
208 | if (kbuf->f_files != 0xffffffffffffffffULL | ||
209 | && (kbuf->f_files & 0xffffffff00000000ULL)) | ||
210 | return -EOVERFLOW; | ||
211 | if (kbuf->f_ffree != 0xffffffffffffffffULL | ||
212 | && (kbuf->f_ffree & 0xffffffff00000000ULL)) | ||
213 | return -EOVERFLOW; | ||
214 | } | ||
215 | if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)) || | ||
216 | __put_user(kbuf->f_type, &ubuf->f_type) || | ||
217 | __put_user(kbuf->f_bsize, &ubuf->f_bsize) || | ||
218 | __put_user(kbuf->f_blocks, &ubuf->f_blocks) || | ||
219 | __put_user(kbuf->f_bfree, &ubuf->f_bfree) || | ||
220 | __put_user(kbuf->f_bavail, &ubuf->f_bavail) || | ||
221 | __put_user(kbuf->f_files, &ubuf->f_files) || | ||
222 | __put_user(kbuf->f_ffree, &ubuf->f_ffree) || | ||
223 | __put_user(kbuf->f_namelen, &ubuf->f_namelen) || | ||
224 | __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) || | ||
225 | __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) || | ||
226 | __put_user(kbuf->f_frsize, &ubuf->f_frsize) || | ||
227 | __put_user(kbuf->f_flags, &ubuf->f_flags) || | ||
228 | __clear_user(ubuf->f_spare, sizeof(ubuf->f_spare))) | ||
229 | return -EFAULT; | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | /* | ||
234 | * The following statfs calls are copies of code from fs/statfs.c and | ||
235 | * should be checked against those from time to time | ||
236 | */ | ||
237 | COMPAT_SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct compat_statfs __user *, buf) | ||
238 | { | ||
239 | struct kstatfs tmp; | ||
240 | int error = user_statfs(pathname, &tmp); | ||
241 | if (!error) | ||
242 | error = put_compat_statfs(buf, &tmp); | ||
243 | return error; | ||
244 | } | ||
245 | |||
246 | COMPAT_SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct compat_statfs __user *, buf) | ||
247 | { | ||
248 | struct kstatfs tmp; | ||
249 | int error = fd_statfs(fd, &tmp); | ||
250 | if (!error) | ||
251 | error = put_compat_statfs(buf, &tmp); | ||
252 | return error; | ||
253 | } | ||
254 | |||
255 | static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstatfs *kbuf) | ||
256 | { | ||
257 | if (sizeof(ubuf->f_bsize) == 4) { | ||
258 | if ((kbuf->f_type | kbuf->f_bsize | kbuf->f_namelen | | ||
259 | kbuf->f_frsize | kbuf->f_flags) & 0xffffffff00000000ULL) | ||
260 | return -EOVERFLOW; | ||
261 | /* f_files and f_ffree may be -1; it's okay | ||
262 | * to stuff that into 32 bits */ | ||
263 | if (kbuf->f_files != 0xffffffffffffffffULL | ||
264 | && (kbuf->f_files & 0xffffffff00000000ULL)) | ||
265 | return -EOVERFLOW; | ||
266 | if (kbuf->f_ffree != 0xffffffffffffffffULL | ||
267 | && (kbuf->f_ffree & 0xffffffff00000000ULL)) | ||
268 | return -EOVERFLOW; | ||
269 | } | ||
270 | if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)) || | ||
271 | __put_user(kbuf->f_type, &ubuf->f_type) || | ||
272 | __put_user(kbuf->f_bsize, &ubuf->f_bsize) || | ||
273 | __put_user(kbuf->f_blocks, &ubuf->f_blocks) || | ||
274 | __put_user(kbuf->f_bfree, &ubuf->f_bfree) || | ||
275 | __put_user(kbuf->f_bavail, &ubuf->f_bavail) || | ||
276 | __put_user(kbuf->f_files, &ubuf->f_files) || | ||
277 | __put_user(kbuf->f_ffree, &ubuf->f_ffree) || | ||
278 | __put_user(kbuf->f_namelen, &ubuf->f_namelen) || | ||
279 | __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) || | ||
280 | __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) || | ||
281 | __put_user(kbuf->f_frsize, &ubuf->f_frsize) || | ||
282 | __put_user(kbuf->f_flags, &ubuf->f_flags) || | ||
283 | __clear_user(ubuf->f_spare, sizeof(ubuf->f_spare))) | ||
284 | return -EFAULT; | ||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | COMPAT_SYSCALL_DEFINE3(statfs64, const char __user *, pathname, compat_size_t, sz, struct compat_statfs64 __user *, buf) | ||
289 | { | ||
290 | struct kstatfs tmp; | ||
291 | int error; | ||
292 | |||
293 | if (sz != sizeof(*buf)) | ||
294 | return -EINVAL; | ||
295 | |||
296 | error = user_statfs(pathname, &tmp); | ||
297 | if (!error) | ||
298 | error = put_compat_statfs64(buf, &tmp); | ||
299 | return error; | ||
300 | } | ||
301 | |||
302 | COMPAT_SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, compat_size_t, sz, struct compat_statfs64 __user *, buf) | ||
303 | { | ||
304 | struct kstatfs tmp; | ||
305 | int error; | ||
306 | |||
307 | if (sz != sizeof(*buf)) | ||
308 | return -EINVAL; | ||
309 | |||
310 | error = fd_statfs(fd, &tmp); | ||
311 | if (!error) | ||
312 | error = put_compat_statfs64(buf, &tmp); | ||
313 | return error; | ||
314 | } | ||
315 | |||
316 | /* | ||
317 | * This is a copy of sys_ustat, just dealing with a structure layout. | ||
318 | * Given how simple this syscall is that apporach is more maintainable | ||
319 | * than the various conversion hacks. | ||
320 | */ | ||
321 | COMPAT_SYSCALL_DEFINE2(ustat, unsigned, dev, struct compat_ustat __user *, u) | ||
322 | { | ||
323 | struct compat_ustat tmp; | ||
324 | struct kstatfs sbuf; | ||
325 | int err = vfs_ustat(new_decode_dev(dev), &sbuf); | ||
326 | if (err) | ||
327 | return err; | ||
328 | |||
329 | memset(&tmp, 0, sizeof(struct compat_ustat)); | ||
330 | tmp.f_tfree = sbuf.f_bfree; | ||
331 | tmp.f_tinode = sbuf.f_ffree; | ||
332 | if (copy_to_user(u, &tmp, sizeof(struct compat_ustat))) | ||
333 | return -EFAULT; | ||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl) | ||
338 | { | ||
339 | if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) || | ||
340 | __get_user(kfl->l_type, &ufl->l_type) || | ||
341 | __get_user(kfl->l_whence, &ufl->l_whence) || | ||
342 | __get_user(kfl->l_start, &ufl->l_start) || | ||
343 | __get_user(kfl->l_len, &ufl->l_len) || | ||
344 | __get_user(kfl->l_pid, &ufl->l_pid)) | ||
345 | return -EFAULT; | ||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | static int put_compat_flock(struct flock *kfl, struct compat_flock __user *ufl) | ||
350 | { | ||
351 | if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) || | ||
352 | __put_user(kfl->l_type, &ufl->l_type) || | ||
353 | __put_user(kfl->l_whence, &ufl->l_whence) || | ||
354 | __put_user(kfl->l_start, &ufl->l_start) || | ||
355 | __put_user(kfl->l_len, &ufl->l_len) || | ||
356 | __put_user(kfl->l_pid, &ufl->l_pid)) | ||
357 | return -EFAULT; | ||
358 | return 0; | ||
359 | } | ||
360 | |||
361 | #ifndef HAVE_ARCH_GET_COMPAT_FLOCK64 | ||
362 | static int get_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl) | ||
363 | { | ||
364 | if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) || | ||
365 | __get_user(kfl->l_type, &ufl->l_type) || | ||
366 | __get_user(kfl->l_whence, &ufl->l_whence) || | ||
367 | __get_user(kfl->l_start, &ufl->l_start) || | ||
368 | __get_user(kfl->l_len, &ufl->l_len) || | ||
369 | __get_user(kfl->l_pid, &ufl->l_pid)) | ||
370 | return -EFAULT; | ||
371 | return 0; | ||
372 | } | ||
373 | #endif | ||
374 | |||
375 | #ifndef HAVE_ARCH_PUT_COMPAT_FLOCK64 | ||
376 | static int put_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl) | ||
377 | { | ||
378 | if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) || | ||
379 | __put_user(kfl->l_type, &ufl->l_type) || | ||
380 | __put_user(kfl->l_whence, &ufl->l_whence) || | ||
381 | __put_user(kfl->l_start, &ufl->l_start) || | ||
382 | __put_user(kfl->l_len, &ufl->l_len) || | ||
383 | __put_user(kfl->l_pid, &ufl->l_pid)) | ||
384 | return -EFAULT; | ||
385 | return 0; | ||
386 | } | ||
387 | #endif | ||
388 | |||
389 | static unsigned int | ||
390 | convert_fcntl_cmd(unsigned int cmd) | ||
391 | { | ||
392 | switch (cmd) { | ||
393 | case F_GETLK64: | ||
394 | return F_GETLK; | ||
395 | case F_SETLK64: | ||
396 | return F_SETLK; | ||
397 | case F_SETLKW64: | ||
398 | return F_SETLKW; | ||
399 | } | ||
400 | |||
401 | return cmd; | ||
402 | } | ||
403 | |||
404 | COMPAT_SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, | ||
405 | compat_ulong_t, arg) | ||
406 | { | ||
407 | mm_segment_t old_fs; | ||
408 | struct flock f; | ||
409 | long ret; | ||
410 | unsigned int conv_cmd; | ||
411 | |||
412 | switch (cmd) { | ||
413 | case F_GETLK: | ||
414 | case F_SETLK: | ||
415 | case F_SETLKW: | ||
416 | ret = get_compat_flock(&f, compat_ptr(arg)); | ||
417 | if (ret != 0) | ||
418 | break; | ||
419 | old_fs = get_fs(); | ||
420 | set_fs(KERNEL_DS); | ||
421 | ret = sys_fcntl(fd, cmd, (unsigned long)&f); | ||
422 | set_fs(old_fs); | ||
423 | if (cmd == F_GETLK && ret == 0) { | ||
424 | /* GETLK was successful and we need to return the data... | ||
425 | * but it needs to fit in the compat structure. | ||
426 | * l_start shouldn't be too big, unless the original | ||
427 | * start + end is greater than COMPAT_OFF_T_MAX, in which | ||
428 | * case the app was asking for trouble, so we return | ||
429 | * -EOVERFLOW in that case. | ||
430 | * l_len could be too big, in which case we just truncate it, | ||
431 | * and only allow the app to see that part of the conflicting | ||
432 | * lock that might make sense to it anyway | ||
433 | */ | ||
434 | |||
435 | if (f.l_start > COMPAT_OFF_T_MAX) | ||
436 | ret = -EOVERFLOW; | ||
437 | if (f.l_len > COMPAT_OFF_T_MAX) | ||
438 | f.l_len = COMPAT_OFF_T_MAX; | ||
439 | if (ret == 0) | ||
440 | ret = put_compat_flock(&f, compat_ptr(arg)); | ||
441 | } | ||
442 | break; | ||
443 | |||
444 | case F_GETLK64: | ||
445 | case F_SETLK64: | ||
446 | case F_SETLKW64: | ||
447 | case F_OFD_GETLK: | ||
448 | case F_OFD_SETLK: | ||
449 | case F_OFD_SETLKW: | ||
450 | ret = get_compat_flock64(&f, compat_ptr(arg)); | ||
451 | if (ret != 0) | ||
452 | break; | ||
453 | old_fs = get_fs(); | ||
454 | set_fs(KERNEL_DS); | ||
455 | conv_cmd = convert_fcntl_cmd(cmd); | ||
456 | ret = sys_fcntl(fd, conv_cmd, (unsigned long)&f); | ||
457 | set_fs(old_fs); | ||
458 | if ((conv_cmd == F_GETLK || conv_cmd == F_OFD_GETLK) && ret == 0) { | ||
459 | /* need to return lock information - see above for commentary */ | ||
460 | if (f.l_start > COMPAT_LOFF_T_MAX) | ||
461 | ret = -EOVERFLOW; | ||
462 | if (f.l_len > COMPAT_LOFF_T_MAX) | ||
463 | f.l_len = COMPAT_LOFF_T_MAX; | ||
464 | if (ret == 0) | ||
465 | ret = put_compat_flock64(&f, compat_ptr(arg)); | ||
466 | } | ||
467 | break; | ||
468 | |||
469 | default: | ||
470 | ret = sys_fcntl(fd, cmd, arg); | ||
471 | break; | ||
472 | } | ||
473 | return ret; | ||
474 | } | ||
475 | |||
476 | COMPAT_SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, | ||
477 | compat_ulong_t, arg) | ||
478 | { | ||
479 | switch (cmd) { | ||
480 | case F_GETLK64: | ||
481 | case F_SETLK64: | ||
482 | case F_SETLKW64: | ||
483 | case F_OFD_GETLK: | ||
484 | case F_OFD_SETLK: | ||
485 | case F_OFD_SETLKW: | ||
486 | return -EINVAL; | ||
487 | } | ||
488 | return compat_sys_fcntl64(fd, cmd, arg); | ||
489 | } | ||
490 | |||
491 | /* A write operation does a read from user space and vice versa */ | ||
492 | #define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ) | ||
493 | |||
494 | ssize_t compat_rw_copy_check_uvector(int type, | ||
495 | const struct compat_iovec __user *uvector, unsigned long nr_segs, | ||
496 | unsigned long fast_segs, struct iovec *fast_pointer, | ||
497 | struct iovec **ret_pointer) | ||
498 | { | ||
499 | compat_ssize_t tot_len; | ||
500 | struct iovec *iov = *ret_pointer = fast_pointer; | ||
501 | ssize_t ret = 0; | ||
502 | int seg; | ||
503 | |||
504 | /* | ||
505 | * SuS says "The readv() function *may* fail if the iovcnt argument | ||
506 | * was less than or equal to 0, or greater than {IOV_MAX}. Linux has | ||
507 | * traditionally returned zero for zero segments, so... | ||
508 | */ | ||
509 | if (nr_segs == 0) | ||
510 | goto out; | ||
511 | |||
512 | ret = -EINVAL; | ||
513 | if (nr_segs > UIO_MAXIOV) | ||
514 | goto out; | ||
515 | if (nr_segs > fast_segs) { | ||
516 | ret = -ENOMEM; | ||
517 | iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL); | ||
518 | if (iov == NULL) | ||
519 | goto out; | ||
520 | } | ||
521 | *ret_pointer = iov; | ||
522 | |||
523 | ret = -EFAULT; | ||
524 | if (!access_ok(VERIFY_READ, uvector, nr_segs*sizeof(*uvector))) | ||
525 | goto out; | ||
526 | |||
527 | /* | ||
528 | * Single unix specification: | ||
529 | * We should -EINVAL if an element length is not >= 0 and fitting an | ||
530 | * ssize_t. | ||
531 | * | ||
532 | * In Linux, the total length is limited to MAX_RW_COUNT, there is | ||
533 | * no overflow possibility. | ||
534 | */ | ||
535 | tot_len = 0; | ||
536 | ret = -EINVAL; | ||
537 | for (seg = 0; seg < nr_segs; seg++) { | ||
538 | compat_uptr_t buf; | ||
539 | compat_ssize_t len; | ||
540 | |||
541 | if (__get_user(len, &uvector->iov_len) || | ||
542 | __get_user(buf, &uvector->iov_base)) { | ||
543 | ret = -EFAULT; | ||
544 | goto out; | ||
545 | } | ||
546 | if (len < 0) /* size_t not fitting in compat_ssize_t .. */ | ||
547 | goto out; | ||
548 | if (type >= 0 && | ||
549 | !access_ok(vrfy_dir(type), compat_ptr(buf), len)) { | ||
550 | ret = -EFAULT; | ||
551 | goto out; | ||
552 | } | ||
553 | if (len > MAX_RW_COUNT - tot_len) | ||
554 | len = MAX_RW_COUNT - tot_len; | ||
555 | tot_len += len; | ||
556 | iov->iov_base = compat_ptr(buf); | ||
557 | iov->iov_len = (compat_size_t) len; | ||
558 | uvector++; | ||
559 | iov++; | ||
560 | } | ||
561 | ret = tot_len; | ||
562 | |||
563 | out: | ||
564 | return ret; | ||
565 | } | ||
566 | |||
567 | struct compat_ncp_mount_data { | 26 | struct compat_ncp_mount_data { |
568 | compat_int_t version; | 27 | compat_int_t version; |
569 | compat_uint_t ncp_fd; | 28 | compat_uint_t ncp_fd; |
@@ -744,653 +203,3 @@ COMPAT_SYSCALL_DEFINE5(mount, const char __user *, dev_name, | |||
744 | out: | 203 | out: |
745 | return retval; | 204 | return retval; |
746 | } | 205 | } |
747 | |||
748 | struct compat_old_linux_dirent { | ||
749 | compat_ulong_t d_ino; | ||
750 | compat_ulong_t d_offset; | ||
751 | unsigned short d_namlen; | ||
752 | char d_name[1]; | ||
753 | }; | ||
754 | |||
755 | struct compat_readdir_callback { | ||
756 | struct dir_context ctx; | ||
757 | struct compat_old_linux_dirent __user *dirent; | ||
758 | int result; | ||
759 | }; | ||
760 | |||
761 | static int compat_fillonedir(struct dir_context *ctx, const char *name, | ||
762 | int namlen, loff_t offset, u64 ino, | ||
763 | unsigned int d_type) | ||
764 | { | ||
765 | struct compat_readdir_callback *buf = | ||
766 | container_of(ctx, struct compat_readdir_callback, ctx); | ||
767 | struct compat_old_linux_dirent __user *dirent; | ||
768 | compat_ulong_t d_ino; | ||
769 | |||
770 | if (buf->result) | ||
771 | return -EINVAL; | ||
772 | d_ino = ino; | ||
773 | if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { | ||
774 | buf->result = -EOVERFLOW; | ||
775 | return -EOVERFLOW; | ||
776 | } | ||
777 | buf->result++; | ||
778 | dirent = buf->dirent; | ||
779 | if (!access_ok(VERIFY_WRITE, dirent, | ||
780 | (unsigned long)(dirent->d_name + namlen + 1) - | ||
781 | (unsigned long)dirent)) | ||
782 | goto efault; | ||
783 | if ( __put_user(d_ino, &dirent->d_ino) || | ||
784 | __put_user(offset, &dirent->d_offset) || | ||
785 | __put_user(namlen, &dirent->d_namlen) || | ||
786 | __copy_to_user(dirent->d_name, name, namlen) || | ||
787 | __put_user(0, dirent->d_name + namlen)) | ||
788 | goto efault; | ||
789 | return 0; | ||
790 | efault: | ||
791 | buf->result = -EFAULT; | ||
792 | return -EFAULT; | ||
793 | } | ||
794 | |||
795 | COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd, | ||
796 | struct compat_old_linux_dirent __user *, dirent, unsigned int, count) | ||
797 | { | ||
798 | int error; | ||
799 | struct fd f = fdget_pos(fd); | ||
800 | struct compat_readdir_callback buf = { | ||
801 | .ctx.actor = compat_fillonedir, | ||
802 | .dirent = dirent | ||
803 | }; | ||
804 | |||
805 | if (!f.file) | ||
806 | return -EBADF; | ||
807 | |||
808 | error = iterate_dir(f.file, &buf.ctx); | ||
809 | if (buf.result) | ||
810 | error = buf.result; | ||
811 | |||
812 | fdput_pos(f); | ||
813 | return error; | ||
814 | } | ||
815 | |||
816 | struct compat_linux_dirent { | ||
817 | compat_ulong_t d_ino; | ||
818 | compat_ulong_t d_off; | ||
819 | unsigned short d_reclen; | ||
820 | char d_name[1]; | ||
821 | }; | ||
822 | |||
823 | struct compat_getdents_callback { | ||
824 | struct dir_context ctx; | ||
825 | struct compat_linux_dirent __user *current_dir; | ||
826 | struct compat_linux_dirent __user *previous; | ||
827 | int count; | ||
828 | int error; | ||
829 | }; | ||
830 | |||
831 | static int compat_filldir(struct dir_context *ctx, const char *name, int namlen, | ||
832 | loff_t offset, u64 ino, unsigned int d_type) | ||
833 | { | ||
834 | struct compat_linux_dirent __user * dirent; | ||
835 | struct compat_getdents_callback *buf = | ||
836 | container_of(ctx, struct compat_getdents_callback, ctx); | ||
837 | compat_ulong_t d_ino; | ||
838 | int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) + | ||
839 | namlen + 2, sizeof(compat_long_t)); | ||
840 | |||
841 | buf->error = -EINVAL; /* only used if we fail.. */ | ||
842 | if (reclen > buf->count) | ||
843 | return -EINVAL; | ||
844 | d_ino = ino; | ||
845 | if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { | ||
846 | buf->error = -EOVERFLOW; | ||
847 | return -EOVERFLOW; | ||
848 | } | ||
849 | dirent = buf->previous; | ||
850 | if (dirent) { | ||
851 | if (signal_pending(current)) | ||
852 | return -EINTR; | ||
853 | if (__put_user(offset, &dirent->d_off)) | ||
854 | goto efault; | ||
855 | } | ||
856 | dirent = buf->current_dir; | ||
857 | if (__put_user(d_ino, &dirent->d_ino)) | ||
858 | goto efault; | ||
859 | if (__put_user(reclen, &dirent->d_reclen)) | ||
860 | goto efault; | ||
861 | if (copy_to_user(dirent->d_name, name, namlen)) | ||
862 | goto efault; | ||
863 | if (__put_user(0, dirent->d_name + namlen)) | ||
864 | goto efault; | ||
865 | if (__put_user(d_type, (char __user *) dirent + reclen - 1)) | ||
866 | goto efault; | ||
867 | buf->previous = dirent; | ||
868 | dirent = (void __user *)dirent + reclen; | ||
869 | buf->current_dir = dirent; | ||
870 | buf->count -= reclen; | ||
871 | return 0; | ||
872 | efault: | ||
873 | buf->error = -EFAULT; | ||
874 | return -EFAULT; | ||
875 | } | ||
876 | |||
877 | COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd, | ||
878 | struct compat_linux_dirent __user *, dirent, unsigned int, count) | ||
879 | { | ||
880 | struct fd f; | ||
881 | struct compat_linux_dirent __user * lastdirent; | ||
882 | struct compat_getdents_callback buf = { | ||
883 | .ctx.actor = compat_filldir, | ||
884 | .current_dir = dirent, | ||
885 | .count = count | ||
886 | }; | ||
887 | int error; | ||
888 | |||
889 | if (!access_ok(VERIFY_WRITE, dirent, count)) | ||
890 | return -EFAULT; | ||
891 | |||
892 | f = fdget_pos(fd); | ||
893 | if (!f.file) | ||
894 | return -EBADF; | ||
895 | |||
896 | error = iterate_dir(f.file, &buf.ctx); | ||
897 | if (error >= 0) | ||
898 | error = buf.error; | ||
899 | lastdirent = buf.previous; | ||
900 | if (lastdirent) { | ||
901 | if (put_user(buf.ctx.pos, &lastdirent->d_off)) | ||
902 | error = -EFAULT; | ||
903 | else | ||
904 | error = count - buf.count; | ||
905 | } | ||
906 | fdput_pos(f); | ||
907 | return error; | ||
908 | } | ||
909 | |||
910 | #ifdef __ARCH_WANT_COMPAT_SYS_GETDENTS64 | ||
911 | |||
912 | struct compat_getdents_callback64 { | ||
913 | struct dir_context ctx; | ||
914 | struct linux_dirent64 __user *current_dir; | ||
915 | struct linux_dirent64 __user *previous; | ||
916 | int count; | ||
917 | int error; | ||
918 | }; | ||
919 | |||
920 | static int compat_filldir64(struct dir_context *ctx, const char *name, | ||
921 | int namlen, loff_t offset, u64 ino, | ||
922 | unsigned int d_type) | ||
923 | { | ||
924 | struct linux_dirent64 __user *dirent; | ||
925 | struct compat_getdents_callback64 *buf = | ||
926 | container_of(ctx, struct compat_getdents_callback64, ctx); | ||
927 | int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1, | ||
928 | sizeof(u64)); | ||
929 | u64 off; | ||
930 | |||
931 | buf->error = -EINVAL; /* only used if we fail.. */ | ||
932 | if (reclen > buf->count) | ||
933 | return -EINVAL; | ||
934 | dirent = buf->previous; | ||
935 | |||
936 | if (dirent) { | ||
937 | if (signal_pending(current)) | ||
938 | return -EINTR; | ||
939 | if (__put_user_unaligned(offset, &dirent->d_off)) | ||
940 | goto efault; | ||
941 | } | ||
942 | dirent = buf->current_dir; | ||
943 | if (__put_user_unaligned(ino, &dirent->d_ino)) | ||
944 | goto efault; | ||
945 | off = 0; | ||
946 | if (__put_user_unaligned(off, &dirent->d_off)) | ||
947 | goto efault; | ||
948 | if (__put_user(reclen, &dirent->d_reclen)) | ||
949 | goto efault; | ||
950 | if (__put_user(d_type, &dirent->d_type)) | ||
951 | goto efault; | ||
952 | if (copy_to_user(dirent->d_name, name, namlen)) | ||
953 | goto efault; | ||
954 | if (__put_user(0, dirent->d_name + namlen)) | ||
955 | goto efault; | ||
956 | buf->previous = dirent; | ||
957 | dirent = (void __user *)dirent + reclen; | ||
958 | buf->current_dir = dirent; | ||
959 | buf->count -= reclen; | ||
960 | return 0; | ||
961 | efault: | ||
962 | buf->error = -EFAULT; | ||
963 | return -EFAULT; | ||
964 | } | ||
965 | |||
966 | COMPAT_SYSCALL_DEFINE3(getdents64, unsigned int, fd, | ||
967 | struct linux_dirent64 __user *, dirent, unsigned int, count) | ||
968 | { | ||
969 | struct fd f; | ||
970 | struct linux_dirent64 __user * lastdirent; | ||
971 | struct compat_getdents_callback64 buf = { | ||
972 | .ctx.actor = compat_filldir64, | ||
973 | .current_dir = dirent, | ||
974 | .count = count | ||
975 | }; | ||
976 | int error; | ||
977 | |||
978 | if (!access_ok(VERIFY_WRITE, dirent, count)) | ||
979 | return -EFAULT; | ||
980 | |||
981 | f = fdget_pos(fd); | ||
982 | if (!f.file) | ||
983 | return -EBADF; | ||
984 | |||
985 | error = iterate_dir(f.file, &buf.ctx); | ||
986 | if (error >= 0) | ||
987 | error = buf.error; | ||
988 | lastdirent = buf.previous; | ||
989 | if (lastdirent) { | ||
990 | typeof(lastdirent->d_off) d_off = buf.ctx.pos; | ||
991 | if (__put_user_unaligned(d_off, &lastdirent->d_off)) | ||
992 | error = -EFAULT; | ||
993 | else | ||
994 | error = count - buf.count; | ||
995 | } | ||
996 | fdput_pos(f); | ||
997 | return error; | ||
998 | } | ||
999 | #endif /* __ARCH_WANT_COMPAT_SYS_GETDENTS64 */ | ||
1000 | |||
1001 | /* | ||
1002 | * Exactly like fs/open.c:sys_open(), except that it doesn't set the | ||
1003 | * O_LARGEFILE flag. | ||
1004 | */ | ||
1005 | COMPAT_SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode) | ||
1006 | { | ||
1007 | return do_sys_open(AT_FDCWD, filename, flags, mode); | ||
1008 | } | ||
1009 | |||
1010 | /* | ||
1011 | * Exactly like fs/open.c:sys_openat(), except that it doesn't set the | ||
1012 | * O_LARGEFILE flag. | ||
1013 | */ | ||
1014 | COMPAT_SYSCALL_DEFINE4(openat, int, dfd, const char __user *, filename, int, flags, umode_t, mode) | ||
1015 | { | ||
1016 | return do_sys_open(dfd, filename, flags, mode); | ||
1017 | } | ||
1018 | |||
1019 | #define __COMPAT_NFDBITS (8 * sizeof(compat_ulong_t)) | ||
1020 | |||
1021 | static int poll_select_copy_remaining(struct timespec *end_time, void __user *p, | ||
1022 | int timeval, int ret) | ||
1023 | { | ||
1024 | struct timespec ts; | ||
1025 | |||
1026 | if (!p) | ||
1027 | return ret; | ||
1028 | |||
1029 | if (current->personality & STICKY_TIMEOUTS) | ||
1030 | goto sticky; | ||
1031 | |||
1032 | /* No update for zero timeout */ | ||
1033 | if (!end_time->tv_sec && !end_time->tv_nsec) | ||
1034 | return ret; | ||
1035 | |||
1036 | ktime_get_ts(&ts); | ||
1037 | ts = timespec_sub(*end_time, ts); | ||
1038 | if (ts.tv_sec < 0) | ||
1039 | ts.tv_sec = ts.tv_nsec = 0; | ||
1040 | |||
1041 | if (timeval) { | ||
1042 | struct compat_timeval rtv; | ||
1043 | |||
1044 | rtv.tv_sec = ts.tv_sec; | ||
1045 | rtv.tv_usec = ts.tv_nsec / NSEC_PER_USEC; | ||
1046 | |||
1047 | if (!copy_to_user(p, &rtv, sizeof(rtv))) | ||
1048 | return ret; | ||
1049 | } else { | ||
1050 | struct compat_timespec rts; | ||
1051 | |||
1052 | rts.tv_sec = ts.tv_sec; | ||
1053 | rts.tv_nsec = ts.tv_nsec; | ||
1054 | |||
1055 | if (!copy_to_user(p, &rts, sizeof(rts))) | ||
1056 | return ret; | ||
1057 | } | ||
1058 | /* | ||
1059 | * If an application puts its timeval in read-only memory, we | ||
1060 | * don't want the Linux-specific update to the timeval to | ||
1061 | * cause a fault after the select has completed | ||
1062 | * successfully. However, because we're not updating the | ||
1063 | * timeval, we can't restart the system call. | ||
1064 | */ | ||
1065 | |||
1066 | sticky: | ||
1067 | if (ret == -ERESTARTNOHAND) | ||
1068 | ret = -EINTR; | ||
1069 | return ret; | ||
1070 | } | ||
1071 | |||
1072 | /* | ||
1073 | * Ooo, nasty. We need here to frob 32-bit unsigned longs to | ||
1074 | * 64-bit unsigned longs. | ||
1075 | */ | ||
1076 | static | ||
1077 | int compat_get_fd_set(unsigned long nr, compat_ulong_t __user *ufdset, | ||
1078 | unsigned long *fdset) | ||
1079 | { | ||
1080 | nr = DIV_ROUND_UP(nr, __COMPAT_NFDBITS); | ||
1081 | if (ufdset) { | ||
1082 | unsigned long odd; | ||
1083 | |||
1084 | if (!access_ok(VERIFY_WRITE, ufdset, nr*sizeof(compat_ulong_t))) | ||
1085 | return -EFAULT; | ||
1086 | |||
1087 | odd = nr & 1UL; | ||
1088 | nr &= ~1UL; | ||
1089 | while (nr) { | ||
1090 | unsigned long h, l; | ||
1091 | if (__get_user(l, ufdset) || __get_user(h, ufdset+1)) | ||
1092 | return -EFAULT; | ||
1093 | ufdset += 2; | ||
1094 | *fdset++ = h << 32 | l; | ||
1095 | nr -= 2; | ||
1096 | } | ||
1097 | if (odd && __get_user(*fdset, ufdset)) | ||
1098 | return -EFAULT; | ||
1099 | } else { | ||
1100 | /* Tricky, must clear full unsigned long in the | ||
1101 | * kernel fdset at the end, this makes sure that | ||
1102 | * actually happens. | ||
1103 | */ | ||
1104 | memset(fdset, 0, ((nr + 1) & ~1)*sizeof(compat_ulong_t)); | ||
1105 | } | ||
1106 | return 0; | ||
1107 | } | ||
1108 | |||
1109 | static | ||
1110 | int compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset, | ||
1111 | unsigned long *fdset) | ||
1112 | { | ||
1113 | unsigned long odd; | ||
1114 | nr = DIV_ROUND_UP(nr, __COMPAT_NFDBITS); | ||
1115 | |||
1116 | if (!ufdset) | ||
1117 | return 0; | ||
1118 | |||
1119 | odd = nr & 1UL; | ||
1120 | nr &= ~1UL; | ||
1121 | while (nr) { | ||
1122 | unsigned long h, l; | ||
1123 | l = *fdset++; | ||
1124 | h = l >> 32; | ||
1125 | if (__put_user(l, ufdset) || __put_user(h, ufdset+1)) | ||
1126 | return -EFAULT; | ||
1127 | ufdset += 2; | ||
1128 | nr -= 2; | ||
1129 | } | ||
1130 | if (odd && __put_user(*fdset, ufdset)) | ||
1131 | return -EFAULT; | ||
1132 | return 0; | ||
1133 | } | ||
1134 | |||
1135 | |||
1136 | /* | ||
1137 | * This is a virtual copy of sys_select from fs/select.c and probably | ||
1138 | * should be compared to it from time to time | ||
1139 | */ | ||
1140 | |||
1141 | /* | ||
1142 | * We can actually return ERESTARTSYS instead of EINTR, but I'd | ||
1143 | * like to be certain this leads to no problems. So I return | ||
1144 | * EINTR just for safety. | ||
1145 | * | ||
1146 | * Update: ERESTARTSYS breaks at least the xview clock binary, so | ||
1147 | * I'm trying ERESTARTNOHAND which restart only when you want to. | ||
1148 | */ | ||
1149 | int compat_core_sys_select(int n, compat_ulong_t __user *inp, | ||
1150 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, | ||
1151 | struct timespec *end_time) | ||
1152 | { | ||
1153 | fd_set_bits fds; | ||
1154 | void *bits; | ||
1155 | int size, max_fds, ret = -EINVAL; | ||
1156 | struct fdtable *fdt; | ||
1157 | long stack_fds[SELECT_STACK_ALLOC/sizeof(long)]; | ||
1158 | |||
1159 | if (n < 0) | ||
1160 | goto out_nofds; | ||
1161 | |||
1162 | /* max_fds can increase, so grab it once to avoid race */ | ||
1163 | rcu_read_lock(); | ||
1164 | fdt = files_fdtable(current->files); | ||
1165 | max_fds = fdt->max_fds; | ||
1166 | rcu_read_unlock(); | ||
1167 | if (n > max_fds) | ||
1168 | n = max_fds; | ||
1169 | |||
1170 | /* | ||
1171 | * We need 6 bitmaps (in/out/ex for both incoming and outgoing), | ||
1172 | * since we used fdset we need to allocate memory in units of | ||
1173 | * long-words. | ||
1174 | */ | ||
1175 | size = FDS_BYTES(n); | ||
1176 | bits = stack_fds; | ||
1177 | if (size > sizeof(stack_fds) / 6) { | ||
1178 | bits = kmalloc(6 * size, GFP_KERNEL); | ||
1179 | ret = -ENOMEM; | ||
1180 | if (!bits) | ||
1181 | goto out_nofds; | ||
1182 | } | ||
1183 | fds.in = (unsigned long *) bits; | ||
1184 | fds.out = (unsigned long *) (bits + size); | ||
1185 | fds.ex = (unsigned long *) (bits + 2*size); | ||
1186 | fds.res_in = (unsigned long *) (bits + 3*size); | ||
1187 | fds.res_out = (unsigned long *) (bits + 4*size); | ||
1188 | fds.res_ex = (unsigned long *) (bits + 5*size); | ||
1189 | |||
1190 | if ((ret = compat_get_fd_set(n, inp, fds.in)) || | ||
1191 | (ret = compat_get_fd_set(n, outp, fds.out)) || | ||
1192 | (ret = compat_get_fd_set(n, exp, fds.ex))) | ||
1193 | goto out; | ||
1194 | zero_fd_set(n, fds.res_in); | ||
1195 | zero_fd_set(n, fds.res_out); | ||
1196 | zero_fd_set(n, fds.res_ex); | ||
1197 | |||
1198 | ret = do_select(n, &fds, end_time); | ||
1199 | |||
1200 | if (ret < 0) | ||
1201 | goto out; | ||
1202 | if (!ret) { | ||
1203 | ret = -ERESTARTNOHAND; | ||
1204 | if (signal_pending(current)) | ||
1205 | goto out; | ||
1206 | ret = 0; | ||
1207 | } | ||
1208 | |||
1209 | if (compat_set_fd_set(n, inp, fds.res_in) || | ||
1210 | compat_set_fd_set(n, outp, fds.res_out) || | ||
1211 | compat_set_fd_set(n, exp, fds.res_ex)) | ||
1212 | ret = -EFAULT; | ||
1213 | out: | ||
1214 | if (bits != stack_fds) | ||
1215 | kfree(bits); | ||
1216 | out_nofds: | ||
1217 | return ret; | ||
1218 | } | ||
1219 | |||
1220 | COMPAT_SYSCALL_DEFINE5(select, int, n, compat_ulong_t __user *, inp, | ||
1221 | compat_ulong_t __user *, outp, compat_ulong_t __user *, exp, | ||
1222 | struct compat_timeval __user *, tvp) | ||
1223 | { | ||
1224 | struct timespec end_time, *to = NULL; | ||
1225 | struct compat_timeval tv; | ||
1226 | int ret; | ||
1227 | |||
1228 | if (tvp) { | ||
1229 | if (copy_from_user(&tv, tvp, sizeof(tv))) | ||
1230 | return -EFAULT; | ||
1231 | |||
1232 | to = &end_time; | ||
1233 | if (poll_select_set_timeout(to, | ||
1234 | tv.tv_sec + (tv.tv_usec / USEC_PER_SEC), | ||
1235 | (tv.tv_usec % USEC_PER_SEC) * NSEC_PER_USEC)) | ||
1236 | return -EINVAL; | ||
1237 | } | ||
1238 | |||
1239 | ret = compat_core_sys_select(n, inp, outp, exp, to); | ||
1240 | ret = poll_select_copy_remaining(&end_time, tvp, 1, ret); | ||
1241 | |||
1242 | return ret; | ||
1243 | } | ||
1244 | |||
1245 | struct compat_sel_arg_struct { | ||
1246 | compat_ulong_t n; | ||
1247 | compat_uptr_t inp; | ||
1248 | compat_uptr_t outp; | ||
1249 | compat_uptr_t exp; | ||
1250 | compat_uptr_t tvp; | ||
1251 | }; | ||
1252 | |||
1253 | COMPAT_SYSCALL_DEFINE1(old_select, struct compat_sel_arg_struct __user *, arg) | ||
1254 | { | ||
1255 | struct compat_sel_arg_struct a; | ||
1256 | |||
1257 | if (copy_from_user(&a, arg, sizeof(a))) | ||
1258 | return -EFAULT; | ||
1259 | return compat_sys_select(a.n, compat_ptr(a.inp), compat_ptr(a.outp), | ||
1260 | compat_ptr(a.exp), compat_ptr(a.tvp)); | ||
1261 | } | ||
1262 | |||
1263 | static long do_compat_pselect(int n, compat_ulong_t __user *inp, | ||
1264 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, | ||
1265 | struct compat_timespec __user *tsp, compat_sigset_t __user *sigmask, | ||
1266 | compat_size_t sigsetsize) | ||
1267 | { | ||
1268 | compat_sigset_t ss32; | ||
1269 | sigset_t ksigmask, sigsaved; | ||
1270 | struct compat_timespec ts; | ||
1271 | struct timespec end_time, *to = NULL; | ||
1272 | int ret; | ||
1273 | |||
1274 | if (tsp) { | ||
1275 | if (copy_from_user(&ts, tsp, sizeof(ts))) | ||
1276 | return -EFAULT; | ||
1277 | |||
1278 | to = &end_time; | ||
1279 | if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec)) | ||
1280 | return -EINVAL; | ||
1281 | } | ||
1282 | |||
1283 | if (sigmask) { | ||
1284 | if (sigsetsize != sizeof(compat_sigset_t)) | ||
1285 | return -EINVAL; | ||
1286 | if (copy_from_user(&ss32, sigmask, sizeof(ss32))) | ||
1287 | return -EFAULT; | ||
1288 | sigset_from_compat(&ksigmask, &ss32); | ||
1289 | |||
1290 | sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP)); | ||
1291 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | ||
1292 | } | ||
1293 | |||
1294 | ret = compat_core_sys_select(n, inp, outp, exp, to); | ||
1295 | ret = poll_select_copy_remaining(&end_time, tsp, 0, ret); | ||
1296 | |||
1297 | if (ret == -ERESTARTNOHAND) { | ||
1298 | /* | ||
1299 | * Don't restore the signal mask yet. Let do_signal() deliver | ||
1300 | * the signal on the way back to userspace, before the signal | ||
1301 | * mask is restored. | ||
1302 | */ | ||
1303 | if (sigmask) { | ||
1304 | memcpy(¤t->saved_sigmask, &sigsaved, | ||
1305 | sizeof(sigsaved)); | ||
1306 | set_restore_sigmask(); | ||
1307 | } | ||
1308 | } else if (sigmask) | ||
1309 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | ||
1310 | |||
1311 | return ret; | ||
1312 | } | ||
1313 | |||
1314 | COMPAT_SYSCALL_DEFINE6(pselect6, int, n, compat_ulong_t __user *, inp, | ||
1315 | compat_ulong_t __user *, outp, compat_ulong_t __user *, exp, | ||
1316 | struct compat_timespec __user *, tsp, void __user *, sig) | ||
1317 | { | ||
1318 | compat_size_t sigsetsize = 0; | ||
1319 | compat_uptr_t up = 0; | ||
1320 | |||
1321 | if (sig) { | ||
1322 | if (!access_ok(VERIFY_READ, sig, | ||
1323 | sizeof(compat_uptr_t)+sizeof(compat_size_t)) || | ||
1324 | __get_user(up, (compat_uptr_t __user *)sig) || | ||
1325 | __get_user(sigsetsize, | ||
1326 | (compat_size_t __user *)(sig+sizeof(up)))) | ||
1327 | return -EFAULT; | ||
1328 | } | ||
1329 | return do_compat_pselect(n, inp, outp, exp, tsp, compat_ptr(up), | ||
1330 | sigsetsize); | ||
1331 | } | ||
1332 | |||
1333 | COMPAT_SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, | ||
1334 | unsigned int, nfds, struct compat_timespec __user *, tsp, | ||
1335 | const compat_sigset_t __user *, sigmask, compat_size_t, sigsetsize) | ||
1336 | { | ||
1337 | compat_sigset_t ss32; | ||
1338 | sigset_t ksigmask, sigsaved; | ||
1339 | struct compat_timespec ts; | ||
1340 | struct timespec end_time, *to = NULL; | ||
1341 | int ret; | ||
1342 | |||
1343 | if (tsp) { | ||
1344 | if (copy_from_user(&ts, tsp, sizeof(ts))) | ||
1345 | return -EFAULT; | ||
1346 | |||
1347 | to = &end_time; | ||
1348 | if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec)) | ||
1349 | return -EINVAL; | ||
1350 | } | ||
1351 | |||
1352 | if (sigmask) { | ||
1353 | if (sigsetsize != sizeof(compat_sigset_t)) | ||
1354 | return -EINVAL; | ||
1355 | if (copy_from_user(&ss32, sigmask, sizeof(ss32))) | ||
1356 | return -EFAULT; | ||
1357 | sigset_from_compat(&ksigmask, &ss32); | ||
1358 | |||
1359 | sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP)); | ||
1360 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | ||
1361 | } | ||
1362 | |||
1363 | ret = do_sys_poll(ufds, nfds, to); | ||
1364 | |||
1365 | /* We can restart this syscall, usually */ | ||
1366 | if (ret == -EINTR) { | ||
1367 | /* | ||
1368 | * Don't restore the signal mask yet. Let do_signal() deliver | ||
1369 | * the signal on the way back to userspace, before the signal | ||
1370 | * mask is restored. | ||
1371 | */ | ||
1372 | if (sigmask) { | ||
1373 | memcpy(¤t->saved_sigmask, &sigsaved, | ||
1374 | sizeof(sigsaved)); | ||
1375 | set_restore_sigmask(); | ||
1376 | } | ||
1377 | ret = -ERESTARTNOHAND; | ||
1378 | } else if (sigmask) | ||
1379 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | ||
1380 | |||
1381 | ret = poll_select_copy_remaining(&end_time, tsp, 0, ret); | ||
1382 | |||
1383 | return ret; | ||
1384 | } | ||
1385 | |||
1386 | #ifdef CONFIG_FHANDLE | ||
1387 | /* | ||
1388 | * Exactly like fs/open.c:sys_open_by_handle_at(), except that it | ||
1389 | * doesn't set the O_LARGEFILE flag. | ||
1390 | */ | ||
1391 | COMPAT_SYSCALL_DEFINE3(open_by_handle_at, int, mountdirfd, | ||
1392 | struct file_handle __user *, handle, int, flags) | ||
1393 | { | ||
1394 | return do_handle_open(mountdirfd, handle, flags); | ||
1395 | } | ||
1396 | #endif | ||
diff --git a/fs/fcntl.c b/fs/fcntl.c index be8fbe289087..8bd81c2e89b2 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/pid_namespace.h> | 23 | #include <linux/pid_namespace.h> |
24 | #include <linux/user_namespace.h> | 24 | #include <linux/user_namespace.h> |
25 | #include <linux/shmem_fs.h> | 25 | #include <linux/shmem_fs.h> |
26 | #include <linux/compat.h> | ||
26 | 27 | ||
27 | #include <asm/poll.h> | 28 | #include <asm/poll.h> |
28 | #include <asm/siginfo.h> | 29 | #include <asm/siginfo.h> |
@@ -420,6 +421,162 @@ out: | |||
420 | } | 421 | } |
421 | #endif | 422 | #endif |
422 | 423 | ||
424 | #ifdef CONFIG_COMPAT | ||
425 | static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl) | ||
426 | { | ||
427 | if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) || | ||
428 | __get_user(kfl->l_type, &ufl->l_type) || | ||
429 | __get_user(kfl->l_whence, &ufl->l_whence) || | ||
430 | __get_user(kfl->l_start, &ufl->l_start) || | ||
431 | __get_user(kfl->l_len, &ufl->l_len) || | ||
432 | __get_user(kfl->l_pid, &ufl->l_pid)) | ||
433 | return -EFAULT; | ||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | static int put_compat_flock(struct flock *kfl, struct compat_flock __user *ufl) | ||
438 | { | ||
439 | if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) || | ||
440 | __put_user(kfl->l_type, &ufl->l_type) || | ||
441 | __put_user(kfl->l_whence, &ufl->l_whence) || | ||
442 | __put_user(kfl->l_start, &ufl->l_start) || | ||
443 | __put_user(kfl->l_len, &ufl->l_len) || | ||
444 | __put_user(kfl->l_pid, &ufl->l_pid)) | ||
445 | return -EFAULT; | ||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | #ifndef HAVE_ARCH_GET_COMPAT_FLOCK64 | ||
450 | static int get_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl) | ||
451 | { | ||
452 | if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) || | ||
453 | __get_user(kfl->l_type, &ufl->l_type) || | ||
454 | __get_user(kfl->l_whence, &ufl->l_whence) || | ||
455 | __get_user(kfl->l_start, &ufl->l_start) || | ||
456 | __get_user(kfl->l_len, &ufl->l_len) || | ||
457 | __get_user(kfl->l_pid, &ufl->l_pid)) | ||
458 | return -EFAULT; | ||
459 | return 0; | ||
460 | } | ||
461 | #endif | ||
462 | |||
463 | #ifndef HAVE_ARCH_PUT_COMPAT_FLOCK64 | ||
464 | static int put_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl) | ||
465 | { | ||
466 | if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) || | ||
467 | __put_user(kfl->l_type, &ufl->l_type) || | ||
468 | __put_user(kfl->l_whence, &ufl->l_whence) || | ||
469 | __put_user(kfl->l_start, &ufl->l_start) || | ||
470 | __put_user(kfl->l_len, &ufl->l_len) || | ||
471 | __put_user(kfl->l_pid, &ufl->l_pid)) | ||
472 | return -EFAULT; | ||
473 | return 0; | ||
474 | } | ||
475 | #endif | ||
476 | |||
477 | static unsigned int | ||
478 | convert_fcntl_cmd(unsigned int cmd) | ||
479 | { | ||
480 | switch (cmd) { | ||
481 | case F_GETLK64: | ||
482 | return F_GETLK; | ||
483 | case F_SETLK64: | ||
484 | return F_SETLK; | ||
485 | case F_SETLKW64: | ||
486 | return F_SETLKW; | ||
487 | } | ||
488 | |||
489 | return cmd; | ||
490 | } | ||
491 | |||
492 | COMPAT_SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, | ||
493 | compat_ulong_t, arg) | ||
494 | { | ||
495 | mm_segment_t old_fs; | ||
496 | struct flock f; | ||
497 | long ret; | ||
498 | unsigned int conv_cmd; | ||
499 | |||
500 | switch (cmd) { | ||
501 | case F_GETLK: | ||
502 | case F_SETLK: | ||
503 | case F_SETLKW: | ||
504 | ret = get_compat_flock(&f, compat_ptr(arg)); | ||
505 | if (ret != 0) | ||
506 | break; | ||
507 | old_fs = get_fs(); | ||
508 | set_fs(KERNEL_DS); | ||
509 | ret = sys_fcntl(fd, cmd, (unsigned long)&f); | ||
510 | set_fs(old_fs); | ||
511 | if (cmd == F_GETLK && ret == 0) { | ||
512 | /* GETLK was successful and we need to return the data... | ||
513 | * but it needs to fit in the compat structure. | ||
514 | * l_start shouldn't be too big, unless the original | ||
515 | * start + end is greater than COMPAT_OFF_T_MAX, in which | ||
516 | * case the app was asking for trouble, so we return | ||
517 | * -EOVERFLOW in that case. | ||
518 | * l_len could be too big, in which case we just truncate it, | ||
519 | * and only allow the app to see that part of the conflicting | ||
520 | * lock that might make sense to it anyway | ||
521 | */ | ||
522 | |||
523 | if (f.l_start > COMPAT_OFF_T_MAX) | ||
524 | ret = -EOVERFLOW; | ||
525 | if (f.l_len > COMPAT_OFF_T_MAX) | ||
526 | f.l_len = COMPAT_OFF_T_MAX; | ||
527 | if (ret == 0) | ||
528 | ret = put_compat_flock(&f, compat_ptr(arg)); | ||
529 | } | ||
530 | break; | ||
531 | |||
532 | case F_GETLK64: | ||
533 | case F_SETLK64: | ||
534 | case F_SETLKW64: | ||
535 | case F_OFD_GETLK: | ||
536 | case F_OFD_SETLK: | ||
537 | case F_OFD_SETLKW: | ||
538 | ret = get_compat_flock64(&f, compat_ptr(arg)); | ||
539 | if (ret != 0) | ||
540 | break; | ||
541 | old_fs = get_fs(); | ||
542 | set_fs(KERNEL_DS); | ||
543 | conv_cmd = convert_fcntl_cmd(cmd); | ||
544 | ret = sys_fcntl(fd, conv_cmd, (unsigned long)&f); | ||
545 | set_fs(old_fs); | ||
546 | if ((conv_cmd == F_GETLK || conv_cmd == F_OFD_GETLK) && ret == 0) { | ||
547 | /* need to return lock information - see above for commentary */ | ||
548 | if (f.l_start > COMPAT_LOFF_T_MAX) | ||
549 | ret = -EOVERFLOW; | ||
550 | if (f.l_len > COMPAT_LOFF_T_MAX) | ||
551 | f.l_len = COMPAT_LOFF_T_MAX; | ||
552 | if (ret == 0) | ||
553 | ret = put_compat_flock64(&f, compat_ptr(arg)); | ||
554 | } | ||
555 | break; | ||
556 | |||
557 | default: | ||
558 | ret = sys_fcntl(fd, cmd, arg); | ||
559 | break; | ||
560 | } | ||
561 | return ret; | ||
562 | } | ||
563 | |||
564 | COMPAT_SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, | ||
565 | compat_ulong_t, arg) | ||
566 | { | ||
567 | switch (cmd) { | ||
568 | case F_GETLK64: | ||
569 | case F_SETLK64: | ||
570 | case F_SETLKW64: | ||
571 | case F_OFD_GETLK: | ||
572 | case F_OFD_SETLK: | ||
573 | case F_OFD_SETLKW: | ||
574 | return -EINVAL; | ||
575 | } | ||
576 | return compat_sys_fcntl64(fd, cmd, arg); | ||
577 | } | ||
578 | #endif | ||
579 | |||
423 | /* Table to convert sigio signal codes into poll band bitmaps */ | 580 | /* Table to convert sigio signal codes into poll band bitmaps */ |
424 | 581 | ||
425 | static const long band_table[NSIGPOLL] = { | 582 | static const long band_table[NSIGPOLL] = { |
diff --git a/fs/fhandle.c b/fs/fhandle.c index 5559168d5637..58a61f55e0d0 100644 --- a/fs/fhandle.c +++ b/fs/fhandle.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/fsnotify.h> | 9 | #include <linux/fsnotify.h> |
10 | #include <linux/personality.h> | 10 | #include <linux/personality.h> |
11 | #include <linux/uaccess.h> | 11 | #include <linux/uaccess.h> |
12 | #include <linux/compat.h> | ||
12 | #include "internal.h" | 13 | #include "internal.h" |
13 | #include "mount.h" | 14 | #include "mount.h" |
14 | 15 | ||
@@ -264,3 +265,15 @@ SYSCALL_DEFINE3(open_by_handle_at, int, mountdirfd, | |||
264 | ret = do_handle_open(mountdirfd, handle, flags); | 265 | ret = do_handle_open(mountdirfd, handle, flags); |
265 | return ret; | 266 | return ret; |
266 | } | 267 | } |
268 | |||
269 | #ifdef CONFIG_COMPAT | ||
270 | /* | ||
271 | * Exactly like fs/open.c:sys_open_by_handle_at(), except that it | ||
272 | * doesn't set the O_LARGEFILE flag. | ||
273 | */ | ||
274 | COMPAT_SYSCALL_DEFINE3(open_by_handle_at, int, mountdirfd, | ||
275 | struct file_handle __user *, handle, int, flags) | ||
276 | { | ||
277 | return do_handle_open(mountdirfd, handle, flags); | ||
278 | } | ||
279 | #endif | ||
diff --git a/fs/internal.h b/fs/internal.h index 11c6d89dce9c..076751d90ba2 100644 --- a/fs/internal.h +++ b/fs/internal.h | |||
@@ -108,8 +108,6 @@ extern struct file *do_filp_open(int dfd, struct filename *pathname, | |||
108 | extern struct file *do_file_open_root(struct dentry *, struct vfsmount *, | 108 | extern struct file *do_file_open_root(struct dentry *, struct vfsmount *, |
109 | const char *, const struct open_flags *); | 109 | const char *, const struct open_flags *); |
110 | 110 | ||
111 | extern long do_handle_open(int mountdirfd, | ||
112 | struct file_handle __user *ufh, int open_flag); | ||
113 | extern int open_check_o_direct(struct file *f); | 111 | extern int open_check_o_direct(struct file *f); |
114 | extern int vfs_open(const struct path *, struct file *, const struct cred *); | 112 | extern int vfs_open(const struct path *, struct file *, const struct cred *); |
115 | extern struct file *filp_clone_open(struct file *); | 113 | extern struct file *filp_clone_open(struct file *); |
@@ -1078,6 +1078,26 @@ SYSCALL_DEFINE4(openat, int, dfd, const char __user *, filename, int, flags, | |||
1078 | return do_sys_open(dfd, filename, flags, mode); | 1078 | return do_sys_open(dfd, filename, flags, mode); |
1079 | } | 1079 | } |
1080 | 1080 | ||
1081 | #ifdef CONFIG_COMPAT | ||
1082 | /* | ||
1083 | * Exactly like sys_open(), except that it doesn't set the | ||
1084 | * O_LARGEFILE flag. | ||
1085 | */ | ||
1086 | COMPAT_SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode) | ||
1087 | { | ||
1088 | return do_sys_open(AT_FDCWD, filename, flags, mode); | ||
1089 | } | ||
1090 | |||
1091 | /* | ||
1092 | * Exactly like sys_openat(), except that it doesn't set the | ||
1093 | * O_LARGEFILE flag. | ||
1094 | */ | ||
1095 | COMPAT_SYSCALL_DEFINE4(openat, int, dfd, const char __user *, filename, int, flags, umode_t, mode) | ||
1096 | { | ||
1097 | return do_sys_open(dfd, filename, flags, mode); | ||
1098 | } | ||
1099 | #endif | ||
1100 | |||
1081 | #ifndef __alpha__ | 1101 | #ifndef __alpha__ |
1082 | 1102 | ||
1083 | /* | 1103 | /* |
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 | ||
845 | ssize_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 | |||
914 | out: | ||
915 | return ret; | ||
916 | } | ||
917 | #endif | ||
918 | |||
844 | static ssize_t __do_readv_writev(int type, struct file *file, | 919 | static 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 | { |
diff --git a/fs/readdir.c b/fs/readdir.c index 0e8a7f355f7a..89659549c09d 100644 --- a/fs/readdir.c +++ b/fs/readdir.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/security.h> | 18 | #include <linux/security.h> |
19 | #include <linux/syscalls.h> | 19 | #include <linux/syscalls.h> |
20 | #include <linux/unistd.h> | 20 | #include <linux/unistd.h> |
21 | #include <linux/compat.h> | ||
21 | 22 | ||
22 | #include <linux/uaccess.h> | 23 | #include <linux/uaccess.h> |
23 | 24 | ||
@@ -324,3 +325,167 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd, | |||
324 | fdput_pos(f); | 325 | fdput_pos(f); |
325 | return error; | 326 | return error; |
326 | } | 327 | } |
328 | |||
329 | #ifdef CONFIG_COMPAT | ||
330 | struct compat_old_linux_dirent { | ||
331 | compat_ulong_t d_ino; | ||
332 | compat_ulong_t d_offset; | ||
333 | unsigned short d_namlen; | ||
334 | char d_name[1]; | ||
335 | }; | ||
336 | |||
337 | struct compat_readdir_callback { | ||
338 | struct dir_context ctx; | ||
339 | struct compat_old_linux_dirent __user *dirent; | ||
340 | int result; | ||
341 | }; | ||
342 | |||
343 | static int compat_fillonedir(struct dir_context *ctx, const char *name, | ||
344 | int namlen, loff_t offset, u64 ino, | ||
345 | unsigned int d_type) | ||
346 | { | ||
347 | struct compat_readdir_callback *buf = | ||
348 | container_of(ctx, struct compat_readdir_callback, ctx); | ||
349 | struct compat_old_linux_dirent __user *dirent; | ||
350 | compat_ulong_t d_ino; | ||
351 | |||
352 | if (buf->result) | ||
353 | return -EINVAL; | ||
354 | d_ino = ino; | ||
355 | if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { | ||
356 | buf->result = -EOVERFLOW; | ||
357 | return -EOVERFLOW; | ||
358 | } | ||
359 | buf->result++; | ||
360 | dirent = buf->dirent; | ||
361 | if (!access_ok(VERIFY_WRITE, dirent, | ||
362 | (unsigned long)(dirent->d_name + namlen + 1) - | ||
363 | (unsigned long)dirent)) | ||
364 | goto efault; | ||
365 | if ( __put_user(d_ino, &dirent->d_ino) || | ||
366 | __put_user(offset, &dirent->d_offset) || | ||
367 | __put_user(namlen, &dirent->d_namlen) || | ||
368 | __copy_to_user(dirent->d_name, name, namlen) || | ||
369 | __put_user(0, dirent->d_name + namlen)) | ||
370 | goto efault; | ||
371 | return 0; | ||
372 | efault: | ||
373 | buf->result = -EFAULT; | ||
374 | return -EFAULT; | ||
375 | } | ||
376 | |||
377 | COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd, | ||
378 | struct compat_old_linux_dirent __user *, dirent, unsigned int, count) | ||
379 | { | ||
380 | int error; | ||
381 | struct fd f = fdget_pos(fd); | ||
382 | struct compat_readdir_callback buf = { | ||
383 | .ctx.actor = compat_fillonedir, | ||
384 | .dirent = dirent | ||
385 | }; | ||
386 | |||
387 | if (!f.file) | ||
388 | return -EBADF; | ||
389 | |||
390 | error = iterate_dir(f.file, &buf.ctx); | ||
391 | if (buf.result) | ||
392 | error = buf.result; | ||
393 | |||
394 | fdput_pos(f); | ||
395 | return error; | ||
396 | } | ||
397 | |||
398 | struct compat_linux_dirent { | ||
399 | compat_ulong_t d_ino; | ||
400 | compat_ulong_t d_off; | ||
401 | unsigned short d_reclen; | ||
402 | char d_name[1]; | ||
403 | }; | ||
404 | |||
405 | struct compat_getdents_callback { | ||
406 | struct dir_context ctx; | ||
407 | struct compat_linux_dirent __user *current_dir; | ||
408 | struct compat_linux_dirent __user *previous; | ||
409 | int count; | ||
410 | int error; | ||
411 | }; | ||
412 | |||
413 | static int compat_filldir(struct dir_context *ctx, const char *name, int namlen, | ||
414 | loff_t offset, u64 ino, unsigned int d_type) | ||
415 | { | ||
416 | struct compat_linux_dirent __user * dirent; | ||
417 | struct compat_getdents_callback *buf = | ||
418 | container_of(ctx, struct compat_getdents_callback, ctx); | ||
419 | compat_ulong_t d_ino; | ||
420 | int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) + | ||
421 | namlen + 2, sizeof(compat_long_t)); | ||
422 | |||
423 | buf->error = -EINVAL; /* only used if we fail.. */ | ||
424 | if (reclen > buf->count) | ||
425 | return -EINVAL; | ||
426 | d_ino = ino; | ||
427 | if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { | ||
428 | buf->error = -EOVERFLOW; | ||
429 | return -EOVERFLOW; | ||
430 | } | ||
431 | dirent = buf->previous; | ||
432 | if (dirent) { | ||
433 | if (signal_pending(current)) | ||
434 | return -EINTR; | ||
435 | if (__put_user(offset, &dirent->d_off)) | ||
436 | goto efault; | ||
437 | } | ||
438 | dirent = buf->current_dir; | ||
439 | if (__put_user(d_ino, &dirent->d_ino)) | ||
440 | goto efault; | ||
441 | if (__put_user(reclen, &dirent->d_reclen)) | ||
442 | goto efault; | ||
443 | if (copy_to_user(dirent->d_name, name, namlen)) | ||
444 | goto efault; | ||
445 | if (__put_user(0, dirent->d_name + namlen)) | ||
446 | goto efault; | ||
447 | if (__put_user(d_type, (char __user *) dirent + reclen - 1)) | ||
448 | goto efault; | ||
449 | buf->previous = dirent; | ||
450 | dirent = (void __user *)dirent + reclen; | ||
451 | buf->current_dir = dirent; | ||
452 | buf->count -= reclen; | ||
453 | return 0; | ||
454 | efault: | ||
455 | buf->error = -EFAULT; | ||
456 | return -EFAULT; | ||
457 | } | ||
458 | |||
459 | COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd, | ||
460 | struct compat_linux_dirent __user *, dirent, unsigned int, count) | ||
461 | { | ||
462 | struct fd f; | ||
463 | struct compat_linux_dirent __user * lastdirent; | ||
464 | struct compat_getdents_callback buf = { | ||
465 | .ctx.actor = compat_filldir, | ||
466 | .current_dir = dirent, | ||
467 | .count = count | ||
468 | }; | ||
469 | int error; | ||
470 | |||
471 | if (!access_ok(VERIFY_WRITE, dirent, count)) | ||
472 | return -EFAULT; | ||
473 | |||
474 | f = fdget_pos(fd); | ||
475 | if (!f.file) | ||
476 | return -EBADF; | ||
477 | |||
478 | error = iterate_dir(f.file, &buf.ctx); | ||
479 | if (error >= 0) | ||
480 | error = buf.error; | ||
481 | lastdirent = buf.previous; | ||
482 | if (lastdirent) { | ||
483 | if (put_user(buf.ctx.pos, &lastdirent->d_off)) | ||
484 | error = -EFAULT; | ||
485 | else | ||
486 | error = count - buf.count; | ||
487 | } | ||
488 | fdput_pos(f); | ||
489 | return error; | ||
490 | } | ||
491 | #endif | ||
diff --git a/fs/select.c b/fs/select.c index e2112270d75a..dd70937ddb60 100644 --- a/fs/select.c +++ b/fs/select.c | |||
@@ -338,6 +338,53 @@ sticky: | |||
338 | return ret; | 338 | return ret; |
339 | } | 339 | } |
340 | 340 | ||
341 | /* | ||
342 | * Scalable version of the fd_set. | ||
343 | */ | ||
344 | |||
345 | typedef struct { | ||
346 | unsigned long *in, *out, *ex; | ||
347 | unsigned long *res_in, *res_out, *res_ex; | ||
348 | } fd_set_bits; | ||
349 | |||
350 | /* | ||
351 | * How many longwords for "nr" bits? | ||
352 | */ | ||
353 | #define FDS_BITPERLONG (8*sizeof(long)) | ||
354 | #define FDS_LONGS(nr) (((nr)+FDS_BITPERLONG-1)/FDS_BITPERLONG) | ||
355 | #define FDS_BYTES(nr) (FDS_LONGS(nr)*sizeof(long)) | ||
356 | |||
357 | /* | ||
358 | * We do a VERIFY_WRITE here even though we are only reading this time: | ||
359 | * we'll write to it eventually.. | ||
360 | * | ||
361 | * Use "unsigned long" accesses to let user-mode fd_set's be long-aligned. | ||
362 | */ | ||
363 | static inline | ||
364 | int get_fd_set(unsigned long nr, void __user *ufdset, unsigned long *fdset) | ||
365 | { | ||
366 | nr = FDS_BYTES(nr); | ||
367 | if (ufdset) | ||
368 | return copy_from_user(fdset, ufdset, nr) ? -EFAULT : 0; | ||
369 | |||
370 | memset(fdset, 0, nr); | ||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | static inline unsigned long __must_check | ||
375 | set_fd_set(unsigned long nr, void __user *ufdset, unsigned long *fdset) | ||
376 | { | ||
377 | if (ufdset) | ||
378 | return __copy_to_user(ufdset, fdset, FDS_BYTES(nr)); | ||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | static inline | ||
383 | void zero_fd_set(unsigned long nr, unsigned long *fdset) | ||
384 | { | ||
385 | memset(fdset, 0, FDS_BYTES(nr)); | ||
386 | } | ||
387 | |||
341 | #define FDS_IN(fds, n) (fds->in + n) | 388 | #define FDS_IN(fds, n) (fds->in + n) |
342 | #define FDS_OUT(fds, n) (fds->out + n) | 389 | #define FDS_OUT(fds, n) (fds->out + n) |
343 | #define FDS_EX(fds, n) (fds->ex + n) | 390 | #define FDS_EX(fds, n) (fds->ex + n) |
@@ -401,7 +448,7 @@ static inline void wait_key_set(poll_table *wait, unsigned long in, | |||
401 | wait->_key |= POLLOUT_SET; | 448 | wait->_key |= POLLOUT_SET; |
402 | } | 449 | } |
403 | 450 | ||
404 | int do_select(int n, fd_set_bits *fds, struct timespec64 *end_time) | 451 | static int do_select(int n, fd_set_bits *fds, struct timespec64 *end_time) |
405 | { | 452 | { |
406 | ktime_t expire, *to = NULL; | 453 | ktime_t expire, *to = NULL; |
407 | struct poll_wqueues table; | 454 | struct poll_wqueues table; |
@@ -881,7 +928,7 @@ static int do_poll(struct poll_list *list, struct poll_wqueues *wait, | |||
881 | #define N_STACK_PPS ((sizeof(stack_pps) - sizeof(struct poll_list)) / \ | 928 | #define N_STACK_PPS ((sizeof(stack_pps) - sizeof(struct poll_list)) / \ |
882 | sizeof(struct pollfd)) | 929 | sizeof(struct pollfd)) |
883 | 930 | ||
884 | int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, | 931 | static int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, |
885 | struct timespec64 *end_time) | 932 | struct timespec64 *end_time) |
886 | { | 933 | { |
887 | struct poll_wqueues table; | 934 | struct poll_wqueues table; |
@@ -1053,3 +1100,373 @@ SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, unsigned int, nfds, | |||
1053 | 1100 | ||
1054 | return ret; | 1101 | return ret; |
1055 | } | 1102 | } |
1103 | |||
1104 | #ifdef CONFIG_COMPAT | ||
1105 | #define __COMPAT_NFDBITS (8 * sizeof(compat_ulong_t)) | ||
1106 | |||
1107 | static | ||
1108 | int compat_poll_select_copy_remaining(struct timespec *end_time, void __user *p, | ||
1109 | int timeval, int ret) | ||
1110 | { | ||
1111 | struct timespec ts; | ||
1112 | |||
1113 | if (!p) | ||
1114 | return ret; | ||
1115 | |||
1116 | if (current->personality & STICKY_TIMEOUTS) | ||
1117 | goto sticky; | ||
1118 | |||
1119 | /* No update for zero timeout */ | ||
1120 | if (!end_time->tv_sec && !end_time->tv_nsec) | ||
1121 | return ret; | ||
1122 | |||
1123 | ktime_get_ts(&ts); | ||
1124 | ts = timespec_sub(*end_time, ts); | ||
1125 | if (ts.tv_sec < 0) | ||
1126 | ts.tv_sec = ts.tv_nsec = 0; | ||
1127 | |||
1128 | if (timeval) { | ||
1129 | struct compat_timeval rtv; | ||
1130 | |||
1131 | rtv.tv_sec = ts.tv_sec; | ||
1132 | rtv.tv_usec = ts.tv_nsec / NSEC_PER_USEC; | ||
1133 | |||
1134 | if (!copy_to_user(p, &rtv, sizeof(rtv))) | ||
1135 | return ret; | ||
1136 | } else { | ||
1137 | struct compat_timespec rts; | ||
1138 | |||
1139 | rts.tv_sec = ts.tv_sec; | ||
1140 | rts.tv_nsec = ts.tv_nsec; | ||
1141 | |||
1142 | if (!copy_to_user(p, &rts, sizeof(rts))) | ||
1143 | return ret; | ||
1144 | } | ||
1145 | /* | ||
1146 | * If an application puts its timeval in read-only memory, we | ||
1147 | * don't want the Linux-specific update to the timeval to | ||
1148 | * cause a fault after the select has completed | ||
1149 | * successfully. However, because we're not updating the | ||
1150 | * timeval, we can't restart the system call. | ||
1151 | */ | ||
1152 | |||
1153 | sticky: | ||
1154 | if (ret == -ERESTARTNOHAND) | ||
1155 | ret = -EINTR; | ||
1156 | return ret; | ||
1157 | } | ||
1158 | |||
1159 | /* | ||
1160 | * Ooo, nasty. We need here to frob 32-bit unsigned longs to | ||
1161 | * 64-bit unsigned longs. | ||
1162 | */ | ||
1163 | static | ||
1164 | int compat_get_fd_set(unsigned long nr, compat_ulong_t __user *ufdset, | ||
1165 | unsigned long *fdset) | ||
1166 | { | ||
1167 | nr = DIV_ROUND_UP(nr, __COMPAT_NFDBITS); | ||
1168 | if (ufdset) { | ||
1169 | unsigned long odd; | ||
1170 | |||
1171 | if (!access_ok(VERIFY_WRITE, ufdset, nr*sizeof(compat_ulong_t))) | ||
1172 | return -EFAULT; | ||
1173 | |||
1174 | odd = nr & 1UL; | ||
1175 | nr &= ~1UL; | ||
1176 | while (nr) { | ||
1177 | unsigned long h, l; | ||
1178 | if (__get_user(l, ufdset) || __get_user(h, ufdset+1)) | ||
1179 | return -EFAULT; | ||
1180 | ufdset += 2; | ||
1181 | *fdset++ = h << 32 | l; | ||
1182 | nr -= 2; | ||
1183 | } | ||
1184 | if (odd && __get_user(*fdset, ufdset)) | ||
1185 | return -EFAULT; | ||
1186 | } else { | ||
1187 | /* Tricky, must clear full unsigned long in the | ||
1188 | * kernel fdset at the end, this makes sure that | ||
1189 | * actually happens. | ||
1190 | */ | ||
1191 | memset(fdset, 0, ((nr + 1) & ~1)*sizeof(compat_ulong_t)); | ||
1192 | } | ||
1193 | return 0; | ||
1194 | } | ||
1195 | |||
1196 | static | ||
1197 | int compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset, | ||
1198 | unsigned long *fdset) | ||
1199 | { | ||
1200 | unsigned long odd; | ||
1201 | nr = DIV_ROUND_UP(nr, __COMPAT_NFDBITS); | ||
1202 | |||
1203 | if (!ufdset) | ||
1204 | return 0; | ||
1205 | |||
1206 | odd = nr & 1UL; | ||
1207 | nr &= ~1UL; | ||
1208 | while (nr) { | ||
1209 | unsigned long h, l; | ||
1210 | l = *fdset++; | ||
1211 | h = l >> 32; | ||
1212 | if (__put_user(l, ufdset) || __put_user(h, ufdset+1)) | ||
1213 | return -EFAULT; | ||
1214 | ufdset += 2; | ||
1215 | nr -= 2; | ||
1216 | } | ||
1217 | if (odd && __put_user(*fdset, ufdset)) | ||
1218 | return -EFAULT; | ||
1219 | return 0; | ||
1220 | } | ||
1221 | |||
1222 | |||
1223 | /* | ||
1224 | * This is a virtual copy of sys_select from fs/select.c and probably | ||
1225 | * should be compared to it from time to time | ||
1226 | */ | ||
1227 | |||
1228 | /* | ||
1229 | * We can actually return ERESTARTSYS instead of EINTR, but I'd | ||
1230 | * like to be certain this leads to no problems. So I return | ||
1231 | * EINTR just for safety. | ||
1232 | * | ||
1233 | * Update: ERESTARTSYS breaks at least the xview clock binary, so | ||
1234 | * I'm trying ERESTARTNOHAND which restart only when you want to. | ||
1235 | */ | ||
1236 | static int compat_core_sys_select(int n, compat_ulong_t __user *inp, | ||
1237 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, | ||
1238 | struct timespec *end_time) | ||
1239 | { | ||
1240 | fd_set_bits fds; | ||
1241 | void *bits; | ||
1242 | int size, max_fds, ret = -EINVAL; | ||
1243 | struct fdtable *fdt; | ||
1244 | long stack_fds[SELECT_STACK_ALLOC/sizeof(long)]; | ||
1245 | |||
1246 | if (n < 0) | ||
1247 | goto out_nofds; | ||
1248 | |||
1249 | /* max_fds can increase, so grab it once to avoid race */ | ||
1250 | rcu_read_lock(); | ||
1251 | fdt = files_fdtable(current->files); | ||
1252 | max_fds = fdt->max_fds; | ||
1253 | rcu_read_unlock(); | ||
1254 | if (n > max_fds) | ||
1255 | n = max_fds; | ||
1256 | |||
1257 | /* | ||
1258 | * We need 6 bitmaps (in/out/ex for both incoming and outgoing), | ||
1259 | * since we used fdset we need to allocate memory in units of | ||
1260 | * long-words. | ||
1261 | */ | ||
1262 | size = FDS_BYTES(n); | ||
1263 | bits = stack_fds; | ||
1264 | if (size > sizeof(stack_fds) / 6) { | ||
1265 | bits = kmalloc(6 * size, GFP_KERNEL); | ||
1266 | ret = -ENOMEM; | ||
1267 | if (!bits) | ||
1268 | goto out_nofds; | ||
1269 | } | ||
1270 | fds.in = (unsigned long *) bits; | ||
1271 | fds.out = (unsigned long *) (bits + size); | ||
1272 | fds.ex = (unsigned long *) (bits + 2*size); | ||
1273 | fds.res_in = (unsigned long *) (bits + 3*size); | ||
1274 | fds.res_out = (unsigned long *) (bits + 4*size); | ||
1275 | fds.res_ex = (unsigned long *) (bits + 5*size); | ||
1276 | |||
1277 | if ((ret = compat_get_fd_set(n, inp, fds.in)) || | ||
1278 | (ret = compat_get_fd_set(n, outp, fds.out)) || | ||
1279 | (ret = compat_get_fd_set(n, exp, fds.ex))) | ||
1280 | goto out; | ||
1281 | zero_fd_set(n, fds.res_in); | ||
1282 | zero_fd_set(n, fds.res_out); | ||
1283 | zero_fd_set(n, fds.res_ex); | ||
1284 | |||
1285 | ret = do_select(n, &fds, end_time); | ||
1286 | |||
1287 | if (ret < 0) | ||
1288 | goto out; | ||
1289 | if (!ret) { | ||
1290 | ret = -ERESTARTNOHAND; | ||
1291 | if (signal_pending(current)) | ||
1292 | goto out; | ||
1293 | ret = 0; | ||
1294 | } | ||
1295 | |||
1296 | if (compat_set_fd_set(n, inp, fds.res_in) || | ||
1297 | compat_set_fd_set(n, outp, fds.res_out) || | ||
1298 | compat_set_fd_set(n, exp, fds.res_ex)) | ||
1299 | ret = -EFAULT; | ||
1300 | out: | ||
1301 | if (bits != stack_fds) | ||
1302 | kfree(bits); | ||
1303 | out_nofds: | ||
1304 | return ret; | ||
1305 | } | ||
1306 | |||
1307 | COMPAT_SYSCALL_DEFINE5(select, int, n, compat_ulong_t __user *, inp, | ||
1308 | compat_ulong_t __user *, outp, compat_ulong_t __user *, exp, | ||
1309 | struct compat_timeval __user *, tvp) | ||
1310 | { | ||
1311 | struct timespec end_time, *to = NULL; | ||
1312 | struct compat_timeval tv; | ||
1313 | int ret; | ||
1314 | |||
1315 | if (tvp) { | ||
1316 | if (copy_from_user(&tv, tvp, sizeof(tv))) | ||
1317 | return -EFAULT; | ||
1318 | |||
1319 | to = &end_time; | ||
1320 | if (poll_select_set_timeout(to, | ||
1321 | tv.tv_sec + (tv.tv_usec / USEC_PER_SEC), | ||
1322 | (tv.tv_usec % USEC_PER_SEC) * NSEC_PER_USEC)) | ||
1323 | return -EINVAL; | ||
1324 | } | ||
1325 | |||
1326 | ret = compat_core_sys_select(n, inp, outp, exp, to); | ||
1327 | ret = compat_poll_select_copy_remaining(&end_time, tvp, 1, ret); | ||
1328 | |||
1329 | return ret; | ||
1330 | } | ||
1331 | |||
1332 | struct compat_sel_arg_struct { | ||
1333 | compat_ulong_t n; | ||
1334 | compat_uptr_t inp; | ||
1335 | compat_uptr_t outp; | ||
1336 | compat_uptr_t exp; | ||
1337 | compat_uptr_t tvp; | ||
1338 | }; | ||
1339 | |||
1340 | COMPAT_SYSCALL_DEFINE1(old_select, struct compat_sel_arg_struct __user *, arg) | ||
1341 | { | ||
1342 | struct compat_sel_arg_struct a; | ||
1343 | |||
1344 | if (copy_from_user(&a, arg, sizeof(a))) | ||
1345 | return -EFAULT; | ||
1346 | return compat_sys_select(a.n, compat_ptr(a.inp), compat_ptr(a.outp), | ||
1347 | compat_ptr(a.exp), compat_ptr(a.tvp)); | ||
1348 | } | ||
1349 | |||
1350 | static long do_compat_pselect(int n, compat_ulong_t __user *inp, | ||
1351 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, | ||
1352 | struct compat_timespec __user *tsp, compat_sigset_t __user *sigmask, | ||
1353 | compat_size_t sigsetsize) | ||
1354 | { | ||
1355 | compat_sigset_t ss32; | ||
1356 | sigset_t ksigmask, sigsaved; | ||
1357 | struct compat_timespec ts; | ||
1358 | struct timespec end_time, *to = NULL; | ||
1359 | int ret; | ||
1360 | |||
1361 | if (tsp) { | ||
1362 | if (copy_from_user(&ts, tsp, sizeof(ts))) | ||
1363 | return -EFAULT; | ||
1364 | |||
1365 | to = &end_time; | ||
1366 | if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec)) | ||
1367 | return -EINVAL; | ||
1368 | } | ||
1369 | |||
1370 | if (sigmask) { | ||
1371 | if (sigsetsize != sizeof(compat_sigset_t)) | ||
1372 | return -EINVAL; | ||
1373 | if (copy_from_user(&ss32, sigmask, sizeof(ss32))) | ||
1374 | return -EFAULT; | ||
1375 | sigset_from_compat(&ksigmask, &ss32); | ||
1376 | |||
1377 | sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP)); | ||
1378 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | ||
1379 | } | ||
1380 | |||
1381 | ret = compat_core_sys_select(n, inp, outp, exp, to); | ||
1382 | ret = compat_poll_select_copy_remaining(&end_time, tsp, 0, ret); | ||
1383 | |||
1384 | if (ret == -ERESTARTNOHAND) { | ||
1385 | /* | ||
1386 | * Don't restore the signal mask yet. Let do_signal() deliver | ||
1387 | * the signal on the way back to userspace, before the signal | ||
1388 | * mask is restored. | ||
1389 | */ | ||
1390 | if (sigmask) { | ||
1391 | memcpy(¤t->saved_sigmask, &sigsaved, | ||
1392 | sizeof(sigsaved)); | ||
1393 | set_restore_sigmask(); | ||
1394 | } | ||
1395 | } else if (sigmask) | ||
1396 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | ||
1397 | |||
1398 | return ret; | ||
1399 | } | ||
1400 | |||
1401 | COMPAT_SYSCALL_DEFINE6(pselect6, int, n, compat_ulong_t __user *, inp, | ||
1402 | compat_ulong_t __user *, outp, compat_ulong_t __user *, exp, | ||
1403 | struct compat_timespec __user *, tsp, void __user *, sig) | ||
1404 | { | ||
1405 | compat_size_t sigsetsize = 0; | ||
1406 | compat_uptr_t up = 0; | ||
1407 | |||
1408 | if (sig) { | ||
1409 | if (!access_ok(VERIFY_READ, sig, | ||
1410 | sizeof(compat_uptr_t)+sizeof(compat_size_t)) || | ||
1411 | __get_user(up, (compat_uptr_t __user *)sig) || | ||
1412 | __get_user(sigsetsize, | ||
1413 | (compat_size_t __user *)(sig+sizeof(up)))) | ||
1414 | return -EFAULT; | ||
1415 | } | ||
1416 | return do_compat_pselect(n, inp, outp, exp, tsp, compat_ptr(up), | ||
1417 | sigsetsize); | ||
1418 | } | ||
1419 | |||
1420 | COMPAT_SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, | ||
1421 | unsigned int, nfds, struct compat_timespec __user *, tsp, | ||
1422 | const compat_sigset_t __user *, sigmask, compat_size_t, sigsetsize) | ||
1423 | { | ||
1424 | compat_sigset_t ss32; | ||
1425 | sigset_t ksigmask, sigsaved; | ||
1426 | struct compat_timespec ts; | ||
1427 | struct timespec end_time, *to = NULL; | ||
1428 | int ret; | ||
1429 | |||
1430 | if (tsp) { | ||
1431 | if (copy_from_user(&ts, tsp, sizeof(ts))) | ||
1432 | return -EFAULT; | ||
1433 | |||
1434 | to = &end_time; | ||
1435 | if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec)) | ||
1436 | return -EINVAL; | ||
1437 | } | ||
1438 | |||
1439 | if (sigmask) { | ||
1440 | if (sigsetsize != sizeof(compat_sigset_t)) | ||
1441 | return -EINVAL; | ||
1442 | if (copy_from_user(&ss32, sigmask, sizeof(ss32))) | ||
1443 | return -EFAULT; | ||
1444 | sigset_from_compat(&ksigmask, &ss32); | ||
1445 | |||
1446 | sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP)); | ||
1447 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | ||
1448 | } | ||
1449 | |||
1450 | ret = do_sys_poll(ufds, nfds, to); | ||
1451 | |||
1452 | /* We can restart this syscall, usually */ | ||
1453 | if (ret == -EINTR) { | ||
1454 | /* | ||
1455 | * Don't restore the signal mask yet. Let do_signal() deliver | ||
1456 | * the signal on the way back to userspace, before the signal | ||
1457 | * mask is restored. | ||
1458 | */ | ||
1459 | if (sigmask) { | ||
1460 | memcpy(¤t->saved_sigmask, &sigsaved, | ||
1461 | sizeof(sigsaved)); | ||
1462 | set_restore_sigmask(); | ||
1463 | } | ||
1464 | ret = -ERESTARTNOHAND; | ||
1465 | } else if (sigmask) | ||
1466 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | ||
1467 | |||
1468 | ret = compat_poll_select_copy_remaining(&end_time, tsp, 0, ret); | ||
1469 | |||
1470 | return ret; | ||
1471 | } | ||
1472 | #endif | ||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/cred.h> | 15 | #include <linux/cred.h> |
16 | #include <linux/syscalls.h> | 16 | #include <linux/syscalls.h> |
17 | #include <linux/pagemap.h> | 17 | #include <linux/pagemap.h> |
18 | #include <linux/compat.h> | ||
18 | 19 | ||
19 | #include <linux/uaccess.h> | 20 | #include <linux/uaccess.h> |
20 | #include <asm/unistd.h> | 21 | #include <asm/unistd.h> |
@@ -575,6 +576,91 @@ SYSCALL_DEFINE5(statx, | |||
575 | return cp_statx(&stat, buffer); | 576 | return cp_statx(&stat, buffer); |
576 | } | 577 | } |
577 | 578 | ||
579 | #ifdef CONFIG_COMPAT | ||
580 | static int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf) | ||
581 | { | ||
582 | struct compat_stat tmp; | ||
583 | |||
584 | if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev)) | ||
585 | return -EOVERFLOW; | ||
586 | |||
587 | memset(&tmp, 0, sizeof(tmp)); | ||
588 | tmp.st_dev = old_encode_dev(stat->dev); | ||
589 | tmp.st_ino = stat->ino; | ||
590 | if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) | ||
591 | return -EOVERFLOW; | ||
592 | tmp.st_mode = stat->mode; | ||
593 | tmp.st_nlink = stat->nlink; | ||
594 | if (tmp.st_nlink != stat->nlink) | ||
595 | return -EOVERFLOW; | ||
596 | SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid)); | ||
597 | SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid)); | ||
598 | tmp.st_rdev = old_encode_dev(stat->rdev); | ||
599 | if ((u64) stat->size > MAX_NON_LFS) | ||
600 | return -EOVERFLOW; | ||
601 | tmp.st_size = stat->size; | ||
602 | tmp.st_atime = stat->atime.tv_sec; | ||
603 | tmp.st_atime_nsec = stat->atime.tv_nsec; | ||
604 | tmp.st_mtime = stat->mtime.tv_sec; | ||
605 | tmp.st_mtime_nsec = stat->mtime.tv_nsec; | ||
606 | tmp.st_ctime = stat->ctime.tv_sec; | ||
607 | tmp.st_ctime_nsec = stat->ctime.tv_nsec; | ||
608 | tmp.st_blocks = stat->blocks; | ||
609 | tmp.st_blksize = stat->blksize; | ||
610 | return copy_to_user(ubuf, &tmp, sizeof(tmp)) ? -EFAULT : 0; | ||
611 | } | ||
612 | |||
613 | COMPAT_SYSCALL_DEFINE2(newstat, const char __user *, filename, | ||
614 | struct compat_stat __user *, statbuf) | ||
615 | { | ||
616 | struct kstat stat; | ||
617 | int error; | ||
618 | |||
619 | error = vfs_stat(filename, &stat); | ||
620 | if (error) | ||
621 | return error; | ||
622 | return cp_compat_stat(&stat, statbuf); | ||
623 | } | ||
624 | |||
625 | COMPAT_SYSCALL_DEFINE2(newlstat, const char __user *, filename, | ||
626 | struct compat_stat __user *, statbuf) | ||
627 | { | ||
628 | struct kstat stat; | ||
629 | int error; | ||
630 | |||
631 | error = vfs_lstat(filename, &stat); | ||
632 | if (error) | ||
633 | return error; | ||
634 | return cp_compat_stat(&stat, statbuf); | ||
635 | } | ||
636 | |||
637 | #ifndef __ARCH_WANT_STAT64 | ||
638 | COMPAT_SYSCALL_DEFINE4(newfstatat, unsigned int, dfd, | ||
639 | const char __user *, filename, | ||
640 | struct compat_stat __user *, statbuf, int, flag) | ||
641 | { | ||
642 | struct kstat stat; | ||
643 | int error; | ||
644 | |||
645 | error = vfs_fstatat(dfd, filename, &stat, flag); | ||
646 | if (error) | ||
647 | return error; | ||
648 | return cp_compat_stat(&stat, statbuf); | ||
649 | } | ||
650 | #endif | ||
651 | |||
652 | COMPAT_SYSCALL_DEFINE2(newfstat, unsigned int, fd, | ||
653 | struct compat_stat __user *, statbuf) | ||
654 | { | ||
655 | struct kstat stat; | ||
656 | int error = vfs_fstat(fd, &stat); | ||
657 | |||
658 | if (!error) | ||
659 | error = cp_compat_stat(&stat, statbuf); | ||
660 | return error; | ||
661 | } | ||
662 | #endif | ||
663 | |||
578 | /* Caller is here responsible for sufficient locking (ie. inode->i_lock) */ | 664 | /* Caller is here responsible for sufficient locking (ie. inode->i_lock) */ |
579 | void __inode_add_bytes(struct inode *inode, loff_t bytes) | 665 | void __inode_add_bytes(struct inode *inode, loff_t bytes) |
580 | { | 666 | { |
diff --git a/fs/statfs.c b/fs/statfs.c index 13ae259d4879..4e4623c7a126 100644 --- a/fs/statfs.c +++ b/fs/statfs.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <linux/statfs.h> | 7 | #include <linux/statfs.h> |
8 | #include <linux/security.h> | 8 | #include <linux/security.h> |
9 | #include <linux/uaccess.h> | 9 | #include <linux/uaccess.h> |
10 | #include <linux/compat.h> | ||
10 | #include "internal.h" | 11 | #include "internal.h" |
11 | 12 | ||
12 | static int flags_by_mnt(int mnt_flags) | 13 | static int flags_by_mnt(int mnt_flags) |
@@ -239,3 +240,142 @@ SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf) | |||
239 | 240 | ||
240 | return copy_to_user(ubuf, &tmp, sizeof(struct ustat)) ? -EFAULT : 0; | 241 | return copy_to_user(ubuf, &tmp, sizeof(struct ustat)) ? -EFAULT : 0; |
241 | } | 242 | } |
243 | |||
244 | #ifdef CONFIG_COMPAT | ||
245 | static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *kbuf) | ||
246 | { | ||
247 | if (sizeof ubuf->f_blocks == 4) { | ||
248 | if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail | | ||
249 | kbuf->f_bsize | kbuf->f_frsize) & 0xffffffff00000000ULL) | ||
250 | return -EOVERFLOW; | ||
251 | /* f_files and f_ffree may be -1; it's okay | ||
252 | * to stuff that into 32 bits */ | ||
253 | if (kbuf->f_files != 0xffffffffffffffffULL | ||
254 | && (kbuf->f_files & 0xffffffff00000000ULL)) | ||
255 | return -EOVERFLOW; | ||
256 | if (kbuf->f_ffree != 0xffffffffffffffffULL | ||
257 | && (kbuf->f_ffree & 0xffffffff00000000ULL)) | ||
258 | return -EOVERFLOW; | ||
259 | } | ||
260 | if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)) || | ||
261 | __put_user(kbuf->f_type, &ubuf->f_type) || | ||
262 | __put_user(kbuf->f_bsize, &ubuf->f_bsize) || | ||
263 | __put_user(kbuf->f_blocks, &ubuf->f_blocks) || | ||
264 | __put_user(kbuf->f_bfree, &ubuf->f_bfree) || | ||
265 | __put_user(kbuf->f_bavail, &ubuf->f_bavail) || | ||
266 | __put_user(kbuf->f_files, &ubuf->f_files) || | ||
267 | __put_user(kbuf->f_ffree, &ubuf->f_ffree) || | ||
268 | __put_user(kbuf->f_namelen, &ubuf->f_namelen) || | ||
269 | __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) || | ||
270 | __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) || | ||
271 | __put_user(kbuf->f_frsize, &ubuf->f_frsize) || | ||
272 | __put_user(kbuf->f_flags, &ubuf->f_flags) || | ||
273 | __clear_user(ubuf->f_spare, sizeof(ubuf->f_spare))) | ||
274 | return -EFAULT; | ||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | /* | ||
279 | * The following statfs calls are copies of code from fs/statfs.c and | ||
280 | * should be checked against those from time to time | ||
281 | */ | ||
282 | COMPAT_SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct compat_statfs __user *, buf) | ||
283 | { | ||
284 | struct kstatfs tmp; | ||
285 | int error = user_statfs(pathname, &tmp); | ||
286 | if (!error) | ||
287 | error = put_compat_statfs(buf, &tmp); | ||
288 | return error; | ||
289 | } | ||
290 | |||
291 | COMPAT_SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct compat_statfs __user *, buf) | ||
292 | { | ||
293 | struct kstatfs tmp; | ||
294 | int error = fd_statfs(fd, &tmp); | ||
295 | if (!error) | ||
296 | error = put_compat_statfs(buf, &tmp); | ||
297 | return error; | ||
298 | } | ||
299 | |||
300 | static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstatfs *kbuf) | ||
301 | { | ||
302 | if (sizeof(ubuf->f_bsize) == 4) { | ||
303 | if ((kbuf->f_type | kbuf->f_bsize | kbuf->f_namelen | | ||
304 | kbuf->f_frsize | kbuf->f_flags) & 0xffffffff00000000ULL) | ||
305 | return -EOVERFLOW; | ||
306 | /* f_files and f_ffree may be -1; it's okay | ||
307 | * to stuff that into 32 bits */ | ||
308 | if (kbuf->f_files != 0xffffffffffffffffULL | ||
309 | && (kbuf->f_files & 0xffffffff00000000ULL)) | ||
310 | return -EOVERFLOW; | ||
311 | if (kbuf->f_ffree != 0xffffffffffffffffULL | ||
312 | && (kbuf->f_ffree & 0xffffffff00000000ULL)) | ||
313 | return -EOVERFLOW; | ||
314 | } | ||
315 | if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)) || | ||
316 | __put_user(kbuf->f_type, &ubuf->f_type) || | ||
317 | __put_user(kbuf->f_bsize, &ubuf->f_bsize) || | ||
318 | __put_user(kbuf->f_blocks, &ubuf->f_blocks) || | ||
319 | __put_user(kbuf->f_bfree, &ubuf->f_bfree) || | ||
320 | __put_user(kbuf->f_bavail, &ubuf->f_bavail) || | ||
321 | __put_user(kbuf->f_files, &ubuf->f_files) || | ||
322 | __put_user(kbuf->f_ffree, &ubuf->f_ffree) || | ||
323 | __put_user(kbuf->f_namelen, &ubuf->f_namelen) || | ||
324 | __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) || | ||
325 | __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) || | ||
326 | __put_user(kbuf->f_frsize, &ubuf->f_frsize) || | ||
327 | __put_user(kbuf->f_flags, &ubuf->f_flags) || | ||
328 | __clear_user(ubuf->f_spare, sizeof(ubuf->f_spare))) | ||
329 | return -EFAULT; | ||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | COMPAT_SYSCALL_DEFINE3(statfs64, const char __user *, pathname, compat_size_t, sz, struct compat_statfs64 __user *, buf) | ||
334 | { | ||
335 | struct kstatfs tmp; | ||
336 | int error; | ||
337 | |||
338 | if (sz != sizeof(*buf)) | ||
339 | return -EINVAL; | ||
340 | |||
341 | error = user_statfs(pathname, &tmp); | ||
342 | if (!error) | ||
343 | error = put_compat_statfs64(buf, &tmp); | ||
344 | return error; | ||
345 | } | ||
346 | |||
347 | COMPAT_SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, compat_size_t, sz, struct compat_statfs64 __user *, buf) | ||
348 | { | ||
349 | struct kstatfs tmp; | ||
350 | int error; | ||
351 | |||
352 | if (sz != sizeof(*buf)) | ||
353 | return -EINVAL; | ||
354 | |||
355 | error = fd_statfs(fd, &tmp); | ||
356 | if (!error) | ||
357 | error = put_compat_statfs64(buf, &tmp); | ||
358 | return error; | ||
359 | } | ||
360 | |||
361 | /* | ||
362 | * This is a copy of sys_ustat, just dealing with a structure layout. | ||
363 | * Given how simple this syscall is that apporach is more maintainable | ||
364 | * than the various conversion hacks. | ||
365 | */ | ||
366 | COMPAT_SYSCALL_DEFINE2(ustat, unsigned, dev, struct compat_ustat __user *, u) | ||
367 | { | ||
368 | struct compat_ustat tmp; | ||
369 | struct kstatfs sbuf; | ||
370 | int err = vfs_ustat(new_decode_dev(dev), &sbuf); | ||
371 | if (err) | ||
372 | return err; | ||
373 | |||
374 | memset(&tmp, 0, sizeof(struct compat_ustat)); | ||
375 | tmp.f_tfree = sbuf.f_bfree; | ||
376 | tmp.f_tinode = sbuf.f_ffree; | ||
377 | if (copy_to_user(u, &tmp, sizeof(struct compat_ustat))) | ||
378 | return -EFAULT; | ||
379 | return 0; | ||
380 | } | ||
381 | #endif | ||
diff --git a/fs/utimes.c b/fs/utimes.c index 32b15b3f6629..6571d8c848a0 100644 --- a/fs/utimes.c +++ b/fs/utimes.c | |||
@@ -1,14 +1,10 @@ | |||
1 | #include <linux/compiler.h> | ||
2 | #include <linux/file.h> | 1 | #include <linux/file.h> |
3 | #include <linux/fs.h> | ||
4 | #include <linux/linkage.h> | ||
5 | #include <linux/mount.h> | 2 | #include <linux/mount.h> |
6 | #include <linux/namei.h> | 3 | #include <linux/namei.h> |
7 | #include <linux/sched.h> | ||
8 | #include <linux/stat.h> | ||
9 | #include <linux/utime.h> | 4 | #include <linux/utime.h> |
10 | #include <linux/syscalls.h> | 5 | #include <linux/syscalls.h> |
11 | #include <linux/uaccess.h> | 6 | #include <linux/uaccess.h> |
7 | #include <linux/compat.h> | ||
12 | #include <asm/unistd.h> | 8 | #include <asm/unistd.h> |
13 | 9 | ||
14 | #ifdef __ARCH_WANT_SYS_UTIME | 10 | #ifdef __ARCH_WANT_SYS_UTIME |
@@ -219,3 +215,63 @@ SYSCALL_DEFINE2(utimes, char __user *, filename, | |||
219 | { | 215 | { |
220 | return sys_futimesat(AT_FDCWD, filename, utimes); | 216 | return sys_futimesat(AT_FDCWD, filename, utimes); |
221 | } | 217 | } |
218 | |||
219 | #ifdef CONFIG_COMPAT | ||
220 | /* | ||
221 | * Not all architectures have sys_utime, so implement this in terms | ||
222 | * of sys_utimes. | ||
223 | */ | ||
224 | COMPAT_SYSCALL_DEFINE2(utime, const char __user *, filename, | ||
225 | struct compat_utimbuf __user *, t) | ||
226 | { | ||
227 | struct timespec tv[2]; | ||
228 | |||
229 | if (t) { | ||
230 | if (get_user(tv[0].tv_sec, &t->actime) || | ||
231 | get_user(tv[1].tv_sec, &t->modtime)) | ||
232 | return -EFAULT; | ||
233 | tv[0].tv_nsec = 0; | ||
234 | tv[1].tv_nsec = 0; | ||
235 | } | ||
236 | return do_utimes(AT_FDCWD, filename, t ? tv : NULL, 0); | ||
237 | } | ||
238 | |||
239 | COMPAT_SYSCALL_DEFINE4(utimensat, unsigned int, dfd, const char __user *, filename, struct compat_timespec __user *, t, int, flags) | ||
240 | { | ||
241 | struct timespec tv[2]; | ||
242 | |||
243 | if (t) { | ||
244 | if (compat_get_timespec(&tv[0], &t[0]) || | ||
245 | compat_get_timespec(&tv[1], &t[1])) | ||
246 | return -EFAULT; | ||
247 | |||
248 | if (tv[0].tv_nsec == UTIME_OMIT && tv[1].tv_nsec == UTIME_OMIT) | ||
249 | return 0; | ||
250 | } | ||
251 | return do_utimes(dfd, filename, t ? tv : NULL, flags); | ||
252 | } | ||
253 | |||
254 | COMPAT_SYSCALL_DEFINE3(futimesat, unsigned int, dfd, const char __user *, filename, struct compat_timeval __user *, t) | ||
255 | { | ||
256 | struct timespec tv[2]; | ||
257 | |||
258 | if (t) { | ||
259 | if (get_user(tv[0].tv_sec, &t[0].tv_sec) || | ||
260 | get_user(tv[0].tv_nsec, &t[0].tv_usec) || | ||
261 | get_user(tv[1].tv_sec, &t[1].tv_sec) || | ||
262 | get_user(tv[1].tv_nsec, &t[1].tv_usec)) | ||
263 | return -EFAULT; | ||
264 | if (tv[0].tv_nsec >= 1000000 || tv[0].tv_nsec < 0 || | ||
265 | tv[1].tv_nsec >= 1000000 || tv[1].tv_nsec < 0) | ||
266 | return -EINVAL; | ||
267 | tv[0].tv_nsec *= 1000; | ||
268 | tv[1].tv_nsec *= 1000; | ||
269 | } | ||
270 | return do_utimes(dfd, filename, t ? tv : NULL, 0); | ||
271 | } | ||
272 | |||
273 | COMPAT_SYSCALL_DEFINE2(utimes, const char __user *, filename, struct compat_timeval __user *, t) | ||
274 | { | ||
275 | return compat_sys_futimesat(AT_FDCWD, filename, t); | ||
276 | } | ||
277 | #endif | ||
diff --git a/include/linux/compat.h b/include/linux/compat.h index af9dbc44fd92..8172b03685f9 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h | |||
@@ -528,11 +528,6 @@ asmlinkage long compat_sys_old_readdir(unsigned int fd, | |||
528 | asmlinkage long compat_sys_getdents(unsigned int fd, | 528 | asmlinkage long compat_sys_getdents(unsigned int fd, |
529 | struct compat_linux_dirent __user *dirent, | 529 | struct compat_linux_dirent __user *dirent, |
530 | unsigned int count); | 530 | unsigned int count); |
531 | #ifdef __ARCH_WANT_COMPAT_SYS_GETDENTS64 | ||
532 | asmlinkage long compat_sys_getdents64(unsigned int fd, | ||
533 | struct linux_dirent64 __user *dirent, | ||
534 | unsigned int count); | ||
535 | #endif | ||
536 | asmlinkage long compat_sys_vmsplice(int fd, const struct compat_iovec __user *, | 531 | asmlinkage long compat_sys_vmsplice(int fd, const struct compat_iovec __user *, |
537 | unsigned int nr_segs, unsigned int flags); | 532 | unsigned int nr_segs, unsigned int flags); |
538 | asmlinkage long compat_sys_open(const char __user *filename, int flags, | 533 | asmlinkage long compat_sys_open(const char __user *filename, int flags, |
diff --git a/include/linux/poll.h b/include/linux/poll.h index a46d6755035e..75ffc5729e4c 100644 --- a/include/linux/poll.h +++ b/include/linux/poll.h | |||
@@ -98,64 +98,8 @@ extern int poll_schedule_timeout(struct poll_wqueues *pwq, int state, | |||
98 | ktime_t *expires, unsigned long slack); | 98 | ktime_t *expires, unsigned long slack); |
99 | extern u64 select_estimate_accuracy(struct timespec64 *tv); | 99 | extern u64 select_estimate_accuracy(struct timespec64 *tv); |
100 | 100 | ||
101 | |||
102 | static inline int poll_schedule(struct poll_wqueues *pwq, int state) | ||
103 | { | ||
104 | return poll_schedule_timeout(pwq, state, NULL, 0); | ||
105 | } | ||
106 | |||
107 | /* | ||
108 | * Scalable version of the fd_set. | ||
109 | */ | ||
110 | |||
111 | typedef struct { | ||
112 | unsigned long *in, *out, *ex; | ||
113 | unsigned long *res_in, *res_out, *res_ex; | ||
114 | } fd_set_bits; | ||
115 | |||
116 | /* | ||
117 | * How many longwords for "nr" bits? | ||
118 | */ | ||
119 | #define FDS_BITPERLONG (8*sizeof(long)) | ||
120 | #define FDS_LONGS(nr) (((nr)+FDS_BITPERLONG-1)/FDS_BITPERLONG) | ||
121 | #define FDS_BYTES(nr) (FDS_LONGS(nr)*sizeof(long)) | ||
122 | |||
123 | /* | ||
124 | * We do a VERIFY_WRITE here even though we are only reading this time: | ||
125 | * we'll write to it eventually.. | ||
126 | * | ||
127 | * Use "unsigned long" accesses to let user-mode fd_set's be long-aligned. | ||
128 | */ | ||
129 | static inline | ||
130 | int get_fd_set(unsigned long nr, void __user *ufdset, unsigned long *fdset) | ||
131 | { | ||
132 | nr = FDS_BYTES(nr); | ||
133 | if (ufdset) | ||
134 | return copy_from_user(fdset, ufdset, nr) ? -EFAULT : 0; | ||
135 | |||
136 | memset(fdset, 0, nr); | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static inline unsigned long __must_check | ||
141 | set_fd_set(unsigned long nr, void __user *ufdset, unsigned long *fdset) | ||
142 | { | ||
143 | if (ufdset) | ||
144 | return __copy_to_user(ufdset, fdset, FDS_BYTES(nr)); | ||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | static inline | ||
149 | void zero_fd_set(unsigned long nr, unsigned long *fdset) | ||
150 | { | ||
151 | memset(fdset, 0, FDS_BYTES(nr)); | ||
152 | } | ||
153 | |||
154 | #define MAX_INT64_SECONDS (((s64)(~((u64)0)>>1)/HZ)-1) | 101 | #define MAX_INT64_SECONDS (((s64)(~((u64)0)>>1)/HZ)-1) |
155 | 102 | ||
156 | extern int do_select(int n, fd_set_bits *fds, struct timespec64 *end_time); | ||
157 | extern int do_sys_poll(struct pollfd __user * ufds, unsigned int nfds, | ||
158 | struct timespec64 *end_time); | ||
159 | extern int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp, | 103 | extern int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp, |
160 | fd_set __user *exp, struct timespec64 *end_time); | 104 | fd_set __user *exp, struct timespec64 *end_time); |
161 | 105 | ||
diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h index a076cf1a3a23..061185a5eb51 100644 --- a/include/uapi/asm-generic/unistd.h +++ b/include/uapi/asm-generic/unistd.h | |||
@@ -194,8 +194,7 @@ __SYSCALL(__NR_quotactl, sys_quotactl) | |||
194 | 194 | ||
195 | /* fs/readdir.c */ | 195 | /* fs/readdir.c */ |
196 | #define __NR_getdents64 61 | 196 | #define __NR_getdents64 61 |
197 | #define __ARCH_WANT_COMPAT_SYS_GETDENTS64 | 197 | __SYSCALL(__NR_getdents64, sys_getdents64) |
198 | __SC_COMP(__NR_getdents64, sys_getdents64, compat_sys_getdents64) | ||
199 | 198 | ||
200 | /* fs/read_write.c */ | 199 | /* fs/read_write.c */ |
201 | #define __NR3264_lseek 62 | 200 | #define __NR3264_lseek 62 |