All of lore.kernel.org
 help / color / mirror / Atom feed
* rewrite file locking compat syscalls
@ 2017-05-15 20:33 Christoph Hellwig
  2017-05-15 20:33 ` [PATCH 1/2] fs/locks: pass kernel struct flock to fcntl_getlk/setlk Christoph Hellwig
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Christoph Hellwig @ 2017-05-15 20:33 UTC (permalink / raw)
  To: jlayton, bfields; +Cc: linux-fsdevel

Export proper lowlevel helper and use them from the compat code instead
of playing set_fs games.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/2] fs/locks: pass kernel struct flock to fcntl_getlk/setlk
  2017-05-15 20:33 rewrite file locking compat syscalls Christoph Hellwig
@ 2017-05-15 20:33 ` Christoph Hellwig
  2017-05-15 20:33 ` [PATCH 2/2] fs/locks: don't mess with the address limit in compat_fcntl64 Christoph Hellwig
  2017-05-16 10:08 ` rewrite file locking compat syscalls Jeff Layton
  2 siblings, 0 replies; 6+ messages in thread
From: Christoph Hellwig @ 2017-05-15 20:33 UTC (permalink / raw)
  To: jlayton, bfields; +Cc: linux-fsdevel

This will make it easier to implement a sane compat fcntl syscall.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 fs/fcntl.c         | 26 ++++++++++++++----
 fs/locks.c         | 77 +++++++++++++++---------------------------------------
 include/linux/fs.h |  8 +++---
 3 files changed, 46 insertions(+), 65 deletions(-)

diff --git a/fs/fcntl.c b/fs/fcntl.c
index f4e7267d117f..671ac43c65df 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -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:
 		/*
@@ -384,6 +392,7 @@ SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd,
 		unsigned long, arg)
 {	
 	struct fd f = fdget_raw(fd);
+	struct flock64 flock;
 	long err = -EBADF;
 
 	if (!f.file)
@@ -401,14 +410,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(filp, 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);
diff --git a/fs/locks.c b/fs/locks.c
index af2031a1fcff..054f6fb7641e 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -2086,26 +2086,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;
@@ -2117,15 +2113,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:
@@ -2218,26 +2211,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.
 	 */
@@ -2246,7 +2229,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;
 
@@ -2261,7 +2244,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;
@@ -2270,7 +2253,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;
@@ -2315,26 +2298,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;
@@ -2348,11 +2327,7 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l)
 
 	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:
@@ -2363,26 +2338,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.
 	 */
@@ -2391,7 +2356,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;
 
@@ -2406,7 +2371,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;
@@ -2415,7 +2380,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;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 803e5a9b2654..aa4affb38c39 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -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);
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/2] fs/locks: don't mess with the address limit in compat_fcntl64
  2017-05-15 20:33 rewrite file locking compat syscalls Christoph Hellwig
  2017-05-15 20:33 ` [PATCH 1/2] fs/locks: pass kernel struct flock to fcntl_getlk/setlk Christoph Hellwig
@ 2017-05-15 20:33 ` Christoph Hellwig
  2017-05-16 10:46   ` Jeff Layton
  2017-05-16 10:08 ` rewrite file locking compat syscalls Jeff Layton
  2 siblings, 1 reply; 6+ messages in thread
From: Christoph Hellwig @ 2017-05-15 20:33 UTC (permalink / raw)
  To: jlayton, bfields; +Cc: linux-fsdevel

Instead write a proper compat syscall that calls common helpers.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 fs/fcntl.c | 118 +++++++++++++++++++++++++++++++++++--------------------------
 fs/locks.c |   2 +-
 2 files changed, 68 insertions(+), 52 deletions(-)

diff --git a/fs/fcntl.c b/fs/fcntl.c
index 671ac43c65df..9d909b029063 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -505,76 +505,92 @@ convert_fcntl_cmd(unsigned int cmd)
 	return cmd;
 }
 
+/*
+ * 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
+ */
+static int fixup_compat_flock(struct flock *flock)
+{
+	if (flock.l_start > COMPAT_OFF_T_MAX)
+		return -EOVERFLOW;
+	if (flock.l_len > COMPAT_OFF_T_MAX)
+		flock.l_len = COMPAT_OFF_T_MAX;
+	return 0;
+}
+
 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;
