summaryrefslogtreecommitdiffstats
path: root/fs/fcntl.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2017-04-08 18:10:56 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2017-04-17 12:52:24 -0400
commit80f0cce6aadebf6caf74d1f8ceb4b008ca72a9e9 (patch)
tree3ecede861f53ad46e44c0bd72a0353698aeeda33 /fs/fcntl.c
parent0460b2a28b4b39cdd1ca9a420126353b27ebc954 (diff)
fcntl: move compat syscalls from compat.c
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/fcntl.c')
-rw-r--r--fs/fcntl.c157
1 files changed, 157 insertions, 0 deletions
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
425static 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
437static 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
450static 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
464static 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
477static unsigned int
478convert_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
492COMPAT_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
564COMPAT_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
425static const long band_table[NSIGPOLL] = { 582static const long band_table[NSIGPOLL] = {