Commit 1d3962ae authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'io_uring-5.7-2020-05-08' of git://git.kernel.dk/linux-block

Pull io_uring fixes from Jens Axboe:

 - Fix finish_wait() balancing in file cancelation (Xiaoguang)

 - Ensure early cleanup of resources in ring map failure (Xiaoguang)

 - Ensure IORING_OP_SLICE does the right file mode checks (Pavel)

 - Remove file opening from openat/openat2/statx, it's not needed and
   messes with O_PATH

* tag 'io_uring-5.7-2020-05-08' of git://git.kernel.dk/linux-block:
  io_uring: don't use 'fd' for openat/openat2/statx
  splice: move f_mode checks to do_{splice,tee}()
  io_uring: handle -EFAULT properly in io_uring_setup()
  io_uring: fix mismatched finish_wait() calls in io_uring_cancel_files()
parents d5eeab8d 63ff8223
...@@ -680,8 +680,6 @@ struct io_op_def { ...@@ -680,8 +680,6 @@ struct io_op_def {
unsigned needs_mm : 1; unsigned needs_mm : 1;
/* needs req->file assigned */ /* needs req->file assigned */
unsigned needs_file : 1; unsigned needs_file : 1;
/* needs req->file assigned IFF fd is >= 0 */
unsigned fd_non_neg : 1;
/* hash wq insertion if file is a regular file */ /* hash wq insertion if file is a regular file */
unsigned hash_reg_file : 1; unsigned hash_reg_file : 1;
/* unbound wq insertion if file is a non-regular file */ /* unbound wq insertion if file is a non-regular file */
...@@ -784,8 +782,6 @@ static const struct io_op_def io_op_defs[] = { ...@@ -784,8 +782,6 @@ static const struct io_op_def io_op_defs[] = {
.needs_file = 1, .needs_file = 1,
}, },
[IORING_OP_OPENAT] = { [IORING_OP_OPENAT] = {
.needs_file = 1,
.fd_non_neg = 1,
.file_table = 1, .file_table = 1,
.needs_fs = 1, .needs_fs = 1,
}, },
...@@ -799,8 +795,6 @@ static const struct io_op_def io_op_defs[] = { ...@@ -799,8 +795,6 @@ static const struct io_op_def io_op_defs[] = {
}, },
[IORING_OP_STATX] = { [IORING_OP_STATX] = {
.needs_mm = 1, .needs_mm = 1,
.needs_file = 1,
.fd_non_neg = 1,
.needs_fs = 1, .needs_fs = 1,
.file_table = 1, .file_table = 1,
}, },
...@@ -837,8 +831,6 @@ static const struct io_op_def io_op_defs[] = { ...@@ -837,8 +831,6 @@ static const struct io_op_def io_op_defs[] = {
.buffer_select = 1, .buffer_select = 1,
}, },
[IORING_OP_OPENAT2] = { [IORING_OP_OPENAT2] = {
.needs_file = 1,
.fd_non_neg = 1,
.file_table = 1, .file_table = 1,
.needs_fs = 1, .needs_fs = 1,
}, },
...@@ -5368,15 +5360,6 @@ static void io_wq_submit_work(struct io_wq_work **workptr) ...@@ -5368,15 +5360,6 @@ static void io_wq_submit_work(struct io_wq_work **workptr)
io_steal_work(req, workptr); io_steal_work(req, workptr);
} }
static int io_req_needs_file(struct io_kiocb *req, int fd)
{
if (!io_op_defs[req->opcode].needs_file)
return 0;
if ((fd == -1 || fd == AT_FDCWD) && io_op_defs[req->opcode].fd_non_neg)
return 0;
return 1;
}
static inline struct file *io_file_from_index(struct io_ring_ctx *ctx, static inline struct file *io_file_from_index(struct io_ring_ctx *ctx,
int index) int index)
{ {
...@@ -5414,14 +5397,11 @@ static int io_file_get(struct io_submit_state *state, struct io_kiocb *req, ...@@ -5414,14 +5397,11 @@ static int io_file_get(struct io_submit_state *state, struct io_kiocb *req,
} }
static int io_req_set_file(struct io_submit_state *state, struct io_kiocb *req, static int io_req_set_file(struct io_submit_state *state, struct io_kiocb *req,
int fd, unsigned int flags) int fd)
{ {
bool fixed; bool fixed;
if (!io_req_needs_file(req, fd)) fixed = (req->flags & REQ_F_FIXED_FILE) != 0;
return 0;
fixed = (flags & IOSQE_FIXED_FILE);
if (unlikely(!fixed && req->needs_fixed_file)) if (unlikely(!fixed && req->needs_fixed_file))
return -EBADF; return -EBADF;
...@@ -5798,7 +5778,7 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req, ...@@ -5798,7 +5778,7 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
struct io_submit_state *state, bool async) struct io_submit_state *state, bool async)
{ {
unsigned int sqe_flags; unsigned int sqe_flags;
int id, fd; int id;
/* /*
* All io need record the previous position, if LINK vs DARIN, * All io need record the previous position, if LINK vs DARIN,
...@@ -5850,8 +5830,10 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req, ...@@ -5850,8 +5830,10 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
IOSQE_ASYNC | IOSQE_FIXED_FILE | IOSQE_ASYNC | IOSQE_FIXED_FILE |
IOSQE_BUFFER_SELECT | IOSQE_IO_LINK); IOSQE_BUFFER_SELECT | IOSQE_IO_LINK);
fd = READ_ONCE(sqe->fd); if (!io_op_defs[req->opcode].needs_file)
return io_req_set_file(state, req, fd, sqe_flags); return 0;
return io_req_set_file(state, req, READ_ONCE(sqe->fd));
} }
static int io_submit_sqes(struct io_ring_ctx *ctx, unsigned int nr, static int io_submit_sqes(struct io_ring_ctx *ctx, unsigned int nr,
...@@ -7360,11 +7342,9 @@ static int io_uring_release(struct inode *inode, struct file *file) ...@@ -7360,11 +7342,9 @@ static int io_uring_release(struct inode *inode, struct file *file)
static void io_uring_cancel_files(struct io_ring_ctx *ctx, static void io_uring_cancel_files(struct io_ring_ctx *ctx,
struct files_struct *files) struct files_struct *files)
{ {
struct io_kiocb *req;
DEFINE_WAIT(wait);
while (!list_empty_careful(&ctx->inflight_list)) { while (!list_empty_careful(&ctx->inflight_list)) {
struct io_kiocb *cancel_req = NULL; struct io_kiocb *cancel_req = NULL, *req;
DEFINE_WAIT(wait);
spin_lock_irq(&ctx->inflight_lock); spin_lock_irq(&ctx->inflight_lock);
list_for_each_entry(req, &ctx->inflight_list, inflight_entry) { list_for_each_entry(req, &ctx->inflight_list, inflight_entry) {
...@@ -7404,6 +7384,7 @@ static void io_uring_cancel_files(struct io_ring_ctx *ctx, ...@@ -7404,6 +7384,7 @@ static void io_uring_cancel_files(struct io_ring_ctx *ctx,
*/ */
if (refcount_sub_and_test(2, &cancel_req->refs)) { if (refcount_sub_and_test(2, &cancel_req->refs)) {
io_put_req(cancel_req); io_put_req(cancel_req);
finish_wait(&ctx->inflight_wait, &wait);
continue; continue;
} }
} }
...@@ -7411,8 +7392,8 @@ static void io_uring_cancel_files(struct io_ring_ctx *ctx, ...@@ -7411,8 +7392,8 @@ static void io_uring_cancel_files(struct io_ring_ctx *ctx,
io_wq_cancel_work(ctx->io_wq, &cancel_req->work); io_wq_cancel_work(ctx->io_wq, &cancel_req->work);
io_put_req(cancel_req); io_put_req(cancel_req);
schedule(); schedule();
}
finish_wait(&ctx->inflight_wait, &wait); finish_wait(&ctx->inflight_wait, &wait);
}
} }
static int io_uring_flush(struct file *file, void *data) static int io_uring_flush(struct file *file, void *data)
...@@ -7761,7 +7742,8 @@ static int io_uring_get_fd(struct io_ring_ctx *ctx) ...@@ -7761,7 +7742,8 @@ static int io_uring_get_fd(struct io_ring_ctx *ctx)
return ret; return ret;
} }
static int io_uring_create(unsigned entries, struct io_uring_params *p) static int io_uring_create(unsigned entries, struct io_uring_params *p,
struct io_uring_params __user *params)
{ {
struct user_struct *user = NULL; struct user_struct *user = NULL;
struct io_ring_ctx *ctx; struct io_ring_ctx *ctx;
...@@ -7853,6 +7835,14 @@ static int io_uring_create(unsigned entries, struct io_uring_params *p) ...@@ -7853,6 +7835,14 @@ static int io_uring_create(unsigned entries, struct io_uring_params *p)
p->cq_off.overflow = offsetof(struct io_rings, cq_overflow); p->cq_off.overflow = offsetof(struct io_rings, cq_overflow);
p->cq_off.cqes = offsetof(struct io_rings, cqes); p->cq_off.cqes = offsetof(struct io_rings, cqes);
p->features = IORING_FEAT_SINGLE_MMAP | IORING_FEAT_NODROP |
IORING_FEAT_SUBMIT_STABLE | IORING_FEAT_RW_CUR_POS |
IORING_FEAT_CUR_PERSONALITY | IORING_FEAT_FAST_POLL;
if (copy_to_user(params, p, sizeof(*p))) {
ret = -EFAULT;
goto err;
}
/* /*
* Install ring fd as the very last thing, so we don't risk someone * Install ring fd as the very last thing, so we don't risk someone
* having closed it before we finish setup * having closed it before we finish setup
...@@ -7861,9 +7851,6 @@ static int io_uring_create(unsigned entries, struct io_uring_params *p) ...@@ -7861,9 +7851,6 @@ static int io_uring_create(unsigned entries, struct io_uring_params *p)
if (ret < 0) if (ret < 0)
goto err; goto err;
p->features = IORING_FEAT_SINGLE_MMAP | IORING_FEAT_NODROP |
IORING_FEAT_SUBMIT_STABLE | IORING_FEAT_RW_CUR_POS |
IORING_FEAT_CUR_PERSONALITY | IORING_FEAT_FAST_POLL;
trace_io_uring_create(ret, ctx, p->sq_entries, p->cq_entries, p->flags); trace_io_uring_create(ret, ctx, p->sq_entries, p->cq_entries, p->flags);
return ret; return ret;
err: err:
...@@ -7879,7 +7866,6 @@ static int io_uring_create(unsigned entries, struct io_uring_params *p) ...@@ -7879,7 +7866,6 @@ static int io_uring_create(unsigned entries, struct io_uring_params *p)
static long io_uring_setup(u32 entries, struct io_uring_params __user *params) static long io_uring_setup(u32 entries, struct io_uring_params __user *params)
{ {
struct io_uring_params p; struct io_uring_params p;
long ret;
int i; int i;
if (copy_from_user(&p, params, sizeof(p))) if (copy_from_user(&p, params, sizeof(p)))
...@@ -7894,14 +7880,7 @@ static long io_uring_setup(u32 entries, struct io_uring_params __user *params) ...@@ -7894,14 +7880,7 @@ static long io_uring_setup(u32 entries, struct io_uring_params __user *params)
IORING_SETUP_CLAMP | IORING_SETUP_ATTACH_WQ)) IORING_SETUP_CLAMP | IORING_SETUP_ATTACH_WQ))
return -EINVAL; return -EINVAL;
ret = io_uring_create(entries, &p); return io_uring_create(entries, &p, params);
if (ret < 0)
return ret;
if (copy_to_user(params, &p, sizeof(p)))
return -EFAULT;
return ret;
} }
SYSCALL_DEFINE2(io_uring_setup, u32, entries, SYSCALL_DEFINE2(io_uring_setup, u32, entries,
......
...@@ -1118,6 +1118,10 @@ long do_splice(struct file *in, loff_t __user *off_in, ...@@ -1118,6 +1118,10 @@ long do_splice(struct file *in, loff_t __user *off_in,
loff_t offset; loff_t offset;
long ret; long ret;
if (unlikely(!(in->f_mode & FMODE_READ) ||
!(out->f_mode & FMODE_WRITE)))
return -EBADF;
ipipe = get_pipe_info(in); ipipe = get_pipe_info(in);
opipe = get_pipe_info(out); opipe = get_pipe_info(out);
...@@ -1125,12 +1129,6 @@ long do_splice(struct file *in, loff_t __user *off_in, ...@@ -1125,12 +1129,6 @@ long do_splice(struct file *in, loff_t __user *off_in,
if (off_in || off_out) if (off_in || off_out)
return -ESPIPE; return -ESPIPE;
if (!(in->f_mode & FMODE_READ))
return -EBADF;
if (!(out->f_mode & FMODE_WRITE))
return -EBADF;
/* Splicing to self would be fun, but... */ /* Splicing to self would be fun, but... */
if (ipipe == opipe) if (ipipe == opipe)
return -EINVAL; return -EINVAL;
...@@ -1153,9 +1151,6 @@ long do_splice(struct file *in, loff_t __user *off_in, ...@@ -1153,9 +1151,6 @@ long do_splice(struct file *in, loff_t __user *off_in,
offset = out->f_pos; offset = out->f_pos;
} }
if (unlikely(!(out->f_mode & FMODE_WRITE)))
return -EBADF;
if (unlikely(out->f_flags & O_APPEND)) if (unlikely(out->f_flags & O_APPEND))
return -EINVAL; return -EINVAL;
...@@ -1440,16 +1435,12 @@ SYSCALL_DEFINE6(splice, int, fd_in, loff_t __user *, off_in, ...@@ -1440,16 +1435,12 @@ SYSCALL_DEFINE6(splice, int, fd_in, loff_t __user *, off_in,
error = -EBADF; error = -EBADF;
in = fdget(fd_in); in = fdget(fd_in);
if (in.file) { if (in.file) {
if (in.file->f_mode & FMODE_READ) {
out = fdget(fd_out); out = fdget(fd_out);
if (out.file) { if (out.file) {
if (out.file->f_mode & FMODE_WRITE) error = do_splice(in.file, off_in, out.file, off_out,
error = do_splice(in.file, off_in,
out.file, off_out,
len, flags); len, flags);
fdput(out); fdput(out);
} }
}
fdput(in); fdput(in);
} }
return error; return error;
...@@ -1770,6 +1761,10 @@ static long do_tee(struct file *in, struct file *out, size_t len, ...@@ -1770,6 +1761,10 @@ static long do_tee(struct file *in, struct file *out, size_t len,
struct pipe_inode_info *opipe = get_pipe_info(out); struct pipe_inode_info *opipe = get_pipe_info(out);
int ret = -EINVAL; int ret = -EINVAL;
if (unlikely(!(in->f_mode & FMODE_READ) ||
!(out->f_mode & FMODE_WRITE)))
return -EBADF;
/* /*
* Duplicate the contents of ipipe to opipe without actually * Duplicate the contents of ipipe to opipe without actually
* copying the data. * copying the data.
...@@ -1795,7 +1790,7 @@ static long do_tee(struct file *in, struct file *out, size_t len, ...@@ -1795,7 +1790,7 @@ static long do_tee(struct file *in, struct file *out, size_t len,
SYSCALL_DEFINE4(tee, int, fdin, int, fdout, size_t, len, unsigned int, flags) SYSCALL_DEFINE4(tee, int, fdin, int, fdout, size_t, len, unsigned int, flags)
{ {
struct fd in; struct fd in, out;
int error; int error;
if (unlikely(flags & ~SPLICE_F_ALL)) if (unlikely(flags & ~SPLICE_F_ALL))
...@@ -1807,15 +1802,11 @@ SYSCALL_DEFINE4(tee, int, fdin, int, fdout, size_t, len, unsigned int, flags) ...@@ -1807,15 +1802,11 @@ SYSCALL_DEFINE4(tee, int, fdin, int, fdout, size_t, len, unsigned int, flags)
error = -EBADF; error = -EBADF;
in = fdget(fdin); in = fdget(fdin);
if (in.file) { if (in.file) {
if (in.file->f_mode & FMODE_READ) { out = fdget(fdout);
struct fd out = fdget(fdout);
if (out.file) { if (out.file) {
if (out.file->f_mode & FMODE_WRITE) error = do_tee(in.file, out.file, len, flags);
error = do_tee(in.file, out.file,
len, flags);
fdput(out); fdput(out);
} }
}
fdput(in); fdput(in);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment