[PATCH 5.6 73/73] io_uring: statx must grab the file table for valid fd

Greg Kroah-Hartman
2020-05-04T18:07:58Z

From: Jens Axboe <axboe@kernel.dk>

commit 5b0bbee4732cbd58aa98213d4c11a366356bba3d upstream.

Clay reports that OP_STATX fails for a test case with a valid fd
and empty path:

-- Test 0: statx:fd 3: SUCCEED, file mode 100755
-- Test 1: statx:path ./uring_statx: SUCCEED, file mode 100755
-- Test 2: io_uring_statx:fd 3: FAIL, errno 9: Bad file descriptor
-- Test 3: io_uring_statx:path ./uring_statx: SUCCEED, file mode 100755

This is due to statx not grabbing the process file table, hence we can't
lookup the fd in async context. If the fd is valid, ensure that we grab
the file table so we can grab the file from async context.

Cc: stable@vger.kernel.org # v5.6
Reported-by: Clay Harris <bugs@claycon.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

---
fs/io_uring.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)

--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -479,6 +479,7 @@ enum {
REQ_F_COMP_LOCKED_BIT,
REQ_F_NEED_CLEANUP_BIT,
REQ_F_OVERFLOW_BIT,
+ REQ_F_NO_FILE_TABLE_BIT,
};

enum {
@@ -521,6 +522,8 @@ enum {
REQ_F_NEED_CLEANUP = BIT(REQ_F_NEED_CLEANUP_BIT),
/* in overflow list */
REQ_F_OVERFLOW = BIT(REQ_F_OVERFLOW_BIT),
+ /* doesn't need file table for this request */
+ REQ_F_NO_FILE_TABLE = BIT(REQ_F_NO_FILE_TABLE_BIT),
};

/*
@@ -711,6 +714,7 @@ static const struct io_op_def io_op_defs
.needs_file = 1,
.fd_non_neg = 1,
.needs_fs = 1,
+ .file_table = 1,
},
[IORING_OP_READ] = {
.needs_mm = 1,
@@ -2843,8 +2847,12 @@ static int io_statx(struct io_kiocb *req
struct kstat stat;
int ret;

- if (force_nonblock)
+ if (force_nonblock) {
+ /* only need file table for an actual valid fd */
+ if (ctx->dfd == -1 || ctx->dfd == AT_FDCWD)
+ req->flags |= REQ_F_NO_FILE_TABLE;
return -EAGAIN;
+ }

if (vfs_stat_set_lookup_flags(&lookup_flags, ctx->how.flags))
return -EINVAL;
@@ -4632,7 +4640,7 @@ static int io_grab_files(struct io_kiocb
int ret = -EBADF;
struct io_ring_ctx *ctx = req->ctx;

- if (req->work.files)
+ if (req->work.files || (req->flags & REQ_F_NO_FILE_TABLE))
return 0;
if (!ctx->ring_file)
return -EBADF;