diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2017-04-08 18:10:56 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2017-04-17 12:52:24 -0400 |
commit | 80f0cce6aadebf6caf74d1f8ceb4b008ca72a9e9 (patch) | |
tree | 3ecede861f53ad46e44c0bd72a0353698aeeda33 | |
parent | 0460b2a28b4b39cdd1ca9a420126353b27ebc954 (diff) |
fcntl: move compat syscalls from compat.c
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/compat.c | 154 | ||||
-rw-r--r-- | fs/fcntl.c | 157 |
2 files changed, 157 insertions, 154 deletions
diff --git a/fs/compat.c b/fs/compat.c index b1c4bee28ede..000af26ef6b9 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
@@ -137,160 +137,6 @@ COMPAT_SYSCALL_DEFINE2(newfstat, unsigned int, fd, | |||
137 | return error; | 137 | return error; |
138 | } | 138 | } |
139 | 139 | ||
140 | static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl) | ||
141 | { | ||
142 | if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) || | ||
143 | __get_user(kfl->l_type, &ufl->l_type) || | ||
144 | __get_user(kfl->l_whence, &ufl->l_whence) || | ||
145 | __get_user(kfl->l_start, &ufl->l_start) || | ||
146 | __get_user(kfl->l_len, &ufl->l_len) || | ||
147 | __get_user(kfl->l_pid, &ufl->l_pid)) | ||
148 | return -EFAULT; | ||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | static int put_compat_flock(struct flock *kfl, struct compat_flock __user *ufl) | ||
153 | { | ||
154 | if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) || | ||
155 | __put_user(kfl->l_type, &ufl->l_type) || | ||
156 | __put_user(kfl->l_whence, &ufl->l_whence) || | ||
157 | __put_user(kfl->l_start, &ufl->l_start) || | ||
158 | __put_user(kfl->l_len, &ufl->l_len) || | ||
159 | __put_user(kfl->l_pid, &ufl->l_pid)) | ||
160 | return -EFAULT; | ||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | #ifndef HAVE_ARCH_GET_COMPAT_FLOCK64 | ||
165 | static int get_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl) | ||
166 | { | ||
167 | if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) || | ||
168 | __get_user(kfl->l_type, &ufl->l_type) || | ||
169 | __get_user(kfl->l_whence, &ufl->l_whence) || | ||
170 | __get_user(kfl->l_start, &ufl->l_start) || | ||
171 | __get_user(kfl->l_len, &ufl->l_len) || | ||
172 | __get_user(kfl->l_pid, &ufl->l_pid)) | ||
173 | return -EFAULT; | ||
174 | return 0; | ||
175 | } | ||
176 | #endif | ||
177 | |||
178 | #ifndef HAVE_ARCH_PUT_COMPAT_FLOCK64 | ||
179 | static int put_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl) | ||
180 | { | ||
181 | if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) || | ||
182 | __put_user(kfl->l_type, &ufl->l_type) || | ||
183 | __put_user(kfl->l_whence, &ufl->l_whence) || | ||
184 | __put_user(kfl->l_start, &ufl->l_start) || | ||
185 | __put_user(kfl->l_len, &ufl->l_len) || | ||
186 | __put_user(kfl->l_pid, &ufl->l_pid)) | ||
187 | return -EFAULT; | ||
188 | return 0; | ||
189 | } | ||
190 | #endif | ||
191 | |||
192 | static unsigned int | ||
193 | convert_fcntl_cmd(unsigned int cmd) | ||
194 | { | ||
195 | switch (cmd) { | ||
196 | case F_GETLK64: | ||
197 | return F_GETLK; | ||
198 | case F_SETLK64: | ||
199 | return F_SETLK; | ||
200 | case F_SETLKW64: | ||
201 | return F_SETLKW; | ||
202 | } | ||
203 | |||
204 | return cmd; | ||
205 | } | ||
206 | |||
207 | COMPAT_SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, | ||
208 | compat_ulong_t, arg) | ||
209 | { | ||
210 | mm_segment_t old_fs; | ||
211 | struct flock f; | ||
212 | long ret; | ||
213 | unsigned int conv_cmd; | ||
214 | |||
215 | switch (cmd) { | ||
216 | case F_GETLK: | ||
217 | case F_SETLK: | ||
218 | case F_SETLKW: | ||
219 | ret = get_compat_flock(&f, compat_ptr(arg)); | ||
220 | if (ret != 0) | ||
221 | break; | ||
222 | old_fs = get_fs(); | ||
223 | set_fs(KERNEL_DS); | ||
224 | ret = sys_fcntl(fd, cmd, (unsigned long)&f); | ||
225 | set_fs(old_fs); | ||
226 | if (cmd == F_GETLK && ret == 0) { | ||
227 | /* GETLK was successful and we need to return the data... | ||
228 | * but it needs to fit in the compat structure. | ||
229 | * l_start shouldn't be too big, unless the original | ||
230 | * start + end is greater than COMPAT_OFF_T_MAX, in which | ||
231 | * case the app was asking for trouble, so we return | ||
232 | * -EOVERFLOW in that case. | ||
233 | * l_len could be too big, in which case we just truncate it, | ||
234 | * and only allow the app to see that part of the conflicting | ||
235 | * lock that might make sense to it anyway | ||
236 | */ | ||
237 | |||
238 | if (f.l_start > COMPAT_OFF_T_MAX) | ||
239 | ret = -EOVERFLOW; | ||
240 | if (f.l_len > COMPAT_OFF_T_MAX) | ||
241 | f.l_len = COMPAT_OFF_T_MAX; | ||
242 | if (ret == 0) | ||
243 | ret = put_compat_flock(&f, compat_ptr(arg)); | ||
244 | } | ||
245 | break; | ||
246 | |||
247 | case F_GETLK64: | ||
248 | case F_SETLK64: | ||
249 | case F_SETLKW64: | ||
250 | case F_OFD_GETLK: | ||
251 | case F_OFD_SETLK: | ||
252 | case F_OFD_SETLKW: | ||
253 | ret = get_compat_flock64(&f, compat_ptr(arg)); | ||
254 | if (ret != 0) | ||
255 | break; | ||
256 | old_fs = get_fs(); | ||
257 | set_fs(KERNEL_DS); | ||
258 | conv_cmd = convert_fcntl_cmd(cmd); | ||
259 | ret = sys_fcntl(fd, conv_cmd, (unsigned long)&f); | ||
260 | set_fs(old_fs); | ||
261 | if ((conv_cmd == F_GETLK || conv_cmd == F_OFD_GETLK) && ret == 0) { | ||
262 | /* need to return lock information - see above for commentary */ | ||
263 | if (f.l_start > COMPAT_LOFF_T_MAX) | ||
264 | ret = -EOVERFLOW; | ||
265 | if (f.l_len > COMPAT_LOFF_T_MAX) | ||
266 | f.l_len = COMPAT_LOFF_T_MAX; | ||
267 | if (ret == 0) | ||
268 | ret = put_compat_flock64(&f, compat_ptr(arg)); | ||
269 | } | ||
270 | break; | ||
271 | |||
272 | default: | ||
273 | ret = sys_fcntl(fd, cmd, arg); | ||
274 | break; | ||
275 | } | ||
276 | return ret; | ||
277 | } | ||
278 | |||
279 | COMPAT_SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, | ||
280 | compat_ulong_t, arg) | ||
281 | { | ||
282 | switch (cmd) { | ||
283 | case F_GETLK64: | ||
284 | case F_SETLK64: | ||
285 | case F_SETLKW64: | ||
286 | case F_OFD_GETLK: | ||
287 | case F_OFD_SETLK: | ||
288 | case F_OFD_SETLKW: | ||
289 | return -EINVAL; | ||
290 | } | ||
291 | return compat_sys_fcntl64(fd, cmd, arg); | ||
292 | } | ||
293 | |||
294 | /* A write operation does a read from user space and vice versa */ | 140 | /* A write operation does a read from user space and vice versa */ |
295 | #define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ) | 141 | #define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ) |
296 | 142 | ||
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] = { |