linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Jens Axboe <axboe@kernel.dk>
To: Al Viro <viro@zeniv.linux.org.uk>
Cc: Max Kellermann <mk@cm4all.com>,
	linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org,
	stable@vger.kernel.org
Subject: Re: [PATCH] fs/io_uring: fix O_PATH fds in openat, openat2, statx
Date: Thu, 7 May 2020 17:03:17 -0600	[thread overview]
Message-ID: <e16125f2-c3ec-f029-c607-19bede54fa17@kernel.dk> (raw)
In-Reply-To: <20200507224447.GI23230@ZenIV.linux.org.uk>

On 5/7/20 4:44 PM, Al Viro wrote:
> On Thu, May 07, 2020 at 04:25:24PM -0600, Jens Axboe wrote:
> 
>>  static int io_close(struct io_kiocb *req, bool force_nonblock)
>>  {
>> +	struct files_struct *files = current->files;
>>  	int ret;
>>  
>>  	req->close.put_file = NULL;
>> -	ret = __close_fd_get_file(req->close.fd, &req->close.put_file);
>> +	spin_lock(&files->file_lock);
>> +	if (req->file->f_op == &io_uring_fops ||
>> +	    req->close.fd == req->ctx->ring_fd) {
>> +		spin_unlock(&files->file_lock);
>> +		return -EBADF;
>> +	}
>> +
>> +	ret = __close_fd_get_file_locked(files, req->close.fd,
>> +						&req->close.put_file);
> 
> Pointless.  By that point req->file might have nothing in common with
> anything in any descriptor table.

How about the below then? Stop using req->file, defer the lookup until
we're in the handler instead. Not sure the 'fd' check makes sense
at this point, but at least we should be consistent in terms of
once we lookup the file and check the f_op.

> Al, carefully _not_ saying anything about the taste and style of the
> entire thing...

It's just a quickie, didn't put much concern into the style and naming
of the locked helper. What do you prefer there? Normally I'd do __,
but it's already that, so... There's only one other user of it, so
we could just make the regular one be close_fd_get_file() and use
the __ prefix for the new locked variant.

But I figured it was more important to get the details right first,
the style is easier to polish.


diff --git a/fs/file.c b/fs/file.c
index c8a4e4c86e55..50ee73b76d17 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -646,18 +646,13 @@ int __close_fd(struct files_struct *files, unsigned fd)
 }
 EXPORT_SYMBOL(__close_fd); /* for ksys_close() */
 
-/*
- * variant of __close_fd that gets a ref on the file for later fput.
- * The caller must ensure that filp_close() called on the file, and then
- * an fput().
- */
-int __close_fd_get_file(unsigned int fd, struct file **res)
+int __close_fd_get_file_locked(struct files_struct *files, unsigned int fd,
+			       struct file **res)
+	__releases(&files->file_lock)
 {
-	struct files_struct *files = current->files;
 	struct file *file;
 	struct fdtable *fdt;
 
-	spin_lock(&files->file_lock);
 	fdt = files_fdtable(files);
 	if (fd >= fdt->max_fds)
 		goto out_unlock;
@@ -677,6 +672,19 @@ int __close_fd_get_file(unsigned int fd, struct file **res)
 	return -ENOENT;
 }
 
+/*
+ * variant of __close_fd that gets a ref on the file for later fput.
+ * The caller must ensure that filp_close() called on the file, and then
+ * an fput().
+ */
+int __close_fd_get_file(unsigned int fd, struct file **res)
+{
+	struct files_struct *files = current->files;
+
+	spin_lock(&files->file_lock);
+	return __close_fd_get_file_locked(files, fd, res);
+}
+
 void do_close_on_exec(struct files_struct *files)
 {
 	unsigned i;
diff --git a/fs/io_uring.c b/fs/io_uring.c
index 979d9f977409..54ef10240bf3 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -786,7 +786,6 @@ static const struct io_op_def io_op_defs[] = {
 		.needs_fs		= 1,
 	},
 	[IORING_OP_CLOSE] = {
-		.needs_file		= 1,
 		.file_table		= 1,
 	},
 	[IORING_OP_FILES_UPDATE] = {
@@ -3399,10 +3398,6 @@ static int io_close_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 		return -EBADF;
 
 	req->close.fd = READ_ONCE(sqe->fd);
-	if (req->file->f_op == &io_uring_fops ||
-	    req->close.fd == req->ctx->ring_fd)
-		return -EBADF;
-
 	return 0;
 }
 
@@ -3430,10 +3425,21 @@ static void io_close_finish(struct io_wq_work **workptr)
 
 static int io_close(struct io_kiocb *req, bool force_nonblock)
 {
+	struct files_struct *files = current->files;
+	struct file *file;
 	int ret;
 
 	req->close.put_file = NULL;
-	ret = __close_fd_get_file(req->close.fd, &req->close.put_file);
+	spin_lock(&files->file_lock);
+	if (req->close.fd == req->ctx->ring_fd)
+		goto badf;
+
+	file = fcheck_files(files, req->close.fd);
+	if (!file || file->f_op == &io_uring_fops)
+		goto badf;
+
+	ret = __close_fd_get_file_locked(files, req->close.fd,
+						&req->close.put_file);
 	if (ret < 0)
 		return ret;
 
@@ -3458,6 +3464,9 @@ static int io_close(struct io_kiocb *req, bool force_nonblock)
 	 */
 	__io_close_finish(req);
 	return 0;
+badf:
+	spin_unlock(&files->file_lock);
+	return -EBADF;
 }
 
 static int io_prep_sfr(struct io_kiocb *req, const struct io_uring_sqe *sqe)
diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h
index f07c55ea0c22..11d19303af46 100644
--- a/include/linux/fdtable.h
+++ b/include/linux/fdtable.h
@@ -122,6 +122,8 @@ extern void __fd_install(struct files_struct *files,
 extern int __close_fd(struct files_struct *files,
 		      unsigned int fd);
 extern int __close_fd_get_file(unsigned int fd, struct file **res);
+extern int __close_fd_get_file_locked(struct files_struct *files,
+				      unsigned int fd, struct file **res);
 
 extern struct kmem_cache *files_cachep;
 

-- 
Jens Axboe


  reply	other threads:[~2020-05-07 23:03 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-07 18:57 [PATCH] fs/io_uring: fix O_PATH fds in openat, openat2, statx Max Kellermann
2020-05-07 18:58 ` Jens Axboe
2020-05-07 19:01   ` Max Kellermann
2020-05-07 19:01 ` Al Viro
2020-05-07 19:05   ` Max Kellermann
2020-05-07 19:05   ` Jens Axboe
2020-05-07 19:12     ` Max Kellermann
2020-05-07 19:29     ` Al Viro
2020-05-07 19:37       ` Max Kellermann
2020-05-07 20:53       ` Jens Axboe
2020-05-07 22:06         ` Al Viro
2020-05-07 22:25           ` Jens Axboe
2020-05-07 22:44             ` Al Viro
2020-05-07 23:03               ` Jens Axboe [this message]
2020-05-07 23:31                 ` Al Viro
2020-05-08  2:28                   ` Jens Axboe
2020-05-08  2:53                     ` Jens Axboe
     [not found]                     ` <20200508152918.12340-1-hdanton@sina.com>
2020-05-08 15:33                       ` Jens Axboe

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=e16125f2-c3ec-f029-c607-19bede54fa17@kernel.dk \
    --to=axboe@kernel.dk \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mk@cm4all.com \
    --cc=stable@vger.kernel.org \
    --cc=viro@zeniv.linux.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).