fcntl: move compat syscalls from compat.c
authorAl Viro <viro@zeniv.linux.org.uk>
Sat, 8 Apr 2017 22:10:56 +0000 (18:10 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Mon, 17 Apr 2017 16:52:24 +0000 (12:52 -0400)
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/compat.c
fs/fcntl.c

index b1c4bee28ede7663f93d594dca3ab4038255b2eb..000af26ef6b996f879ba00aa87c9255aa5164cb0 100644 (file)
@@ -137,160 +137,6 @@ COMPAT_SYSCALL_DEFINE2(newfstat, unsigned int, fd,
        return error;
 }
 
-static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
-{
-       if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
-           __get_user(kfl->l_type, &ufl->l_type) ||
-           __get_user(kfl->l_whence, &ufl->l_whence) ||
-           __get_user(kfl->l_start, &ufl->l_start) ||
-           __get_user(kfl->l_len, &ufl->l_len) ||
-           __get_user(kfl->l_pid, &ufl->l_pid))
-               return -EFAULT;
-       return 0;
-}
-
-static int put_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
-{
-       if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) ||
-           __put_user(kfl->l_type, &ufl->l_type) ||
-           __put_user(kfl->l_whence, &ufl->l_whence) ||
-           __put_user(kfl->l_start, &ufl->l_start) ||
-           __put_user(kfl->l_len, &ufl->l_len) ||
-           __put_user(kfl->l_pid, &ufl->l_pid))
-               return -EFAULT;
-       return 0;
-}
-
-#ifndef HAVE_ARCH_GET_COMPAT_FLOCK64
-static int get_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl)
-{
-       if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
-           __get_user(kfl->l_type, &ufl->l_type) ||
-           __get_user(kfl->l_whence, &ufl->l_whence) ||
-           __get_user(kfl->l_start, &ufl->l_start) ||
-           __get_user(kfl->l_len, &ufl->l_len) ||
-           __get_user(kfl->l_pid, &ufl->l_pid))
-               return -EFAULT;
-       return 0;
-}
-#endif
-
-#ifndef HAVE_ARCH_PUT_COMPAT_FLOCK64
-static int put_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl)
-{
-       if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) ||
-           __put_user(kfl->l_type, &ufl->l_type) ||
-           __put_user(kfl->l_whence, &ufl->l_whence) ||
-           __put_user(kfl->l_start, &ufl->l_start) ||
-           __put_user(kfl->l_len, &ufl->l_len) ||
-           __put_user(kfl->l_pid, &ufl->l_pid))
-               return -EFAULT;
-       return 0;
-}
-#endif
-
-static unsigned int
-convert_fcntl_cmd(unsigned int cmd)
-{
-       switch (cmd) {
-       case F_GETLK64:
-               return F_GETLK;
-       case F_SETLK64:
-               return F_SETLK;
-       case F_SETLKW64:
-               return F_SETLKW;
-       }
-
-       return cmd;
-}
-
-COMPAT_SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd,
-                      compat_ulong_t, arg)
-{
-       mm_segment_t old_fs;
-       struct flock f;
-       long ret;
-       unsigned int conv_cmd;
-
-       switch (cmd) {
-       case F_GETLK:
-       case F_SETLK:
-       case F_SETLKW:
-               ret = get_compat_flock(&f, compat_ptr(arg));
-               if (ret != 0)
-                       break;
-               old_fs = get_fs();
-               set_fs(KERNEL_DS);
-               ret = sys_fcntl(fd, cmd, (unsigned long)&f);
-               set_fs(old_fs);
-               if (cmd == F_GETLK && ret == 0) {
-                       /* GETLK was successful and we need to return the data...
-                        * but it needs to fit in the compat structure.
-                        * l_start shouldn't be too big, unless the original
-                        * start + end is greater than COMPAT_OFF_T_MAX, in which
-                        * case the app was asking for trouble, so we return
-                        * -EOVERFLOW in that case.
-                        * l_len could be too big, in which case we just truncate it,
-                        * and only allow the app to see that part of the conflicting
-                        * lock that might make sense to it anyway
-                        */
-
-                       if (f.l_start > COMPAT_OFF_T_MAX)
-                               ret = -EOVERFLOW;
-                       if (f.l_len > COMPAT_OFF_T_MAX)
-                               f.l_len = COMPAT_OFF_T_MAX;
-                       if (ret == 0)
-                               ret = put_compat_flock(&f, compat_ptr(arg));
-               }
-               break;
-
-       case F_GETLK64:
-       case F_SETLK64:
-       case F_SETLKW64:
-       case F_OFD_GETLK:
-       case F_OFD_SETLK:
-       case F_OFD_SETLKW:
-               ret = get_compat_flock64(&f, compat_ptr(arg));
-               if (ret != 0)
-                       break;
-               old_fs = get_fs();
-               set_fs(KERNEL_DS);
-               conv_cmd = convert_fcntl_cmd(cmd);
-               ret = sys_fcntl(fd, conv_cmd, (unsigned long)&f);
-               set_fs(old_fs);
-               if ((conv_cmd == F_GETLK || conv_cmd == F_OFD_GETLK) && ret == 0) {
-                       /* need to return lock information - see above for commentary */
-                       if (f.l_start > COMPAT_LOFF_T_MAX)
-                               ret = -EOVERFLOW;
-                       if (f.l_len > COMPAT_LOFF_T_MAX)
-                               f.l_len = COMPAT_LOFF_T_MAX;
-                       if (ret == 0)
-                               ret = put_compat_flock64(&f, compat_ptr(arg));
-               }
-               break;
-
-       default:
-               ret = sys_fcntl(fd, cmd, arg);
-               break;
-       }
-       return ret;
-}
-
-COMPAT_SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd,
-                      compat_ulong_t, arg)
-{
-       switch (cmd) {
-       case F_GETLK64:
-       case F_SETLK64:
-       case F_SETLKW64:
-       case F_OFD_GETLK:
-       case F_OFD_SETLK:
-       case F_OFD_SETLKW:
-               return -EINVAL;
-       }
-       return compat_sys_fcntl64(fd, cmd, arg);
-}
-
 /* A write operation does a read from user space and vice versa */
 #define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ)
 