+	struct fd f = fdget_raw(fd);
+	struct flock flock;
+	long err = -EBADF;
+
+	if (!f.file)
+		return err;
+
+	if (unlikely(f.file->f_mode & FMODE_PATH)) {
+		if (!check_fcntl_cmd(cmd))
+			goto out_put;
+	}
+
+	err = security_file_fcntl(f.file, cmd, arg);
+	if (err)
+		goto out_put;
 
 	switch (cmd) {
 	case F_GETLK:
+		err = get_compat_flock(&flock, compat_ptr(arg));
+		if (err)
+			break;
+		err = fcntl_getlk(f.file, convert_fcntl_cmd(cmd), &flock);
+		if (err)
+			break;
+		err = fixup_compat_flock(&flock);
+		if (err)
+			return err;
+		err = put_compat_flock(&flock, compat_ptr(arg));
+		break;
+	case F_GETLK64:
+	case F_OFD_GETLK:
+		err = get_compat_flock64(&flock, compat_ptr(arg));
+		if (err)
+			break;
+		err = fcntl_getlk(f.file, convert_fcntl_cmd(cmd), &flock);
+		if (err)
+			break;
+		err = fixup_compat_flock(&flock);
+		if (err)
+			return err;
+		err = put_compat_flock64(&flock, compat_ptr(arg));
+		break;
 	case F_SETLK:
 	case F_SETLKW:
-		ret = get_compat_flock(&f, compat_ptr(arg));
-		if (ret != 0)
+		err = get_compat_flock(&flock, compat_ptr(arg));
+		if (err)
 			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));
-		}
+		err = fcntl_setlk(fd, f.file, convert_fcntl_cmd(cmd), &flock);
 		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)
+		err = get_compat_flock64(&flock, compat_ptr(arg));
+		if (err)
 			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));
-		}
+		err = fcntl_setlk(fd, f.file, convert_fcntl_cmd(cmd), &flock);
 		break;
-
 	default:
-		ret = sys_fcntl(fd, cmd, arg);
+		err = do_fcntl(fd, cmd, arg, f.file);
 		break;
 	}
-	return ret;
+out_put:
+	fdput(f);
+	return err;
 }
 
 COMPAT_SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd,
diff --git a/fs/locks.c b/fs/locks.c
index 054f6fb7641e..8b4e78e4c054 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -2325,7 +2325,7 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 *flock)
 	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);
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: rewrite file locking compat syscalls
  2017-05-15 20:33 rewrite file locking compat syscalls Christoph Hellwig
  2017-05-15 20:33 ` [PATCH 1/2] fs/locks: pass kernel struct flock to fcntl_getlk/setlk Christoph Hellwig
  2017-05-15 20:33 ` [PATCH 2/2] fs/locks: don't mess with the address limit in compat_fcntl64 Christoph Hellwig
@ 2017-05-16 10:08 ` Jeff Layton
  2 siblings, 0 replies; 6+ messages in thread
From: Jeff Layton @ 2017-05-16 10:08 UTC (permalink / raw)
  To: Christoph Hellwig, bfields; +Cc: linux-fsdevel

On Mon, 2017-05-15 at 22:33 +0200, Christoph Hellwig wrote:
> Export proper lowlevel helper and use them from the compat code instead
> of playing set_fs games.
> 

Looks good -- nice cleanup...and yeah, ISTR that I broke ARM when
merging the OFD lock code because I screwed up the set_fs calls. So, I'm
all for this change.

Christoph, do you want me to plan to merge these for v4.13? If so, I'll
get them into my linux-next branch soon so we can start testing them.

Thanks,

Reviewed-by: Jeff Layton <jlayton@redhat.com>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/2] fs/locks: don't mess with the address limit in compat_fcntl64
  2017-05-15 20:33 ` [PATCH 2/2] fs/locks: don't mess with the address limit in compat_fcntl64 Christoph Hellwig
@ 2017-05-16 10:46   ` Jeff Layton
  2017-05-16 11:50     ` Christoph Hellwig
  0 siblings, 1 reply; 6+ messages in thread
From: Jeff Layton @ 2017-05-16 10:46 UTC (permalink / raw)
  To: Christoph Hellwig, bfields; +Cc: linux-fsdevel

On Mon, 2017-05-15 at 22:33 +0200, Christoph Hellwig wrote:
> Instead write a proper compat syscall that calls common helpers.
> 
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
>  fs/fcntl.c | 118 +++++++++++++++++++++++++++++++++++--------------------------
>  fs/locks.c |   2 +-
>  2 files changed, 68 insertions(+), 52 deletions(-)
> 
> diff --git a/fs/fcntl.c b/fs/fcntl.c
> index 671ac43c65df..9d909b029063 100644
> --- a/fs/fcntl.c
> +++ b/fs/fcntl.c
> @@ -505,76 +505,92 @@ convert_fcntl_cmd(unsigned int cmd)
>  	return cmd;
>  }
>  
> +/*
> + * 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
> + */
> +static int fixup_compat_flock(struct flock *flock)
> +{
> +	if (flock.l_start > COMPAT_OFF_T_MAX)
> +		return -EOVERFLOW;
> +	if (flock.l_len > COMPAT_OFF_T_MAX)
> +		flock.l_len = COMPAT_OFF_T_MAX;
> +	return 0;
> +}
> +

Erm...build break above though -- flock is a pointer there, so those
should be "flock->...". I'll just squash that fix into the patch unless
you need to send a respin for other reasons.

>  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;
> +	struct fd f = fdget_raw(fd);
> +	struct flock flock;
> +	long err = -EBADF;
> +
> +	if (!f.file)
> +		return err;
> +
> +	if (unlikely(f.file->f_mode & FMODE_PATH)) {
> +		if (!check_fcntl_cmd(cmd))
> +			goto out_put;
> +	}
> +
> +	err = security_file_fcntl(f.file, cmd, arg);
> +	if (err)
> +		goto out_put;
>  
>  	switch (cmd) {
>  	case F_GETLK:
> +		err = get_compat_flock(&flock, compat_ptr(arg));
> +		if (err)
> +			break;
> +		err = fcntl_getlk(f.file, convert_fcntl_cmd(cmd), &flock);
> +		if (err)
> +			break;
> +		err = fixup_compat_flock(&flock);
> +		if (err)
> +			return err;
> +		err = put_compat_flock(&flock, compat_ptr(arg));
> +		break;
> +	case F_GETLK64:
> +	case F_OFD_GETLK:
> +		err = get_compat_flock64(&flock, compat_ptr(arg));
> +		if (err)
> +			break;
> +		err = fcntl_getlk(f.file, convert_fcntl_cmd(cmd), &flock);
> +		if (err)
> +			break;
> +		err = fixup_compat_flock(&flock);
> +		if (err)
> +			return err;
> +		err = put_compat_flock64(&flock, compat_ptr(arg));
> +		break;
>  	case F_SETLK:
>  	case F_SETLKW:
> -		ret = get_compat_flock(&f, compat_ptr(arg));
> -		if (ret != 0)
> +		err = get_compat_flock(&flock, compat_ptr(arg));
> +		if (err)
>  			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));
> -		}
> +		err = fcntl_setlk(fd, f.file, convert_fcntl_cmd(cmd), &flock);
>  		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)
> +		err = get_compat_flock64(&flock, compat_ptr(arg));
> +		if (err)
>  			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));
> -		}
> +		err = fcntl_setlk(fd, f.file, convert_fcntl_cmd(cmd), &flock);
>  		break;
> -
>  	default:
> -		ret = sys_fcntl(fd, cmd, arg);
> +		err = do_fcntl(fd, cmd, arg, f.file);
>  		break;
>  	}
> -	return ret;
> +out_put:
> +	fdput(f);
> +	return err;
>  }
>  
>  COMPAT_SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd,
> diff --git a/fs/locks.c b/fs/locks.c
> index 054f6fb7641e..8b4e78e4c054 100644
> --- a/fs/locks.c
> +++ b/fs/locks.c
> @@ -2325,7 +2325,7 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 *flock)
>  	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);
>  

-- 
Jeff Layton <jlayton@poochiereds.net>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/2] fs/locks: don't mess with the address limit in compat_fcntl64
  2017-05-16 10:46   ` Jeff Layton
@ 2017-05-16 11:50     ` Christoph Hellwig
  0 siblings, 0 replies; 6+ messages in thread
From: Christoph Hellwig @ 2017-05-16 11:50 UTC (permalink / raw)
  To: Jeff Layton; +Cc: bfields, linux-fsdevel

On Tue, May 16, 2017 at 06:46:10AM -0400, Jeff Layton wrote:
> Erm...build break above though -- flock is a pointer there, so those
> should be "flock->...". I'll just squash that fix into the patch unless
> you need to send a respin for other reasons.

Thanks.  I did a last minute fixup to factor this into a helper and messed
up..

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2017-05-16 11:50 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-05-15 20:33 rewrite file locking compat syscalls Christoph Hellwig
2017-05-15 20:33 ` [PATCH 1/2] fs/locks: pass kernel struct flock to fcntl_getlk/setlk Christoph Hellwig
2017-05-15 20:33 ` [PATCH 2/2] fs/locks: don't mess with the address limit in compat_fcntl64 Christoph Hellwig
2017-05-16 10:46   ` Jeff Layton
2017-05-16 11:50     ` Christoph Hellwig
2017-05-16 10:08 ` rewrite file locking compat syscalls Jeff Layton

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.