]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
io_uring: fix double io_uring free
authorPavel Begunkov <asml.silence@gmail.com>
Mon, 21 Dec 2020 18:34:05 +0000 (18:34 +0000)
committerJens Axboe <axboe@kernel.dk>
Wed, 23 Dec 2020 00:14:50 +0000 (17:14 -0700)
Once we created a file for current context during setup, we should not
call io_ring_ctx_wait_and_kill() directly as it'll be done by fput(file)

Cc: stable@vger.kernel.org # 5.10
Reported-by: syzbot+c9937dfb2303a5f18640@syzkaller.appspotmail.com
Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
[axboe: fix unused 'ret' for !CONFIG_UNIX]
Signed-off-by: Jens Axboe <axboe@kernel.dk>
fs/io_uring.c

index 846c635d06200e8dc919dbd75b60ac2c91fe3f9f..7c0b77d49cd2425748aa0fc5263c037e58577cb3 100644 (file)
@@ -9379,55 +9379,52 @@ static int io_allocate_scq_urings(struct io_ring_ctx *ctx,
        return 0;
 }
 
+static int io_uring_install_fd(struct io_ring_ctx *ctx, struct file *file)
+{
+       int ret, fd;
+
+       fd = get_unused_fd_flags(O_RDWR | O_CLOEXEC);
+       if (fd < 0)
+               return fd;
+
+       ret = io_uring_add_task_file(ctx, file);
+       if (ret) {
+               put_unused_fd(fd);
+               return ret;
+       }
+       fd_install(fd, file);
+       return fd;
+}
+
 /*
  * Allocate an anonymous fd, this is what constitutes the application
  * visible backing of an io_uring instance. The application mmaps this
  * fd to gain access to the SQ/CQ ring details. If UNIX sockets are enabled,
  * we have to tie this fd to a socket for file garbage collection purposes.
  */
-static int io_uring_get_fd(struct io_ring_ctx *ctx)
+static struct file *io_uring_get_file(struct io_ring_ctx *ctx)
 {
        struct file *file;
+#if defined(CONFIG_UNIX)
        int ret;
-       int fd;
 
-#if defined(CONFIG_UNIX)
        ret = sock_create_kern(&init_net, PF_UNIX, SOCK_RAW, IPPROTO_IP,
                                &ctx->ring_sock);
        if (ret)
-               return ret;
+               return ERR_PTR(ret);
 #endif
 
-       ret = get_unused_fd_flags(O_RDWR | O_CLOEXEC);
-       if (ret < 0)
-               goto err;
-       fd = ret;
-
        file = anon_inode_getfile("[io_uring]", &io_uring_fops, ctx,
                                        O_RDWR | O_CLOEXEC);
-       if (IS_ERR(file)) {
-               put_unused_fd(fd);
-               ret = PTR_ERR(file);
-               goto err;
-       }
-
 #if defined(CONFIG_UNIX)
-       ctx->ring_sock->file = file;
-#endif
-       ret = io_uring_add_task_file(ctx, file);
-       if (ret) {
-               fput(file);
-               put_unused_fd(fd);
-               goto err;
+       if (IS_ERR(file)) {
+               sock_release(ctx->ring_sock);
+               ctx->ring_sock = NULL;
+       } else {
+               ctx->ring_sock->file = file;
        }
-       fd_install(fd, file);
-       return fd;
-err:
-#if defined(CONFIG_UNIX)
-       sock_release(ctx->ring_sock);
-       ctx->ring_sock = NULL;
 #endif
-       return ret;
+       return file;
 }
 
 static int io_uring_create(unsigned entries, struct io_uring_params *p,
@@ -9435,6 +9432,7 @@ static int io_uring_create(unsigned entries, struct io_uring_params *p,
 {
        struct user_struct *user = NULL;
        struct io_ring_ctx *ctx;
+       struct file *file;
        bool limit_mem;
        int ret;
 
@@ -9582,13 +9580,22 @@ static int io_uring_create(unsigned entries, struct io_uring_params *p,
                goto err;
        }
 
+       file = io_uring_get_file(ctx);
+       if (IS_ERR(file)) {
+               ret = PTR_ERR(file);
+               goto err;
+       }
+
        /*
         * Install ring fd as the very last thing, so we don't risk someone
         * having closed it before we finish setup
         */
-       ret = io_uring_get_fd(ctx);
-       if (ret < 0)
-               goto err;
+       ret = io_uring_install_fd(ctx, file);
+       if (ret < 0) {
+               /* fput will clean it up */
+               fput(file);
+               return ret;
+       }
 
        trace_io_uring_create(ret, ctx, p->sq_entries, p->cq_entries, p->flags);
        return ret;