]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
io_uring: refactor poll update
authorPavel Begunkov <asml.silence@gmail.com>
Mon, 19 Sep 2022 17:57:00 +0000 (19:57 +0200)
committerStefan Bader <stefan.bader@canonical.com>
Tue, 20 Sep 2022 09:08:26 +0000 (11:08 +0200)
[ upstream commmit 2bbb146d96f4b45e17d6aeede300796bc1a96d68 ]

Clean up io_poll_update() and unify cancellation paths for remove and
update.

Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
Link: https://lore.kernel.org/r/5937138b6265a1285220e2fab1b28132c1d73ce3.1639605189.git.asml.silence@gmail.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
[pavel: backport]
Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
(cherry picked from commit 040e58f51c0b0a7564b55d27702d6fdc16e476e4 linux-5.15.y)
CVE-2022-3176
Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
Acked-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
fs/io_uring.c

index 9bff14c5e2b265cd56d590110666cd0e26534511..28cd5505626ac427bf433a9ccdda4082b7a38b27 100644 (file)
@@ -5923,61 +5923,51 @@ static int io_poll_update(struct io_kiocb *req, unsigned int issue_flags)
        struct io_ring_ctx *ctx = req->ctx;
        struct io_kiocb *preq;
        bool completing;
-       int ret;
+       int ret2, ret = 0;
 
        spin_lock(&ctx->completion_lock);
        preq = io_poll_find(ctx, req->poll_update.old_user_data, true);
        if (!preq) {
                ret = -ENOENT;
-               goto err;
-       }
-
-       if (!req->poll_update.update_events && !req->poll_update.update_user_data) {
-               completing = true;
-               ret = io_poll_remove_one(preq) ? 0 : -EALREADY;
-               goto err;
+fail:
+               spin_unlock(&ctx->completion_lock);
+               goto out;
        }
-
+       io_poll_remove_double(preq);
        /*
         * Don't allow racy completion with singleshot, as we cannot safely
         * update those. For multishot, if we're racing with completion, just
         * let completion re-add it.
         */
-       io_poll_remove_double(preq);
        completing = !__io_poll_remove_one(preq, &preq->poll, false);
        if (completing && (preq->poll.events & EPOLLONESHOT)) {
                ret = -EALREADY;
-               goto err;
-       }
-       /* we now have a detached poll request. reissue. */
-       ret = 0;
-err:
-       if (ret < 0) {
-               spin_unlock(&ctx->completion_lock);
-               req_set_fail(req);
-               io_req_complete(req, ret);
-               return 0;
-       }
-       /* only mask one event flags, keep behavior flags */
-       if (req->poll_update.update_events) {
-               preq->poll.events &= ~0xffff;
-               preq->poll.events |= req->poll_update.events & 0xffff;
-               preq->poll.events |= IO_POLL_UNMASK;
+               goto fail;
        }
-       if (req->poll_update.update_user_data)
-               preq->user_data = req->poll_update.new_user_data;
        spin_unlock(&ctx->completion_lock);
 
-       /* complete update request, we're done with it */
-       io_req_complete(req, ret);
-
-       if (!completing) {
-               ret = io_poll_add(preq, issue_flags);
-               if (ret < 0) {
-                       req_set_fail(preq);
-                       io_req_complete(preq, ret);
+       if (req->poll_update.update_events || req->poll_update.update_user_data) {
+               /* only mask one event flags, keep behavior flags */
+               if (req->poll_update.update_events) {
+                       preq->poll.events &= ~0xffff;
+                       preq->poll.events |= req->poll_update.events & 0xffff;
+                       preq->poll.events |= IO_POLL_UNMASK;
                }
+               if (req->poll_update.update_user_data)
+                       preq->user_data = req->poll_update.new_user_data;
+
+               ret2 = io_poll_add(preq, issue_flags);
+               /* successfully updated, don't complete poll request */
+               if (!ret2)
+                       goto out;
        }
+       req_set_fail(preq);
+       io_req_complete(preq, -ECANCELED);
+out:
+       if (ret < 0)
+               req_set_fail(req);
+       /* complete update request, we're done with it */
+       io_req_complete(req, ret);
        return 0;
 }