]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
fs/locks: pass kernel struct flock to fcntl_getlk/setlk
authorChristoph Hellwig <hch@lst.de>
Sat, 27 May 2017 10:07:19 +0000 (06:07 -0400)
committerJeff Layton <jlayton@redhat.com>
Sat, 27 May 2017 10:07:19 +0000 (06:07 -0400)
This will make it easier to implement a sane compat fcntl syscall.

[ jlayton: fix undeclared identifiers in 32-bit fcntl64 syscall handler ]

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Jeff Layton <jlayton@redhat.com>
fs/fcntl.c
fs/locks.c
include/linux/fs.h

index f4e7267d117fb83b69f6f5be2305fb8b375077c8..ed4283d500a37cc655626f1e9600a62b7d76e320 100644 (file)
@@ -246,6 +246,8 @@ static int f_getowner_uids(struct file *filp, unsigned long arg)
 static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
                struct file *filp)
 {
+       void __user *argp = (void __user *)arg;
+       struct flock flock;
        long err = -EINVAL;
 
        switch (cmd) {
@@ -273,7 +275,11 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
        case F_OFD_GETLK:
 #endif
        case F_GETLK:
-               err = fcntl_getlk(filp, cmd, (struct flock __user *) arg);
+               if (copy_from_user(&flock, argp, sizeof(flock)))
+                       return -EFAULT;
+               err = fcntl_getlk(filp, cmd, &flock);
+               if (!err && copy_to_user(argp, &flock, sizeof(flock)))
+                       return -EFAULT;
                break;
 #if BITS_PER_LONG != 32
        /* 32-bit arches must use fcntl64() */
@@ -283,7 +289,9 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
                /* Fallthrough */
        case F_SETLK:
        case F_SETLKW:
-               err = fcntl_setlk(fd, filp, cmd, (struct flock __user *) arg);
+               if (copy_from_user(&flock, argp, sizeof(flock)))
+                       return -EFAULT;
+               err = fcntl_setlk(fd, filp, cmd, &flock);
                break;
        case F_GETOWN:
                /*
@@ -383,7 +391,9 @@ SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)
 SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd,
                unsigned long, arg)
 {      
+       void __user *argp = (void __user *)arg;
        struct fd f = fdget_raw(fd);
+       struct flock64 flock;
        long err = -EBADF;
 
        if (!f.file)
@@ -401,14 +411,21 @@ SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd,
        switch (cmd) {
        case F_GETLK64:
        case F_OFD_GETLK:
-               err = fcntl_getlk64(f.file, cmd, (struct flock64 __user *) arg);
+               err = -EFAULT;
+               if (copy_from_user(&flock, argp, sizeof(flock)))
+                       break;
+               err = fcntl_getlk64(f.file, cmd, &flock);
+               if (!err && copy_to_user(argp, &flock, sizeof(flock)))
+                       err = -EFAULT;
                break;
        case F_SETLK64:
        case F_SETLKW64:
        case F_OFD_SETLK:
        case F_OFD_SETLKW:
-               err = fcntl_setlk64(fd, f.file, cmd,
-                               (struct flock64 __user *) arg);
+               err = -EFAULT;
+               if (copy_from_user(&flock, argp, sizeof(flock)))
+                       break;
+               err = fcntl_setlk64(fd, f.file, cmd, &flock);
                break;
        default:
                err = do_fcntl(fd, cmd, arg, f.file);
index 4a4543a7f9c11baec01c01eb3e18ebc9637fcac1..afefeb4ad6ded4229d7ba69517c512a59177b3a1 100644 (file)
@@ -2084,26 +2084,22 @@ static void posix_lock_to_flock64(struct flock64 *flock, struct file_lock *fl)
 /* Report the first existing lock that would conflict with l.
  * This implements the F_GETLK command of fcntl().
  */
-int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock __user *l)
+int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock *flock)
 {
        struct file_lock file_lock;
-       struct flock flock;
        int error;
 
-       error = -EFAULT;
-       if (copy_from_user(&flock, l, sizeof(flock)))
-               goto out;
        error = -EINVAL;
-       if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK))
+       if (flock->l_type != F_RDLCK && flock->l_type != F_WRLCK)
                goto out;
 
-       error = flock_to_posix_lock(filp, &file_lock, &flock);
+       error = flock_to_posix_lock(filp, &file_lock, flock);
        if (error)
                goto out;
 
        if (cmd == F_OFD_GETLK) {
                error = -EINVAL;
-               if (flock.l_pid != 0)
+               if (flock->l_pid != 0)
                        goto out;
 
                cmd = F_GETLK;
@@ -2115,15 +2111,12 @@ int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock __user *l)
        if (error)
                goto out;
  
-       flock.l_type = file_lock.fl_type;
+       flock->l_type = file_lock.fl_type;
        if (file_lock.fl_type != F_UNLCK) {
-               error = posix_lock_to_flock(&flock, &file_lock);
+               error = posix_lock_to_flock(flock, &file_lock);
                if (error)
                        goto rel_priv;
        }
-       error = -EFAULT;
-       if (!copy_to_user(l, &flock, sizeof(flock)))
-               error = 0;
 rel_priv:
        locks_release_private(&file_lock);
 out:
@@ -2216,26 +2209,16 @@ check_fmode_for_setlk(struct file_lock *fl)
  * This implements both the F_SETLK and F_SETLKW commands of fcntl().
  */
 int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
