Message ID | 20220919175810.689086-3-cascardo@canonical.com |
---|---|
State | New |
Headers | show |
Series | [SRU,Jammy,01/12] io_uring: refactor poll update | expand |
All 12 cherry picks from upstream stable, LGTM. Acked-by: Kamal Mostafa <kamal@canonical.com> -Kamal On Mon, Sep 19, 2022 at 02:57:59PM -0300, Thadeu Lima de Souza Cascardo wrote: > From: Pavel Begunkov <asml.silence@gmail.com> > > [ 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> > --- > fs/io_uring.c | 62 +++++++++++++++++++++------------------------------ > 1 file changed, 26 insertions(+), 36 deletions(-) > > diff --git a/fs/io_uring.c b/fs/io_uring.c > index 9bff14c5e2b2..28cd5505626a 100644 > --- a/fs/io_uring.c > +++ b/fs/io_uring.c > @@ -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; > } > > -- > 2.34.1 > > > -- > kernel-team mailing list > kernel-team@lists.ubuntu.com > https://lists.ubuntu.com/mailman/listinfo/kernel-team
diff --git a/fs/io_uring.c b/fs/io_uring.c index 9bff14c5e2b2..28cd5505626a 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -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; }