diff mbox series

[SRU,Jammy,01/12] io_uring: refactor poll update

Message ID 20220919175810.689086-3-cascardo@canonical.com
State New
Headers show
Series [SRU,Jammy,01/12] io_uring: refactor poll update | expand

Commit Message

Thadeu Lima de Souza Cascardo Sept. 19, 2022, 5:57 p.m. UTC
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(-)

Comments

Kamal Mostafa Sept. 19, 2022, 7:52 p.m. UTC | #1
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 mbox series

Patch

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;
 }