diff options
author | Jens Axboe <axboe@kernel.dk> | 2020-01-28 10:15:23 -0700 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2020-01-28 12:34:55 -0700 |
commit | ae6bb8ad15feed85849a3e73b85689fe69985e1e (patch) | |
tree | 2688dd14217456b2e336bbccce6913678922faad | |
parent | f636a8b59574ae2784f8f2828564d80aac0daf6a (diff) |
io_uring: support using a registered personality for commandsfor-5.6/io_uring-vfs-creds
For personalities previously registered via IORING_REGISTER_PERSONALITY,
allow any command to select them. This is done through setting
sqe->personality to the id returned from registration, and then flagging
sqe->flags with IOSQE_PERSONALITY.
Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r-- | fs/io_uring.c | 25 | ||||
-rw-r--r-- | include/uapi/linux/io_uring.h | 10 |
2 files changed, 32 insertions, 3 deletions
diff --git a/fs/io_uring.c b/fs/io_uring.c index 74185cbabc3d..95a450451782 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -1188,6 +1188,8 @@ static void __io_req_aux_free(struct io_kiocb *req) else fput(req->file); } + if (req->work.creds) + put_cred(req->work.creds); } static void __io_free_req(struct io_kiocb *req) @@ -3975,7 +3977,8 @@ static int io_req_defer_prep(struct io_kiocb *req, mmgrab(current->mm); req->work.mm = current->mm; } - req->work.creds = get_current_cred(); + if (!req->work.creds) + req->work.creds = get_current_cred(); switch (req->opcode) { case IORING_OP_NOP: @@ -4605,11 +4608,13 @@ static inline void io_queue_link_head(struct io_kiocb *req) } #define SQE_VALID_FLAGS (IOSQE_FIXED_FILE|IOSQE_IO_DRAIN|IOSQE_IO_LINK| \ - IOSQE_IO_HARDLINK | IOSQE_ASYNC) + IOSQE_IO_HARDLINK | IOSQE_ASYNC | \ + IOSQE_PERSONALITY) static bool io_submit_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe, struct io_submit_state *state, struct io_kiocb **link) { + const struct cred *old_creds = NULL; struct io_ring_ctx *ctx = req->ctx; unsigned int sqe_flags; int ret; @@ -4621,6 +4626,18 @@ static bool io_submit_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe, ret = -EINVAL; goto err_req; } + + if (sqe_flags & IOSQE_PERSONALITY) { + int id = READ_ONCE(sqe->personality); + + req->work.creds = idr_find(&ctx->personality_idr, id); + if (unlikely(!req->work.creds)) { + ret = -EINVAL; + goto err_req; + } + old_creds = override_creds(req->work.creds); + } + /* same numerical values with corresponding REQ_F_*, safe to copy */ req->flags |= sqe_flags & (IOSQE_IO_DRAIN|IOSQE_IO_HARDLINK| IOSQE_ASYNC); @@ -4630,6 +4647,8 @@ static bool io_submit_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe, err_req: io_cqring_add_event(req, ret); io_double_put_req(req); + if (old_creds) + revert_creds(old_creds); return false; } @@ -4690,6 +4709,8 @@ err_req: } } + if (old_creds) + revert_creds(old_creds); return true; } diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h index b4ccf31db2d1..761abd5c197f 100644 --- a/include/uapi/linux/io_uring.h +++ b/include/uapi/linux/io_uring.h @@ -40,7 +40,12 @@ struct io_uring_sqe { }; __u64 user_data; /* data to be passed back at completion time */ union { - __u16 buf_index; /* index into fixed buffers, if used */ + struct { + /* index into fixed buffers, if used */ + __u16 buf_index; + /* personality to use, if used */ + __u16 personality; + }; __u64 __pad2[3]; }; }; @@ -51,6 +56,7 @@ enum { IOSQE_IO_LINK_BIT, IOSQE_IO_HARDLINK_BIT, IOSQE_ASYNC_BIT, + IOSQE_PERSONALITY_BIT, }; /* @@ -66,6 +72,8 @@ enum { #define IOSQE_IO_HARDLINK (1U << IOSQE_IO_HARDLINK_BIT) /* always go async */ #define IOSQE_ASYNC (1U << IOSQE_ASYNC_BIT) +/* use specified personality */ +#define IOSQE_PERSONALITY (1U << IOSQE_PERSONALITY_BIT) /* * io_uring_setup() flags |