-               struct flock __user *l)
+               struct flock *flock)
 {
        struct file_lock *file_lock = locks_alloc_lock();
-       struct flock flock;
-       struct inode *inode;
+       struct inode *inode = locks_inode(filp);
        struct file *f;
        int error;
 
        if (file_lock == NULL)
                return -ENOLCK;
 
-       inode = locks_inode(filp);
-
-       /*
-        * This might block, so we do it before checking the inode.
-        */
-       error = -EFAULT;
-       if (copy_from_user(&flock, l, sizeof(flock)))
-               goto out;
-
        /* Don't allow mandatory locks on files that may be memory mapped
         * and shared.
         */
@@ -2244,7 +2227,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
                goto out;
        }
 
-       error = flock_to_posix_lock(filp, file_lock, &flock);
+       error = flock_to_posix_lock(filp, file_lock, flock);
        if (error)
                goto out;
 
@@ -2259,7 +2242,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
        switch (cmd) {
        case F_OFD_SETLK:
                error = -EINVAL;
-               if (flock.l_pid != 0)
+               if (flock->l_pid != 0)
                        goto out;
 
                cmd = F_SETLK;
@@ -2268,7 +2251,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
                break;
        case F_OFD_SETLKW:
                error = -EINVAL;
-               if (flock.l_pid != 0)
+               if (flock->l_pid != 0)
                        goto out;
 
                cmd = F_SETLKW;
@@ -2313,26 +2296,22 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
 /* Report the first existing lock that would conflict with l.
  * This implements the F_GETLK command of fcntl().
  */
-int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l)
+int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 *flock)
 {
        struct file_lock file_lock;
-       struct flock64 flock;
        int error;
 
-       error = -EFAULT;
-       if (copy_from_user(&flock, l, sizeof(flock)))
-               goto out;
        error = -EINVAL;
-       if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK))
+       if (flock->l_type != F_RDLCK && flock->l_type != F_WRLCK)
                goto out;
 
-       error = flock64_to_posix_lock(filp, &file_lock, &flock);
+       error = flock64_to_posix_lock(filp, &file_lock, flock);
        if (error)
                goto out;
 
        if (cmd == F_OFD_GETLK) {
                error = -EINVAL;
-               if (flock.l_pid != 0)
+               if (flock->l_pid != 0)
                        goto out;
 
                cmd = F_GETLK64;
@@ -2344,13 +2323,9 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l)
        if (error)
                goto out;
 
-       flock.l_type = file_lock.fl_type;
+       flock->l_type = file_lock.fl_type;
        if (file_lock.fl_type != F_UNLCK)
-               posix_lock_to_flock64(&flock, &file_lock);
-
-       error = -EFAULT;
-       if (!copy_to_user(l, &flock, sizeof(flock)))
-               error = 0;
+               posix_lock_to_flock64(flock, &file_lock);
 
        locks_release_private(&file_lock);
 out:
@@ -2361,26 +2336,16 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l)
  * This implements both the F_SETLK and F_SETLKW commands of fcntl().
  */
 int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
-               struct flock64 __user *l)
+               struct flock64 *flock)
 {
        struct file_lock *file_lock = locks_alloc_lock();
-       struct flock64 flock;
-       struct inode *inode;
+       struct inode *inode = locks_inode(filp);
        struct file *f;
        int error;
 
        if (file_lock == NULL)
                return -ENOLCK;
 
-       /*
-        * This might block, so we do it before checking the inode.
-        */
-       error = -EFAULT;
-       if (copy_from_user(&flock, l, sizeof(flock)))
-               goto out;
-
-       inode = locks_inode(filp);
-
        /* Don't allow mandatory locks on files that may be memory mapped
         * and shared.
         */
@@ -2389,7 +2354,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
                goto out;
        }
 
-       error = flock64_to_posix_lock(filp, file_lock, &flock);
+       error = flock64_to_posix_lock(filp, file_lock, flock);
        if (error)
                goto out;
 
@@ -2404,7 +2369,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
        switch (cmd) {
        case F_OFD_SETLK:
                error = -EINVAL;
-               if (flock.l_pid != 0)
+               if (flock->l_pid != 0)
                        goto out;
 
                cmd = F_SETLK64;
@@ -2413,7 +2378,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
                break;
        case F_OFD_SETLKW:
                error = -EINVAL;
-               if (flock.l_pid != 0)
+               if (flock->l_pid != 0)
                        goto out;
 
                cmd = F_SETLKW64;
index 803e5a9b265422d2c2034678331b6d4dd353d1de..aa4affb38c39192f2878a26681b772c1dbf64ed1 100644 (file)
@@ -1038,14 +1038,14 @@ static inline struct inode *locks_inode(const struct file *f)
 }
 
 #ifdef CONFIG_FILE_LOCKING
-extern int fcntl_getlk(struct file *, unsigned int, struct flock __user *);
+extern int fcntl_getlk(struct file *, unsigned int, struct flock *);
 extern int fcntl_setlk(unsigned int, struct file *, unsigned int,
-                       struct flock __user *);
+                       struct flock *);
 
 #if BITS_PER_LONG == 32
-extern int fcntl_getlk64(struct file *, unsigned int, struct flock64 __user *);
+extern int fcntl_getlk64(struct file *, unsigned int, struct flock64 *);
 extern int fcntl_setlk64(unsigned int, struct file *, unsigned int,
-                       struct flock64 __user *);
+                       struct flock64 *);
 #endif
 
 extern int fcntl_setlease(unsigned int fd, struct file *filp, long arg);