io_uring: support using a registered personality for commands for-5.6/io_uring-vfs-creds
authorJens Axboe <axboe@kernel.dk>
Tue, 28 Jan 2020 17:15:23 +0000 (10:15 -0700)
committerJens Axboe <axboe@kernel.dk>
Tue, 28 Jan 2020 19:34:55 +0000 (12:34 -0700)
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>
fs/io_uring.c
include/uapi/linux/io_uring.h

index 74185cbabc3dd796dfe75c609ddb71fc6b5fc76e..95a450451782f02466a6cd8118e86f599ab12f7d 100644 (file)
@@ -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;
 }
 
index b4ccf31db2d169383c9f6fe1c12e17899f2941df..761abd5c197fc1acd5a264f7d85cab6889c75941 100644 (file)
@@ -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