index be8fbe289087e61222103ec5675bb27857c502e0..8bd81c2e89b2701c9b64aa46556e623e5bb4acb4 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/pid_namespace.h>
 #include <linux/user_namespace.h>
 #include <linux/shmem_fs.h>
+#include <linux/compat.h>
 
 #include <asm/poll.h>
 #include <asm/siginfo.h>
@@ -420,6 +421,162 @@ out:
 }
 #endif
 
+#ifdef CONFIG_COMPAT
+static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
+{
+       if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
+           __get_user(kfl->l_type, &ufl->l_type) ||
+           __get_user(kfl->l_whence, &ufl->l_whence) ||
+           __get_user(kfl->l_start, &ufl->l_start) ||
+           __get_user(kfl->l_len, &ufl->l_len) ||
+           __get_user(kfl->l_pid, &ufl->l_pid))
+               return -EFAULT;
+       return 0;
+}
+
+static int put_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
+{
+       if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) ||
+           __put_user(kfl->l_type, &ufl->l_type) ||
+           __put_user(kfl->l_whence, &ufl->l_whence) ||
+           __put_user(kfl->l_start, &ufl->l_start) ||
+           __put_user(kfl->l_len, &ufl->l_len) ||
+           __put_user(kfl->l_pid, &ufl->l_pid))
+               return -EFAULT;
+       return 0;
+}
+
+#ifndef HAVE_ARCH_GET_COMPAT_FLOCK64
+static int get_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl)
+{
+       if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
+           __get_user(kfl->l_type, &ufl->l_type) ||
+           __get_user(kfl->l_whence, &ufl->l_whence) ||
+           __get_user(kfl->l_start, &ufl->l_start) ||
+           __get_user(kfl->l_len, &ufl->l_len) ||
+           __get_user(kfl->l_pid, &ufl->l_pid))
+               return -EFAULT;
+       return 0;
+}
+#endif
+
+#ifndef HAVE_ARCH_PUT_COMPAT_FLOCK64
+static int put_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl)
+{
+       if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) ||
+           __put_user(kfl->l_type, &ufl->l_type) ||
+           __put_user(kfl->l_whence, &ufl->l_whence) ||
+           __put_user(kfl->l_start, &ufl->l_start) ||
+           __put_user(kfl->l_len, &ufl->l_len) ||
+           __put_user(kfl->l_pid, &ufl->l_pid))
+               return -EFAULT;
+       return 0;
+}
+#endif
+
+static unsigned int
+convert_fcntl_cmd(unsigned int cmd)
+{
+       switch (cmd) {
+       case F_GETLK64:
+               return F_GETLK;
+       case F_SETLK64:
+               return F_SETLK;
+       case F_SETLKW64:
+               return F_SETLKW;
+       }
+
+       return cmd;
+}
+
+COMPAT_SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd,
+                      compat_ulong_t, arg)
+{
+       mm_segment_t old_fs;
+       struct flock f;
+       long ret;
+       unsigned int conv_cmd;
+
+       switch (cmd) {
+       case F_GETLK:
+       case F_SETLK:
+       case F_SETLKW:
+               ret = get_compat_flock(&f, compat_ptr(arg));
+               if (ret != 0)
+                       break;
+               old_fs = get_fs();
+               set_fs(KERNEL_DS);
+               ret = sys_fcntl(fd, cmd, (unsigned long)&f);
+               set_fs(old_fs);
+               if (cmd == F_GETLK && ret == 0) {
+                       /* GETLK was successful and we need to return the data...
+                        * but it needs to fit in the compat structure.
+                        * l_start shouldn't be too big, unless the original
+                        * start + end is greater than COMPAT_OFF_T_MAX, in which
+                        * case the app was asking for trouble, so we return
+                        * -EOVERFLOW in that case.
+                        * l_len could be too big, in which case we just truncate it,
+                        * and only allow the app to see that part of the conflicting
+                        * lock that might make sense to it anyway
+                        */
+
+                       if (f.l_start > COMPAT_OFF_T_MAX)
+                               ret = -EOVERFLOW;
+                       if (f.l_len > COMPAT_OFF_T_MAX)
+                               f.l_len = COMPAT_OFF_T_MAX;
+                       if (ret == 0)
+                               ret = put_compat_flock(&f, compat_ptr(arg));
+               }
+               break;
+
+       case F_GETLK64:
+       case F_SETLK64:
+       case F_SETLKW64:
+       case F_OFD_GETLK:
+       case F_OFD_SETLK:
+       case F_OFD_SETLKW:
+               ret = get_compat_flock64(&f, compat_ptr(arg));
+               if (ret != 0)
+                       break;
+               old_fs = get_fs();
+               set_fs(KERNEL_DS);
+               conv_cmd = convert_fcntl_cmd(cmd);
+               ret = sys_fcntl(fd, conv_cmd, (unsigned long)&f);
+               set_fs(old_fs);
+               if ((conv_cmd == F_GETLK || conv_cmd == F_OFD_GETLK) && ret == 0) {
+                       /* need to return lock information - see above for commentary */
+                       if (f.l_start > COMPAT_LOFF_T_MAX)
+                               ret = -EOVERFLOW;
+                       if (f.l_len > COMPAT_LOFF_T_MAX)
+                               f.l_len = COMPAT_LOFF_T_MAX;
+                       if (ret == 0)
+                               ret = put_compat_flock64(&f, compat_ptr(arg));
+               }
+               break;
+
+       default:
+               ret = sys_fcntl(fd, cmd, arg);
+               break;
+       }
+       return ret;
+}
+
+COMPAT_SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd,
+                      compat_ulong_t, arg)
+{
+       switch (cmd) {
+       case F_GETLK64:
+       case F_SETLK64:
+       case F_SETLKW64:
+       case F_OFD_GETLK:
+       case F_OFD_SETLK:
+       case F_OFD_SETLKW:
+               return -EINVAL;
+       }
+       return compat_sys_fcntl64(fd, cmd, arg);
+}
+#endif
+
 /* Table to convert sigio signal codes into poll band bitmaps */
 
 static const long band_table[NSIGPOLL] = {