diff mbox series

[SRU,Focal,1/1] io_uring: fix fs->users overflow

Message ID 20220518043020.1089267-2-cascardo@canonical.com
State New
Headers show
Series CVE-2022-1116 | expand

Commit Message

Thadeu Lima de Souza Cascardo May 18, 2022, 4:30 a.m. UTC
From: Pavel Begunkov <asml.silence@gmail.com>

There is a bunch of cases where we can grab req->fs but not put it, this
can be used to cause a controllable overflow with further implications.
Release req->fs in the request free path and make sure we zero the field
to be sure we don't do it twice.

Fixes: cac68d12c531 ("io_uring: grab ->fs as part of async offload")
Reported-by: Bing-Jhong Billy Jheng <billy@starlabs.sg>
Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
(cherry picked from commit 1a623d361ffe5cecd4244a02f449528416360038 linux-5.4.y)
CVE-2022-1116
Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
---
 fs/io_uring.c | 28 ++++++++++++++++++----------
 1 file changed, 18 insertions(+), 10 deletions(-)

Comments

Stefan Bader May 18, 2022, 9:05 a.m. UTC | #1
On 18.05.22 06:30, Thadeu Lima de Souza Cascardo wrote:
> From: Pavel Begunkov <asml.silence@gmail.com>
> 
> There is a bunch of cases where we can grab req->fs but not put it, this
> can be used to cause a controllable overflow with further implications.
> Release req->fs in the request free path and make sure we zero the field
> to be sure we don't do it twice.
> 
> Fixes: cac68d12c531 ("io_uring: grab ->fs as part of async offload")
> Reported-by: Bing-Jhong Billy Jheng <billy@starlabs.sg>
> Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> (cherry picked from commit 1a623d361ffe5cecd4244a02f449528416360038 linux-5.4.y)
> CVE-2022-1116
> Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
> ---
>   fs/io_uring.c | 28 ++++++++++++++++++----------
>   1 file changed, 18 insertions(+), 10 deletions(-)
> 
> diff --git a/fs/io_uring.c b/fs/io_uring.c
> index 478df7e10767..e73969fa96bc 100644
> --- a/fs/io_uring.c
> +++ b/fs/io_uring.c
> @@ -438,6 +438,22 @@ static struct io_ring_ctx *io_ring_ctx_alloc(struct io_uring_params *p)
>   	return ctx;
>   }
>   
> +static void io_req_put_fs(struct io_kiocb *req)
> +{
> +	struct fs_struct *fs = req->fs;
> +
> +	if (!fs)
> +		return;
> +
> +	spin_lock(&req->fs->lock);
> +	if (--fs->users)
> +		fs = NULL;
> +	spin_unlock(&req->fs->lock);
> +	if (fs)
> +		free_fs_struct(fs);
> +	req->fs = NULL;
> +}
> +
>   static inline bool __io_sequence_defer(struct io_ring_ctx *ctx,
>   				       struct io_kiocb *req)
>   {
> @@ -695,6 +711,7 @@ static void io_free_req_many(struct io_ring_ctx *ctx, void **reqs, int *nr)
>   
>   static void __io_free_req(struct io_kiocb *req)
>   {
> +	io_req_put_fs(req);
>   	if (req->file && !(req->flags & REQ_F_FIXED_FILE))
>   		fput(req->file);
>   	percpu_ref_put(&req->ctx->refs);
> @@ -1701,16 +1718,7 @@ static int io_send_recvmsg(struct io_kiocb *req, const struct io_uring_sqe *sqe,
>   			ret = -EINTR;
>   	}
>   
> -	if (req->fs) {
> -		struct fs_struct *fs = req->fs;
> -
> -		spin_lock(&req->fs->lock);
> -		if (--fs->users)
> -			fs = NULL;
> -		spin_unlock(&req->fs->lock);
> -		if (fs)
> -			free_fs_struct(fs);
> -	}
> +	io_req_put_fs(req);
>   	io_cqring_add_event(req->ctx, sqe->user_data, ret);
>   	io_put_req(req);
>   	return 0;
Stefan Bader May 18, 2022, 1:58 p.m. UTC | #2
On 18.05.22 06:30, Thadeu Lima de Souza Cascardo wrote:
> From: Pavel Begunkov <asml.silence@gmail.com>
> 
> There is a bunch of cases where we can grab req->fs but not put it, this
> can be used to cause a controllable overflow with further implications.
> Release req->fs in the request free path and make sure we zero the field
> to be sure we don't do it twice.
> 
> Fixes: cac68d12c531 ("io_uring: grab ->fs as part of async offload")
> Reported-by: Bing-Jhong Billy Jheng <billy@starlabs.sg>
> Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> (cherry picked from commit 1a623d361ffe5cecd4244a02f449528416360038 linux-5.4.y)
> CVE-2022-1116
> Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com > ---

Applied to focal:linux (re-spin). Thanks.

-Stefan

>   fs/io_uring.c | 28 ++++++++++++++++++----------
>   1 file changed, 18 insertions(+), 10 deletions(-)
> 
> diff --git a/fs/io_uring.c b/fs/io_uring.c
> index 478df7e10767..e73969fa96bc 100644
> --- a/fs/io_uring.c
> +++ b/fs/io_uring.c
> @@ -438,6 +438,22 @@ static struct io_ring_ctx *io_ring_ctx_alloc(struct io_uring_params *p)
>   	return ctx;
>   }
>   
> +static void io_req_put_fs(struct io_kiocb *req)
> +{
> +	struct fs_struct *fs = req->fs;
> +
> +	if (!fs)
> +		return;
> +
> +	spin_lock(&req->fs->lock);
> +	if (--fs->users)
> +		fs = NULL;
> +	spin_unlock(&req->fs->lock);
> +	if (fs)
> +		free_fs_struct(fs);
> +	req->fs = NULL;
> +}
> +
>   static inline bool __io_sequence_defer(struct io_ring_ctx *ctx,
>   				       struct io_kiocb *req)
>   {
> @@ -695,6 +711,7 @@ static void io_free_req_many(struct io_ring_ctx *ctx, void **reqs, int *nr)
>   
>   static void __io_free_req(struct io_kiocb *req)
>   {
> +	io_req_put_fs(req);
>   	if (req->file && !(req->flags & REQ_F_FIXED_FILE))
>   		fput(req->file);
>   	percpu_ref_put(&req->ctx->refs);
> @@ -1701,16 +1718,7 @@ static int io_send_recvmsg(struct io_kiocb *req, const struct io_uring_sqe *sqe,
>   			ret = -EINTR;
>   	}
>   
> -	if (req->fs) {
> -		struct fs_struct *fs = req->fs;
> -
> -		spin_lock(&req->fs->lock);
> -		if (--fs->users)
> -			fs = NULL;
> -		spin_unlock(&req->fs->lock);
> -		if (fs)
> -			free_fs_struct(fs);
> -	}
> +	io_req_put_fs(req);
>   	io_cqring_add_event(req->ctx, sqe->user_data, ret);
>   	io_put_req(req);
>   	return 0;
diff mbox series

Patch

diff --git a/fs/io_uring.c b/fs/io_uring.c
index 478df7e10767..e73969fa96bc 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -438,6 +438,22 @@  static struct io_ring_ctx *io_ring_ctx_alloc(struct io_uring_params *p)
 	return ctx;
 }
 
+static void io_req_put_fs(struct io_kiocb *req)
+{
+	struct fs_struct *fs = req->fs;
+
+	if (!fs)
+		return;
+
+	spin_lock(&req->fs->lock);
+	if (--fs->users)
+		fs = NULL;
+	spin_unlock(&req->fs->lock);
+	if (fs)
+		free_fs_struct(fs);
+	req->fs = NULL;
+}
+
 static inline bool __io_sequence_defer(struct io_ring_ctx *ctx,
 				       struct io_kiocb *req)
 {
@@ -695,6 +711,7 @@  static void io_free_req_many(struct io_ring_ctx *ctx, void **reqs, int *nr)
 
 static void __io_free_req(struct io_kiocb *req)
 {
+	io_req_put_fs(req);
 	if (req->file && !(req->flags & REQ_F_FIXED_FILE))
 		fput(req->file);
 	percpu_ref_put(&req->ctx->refs);
@@ -1701,16 +1718,7 @@  static int io_send_recvmsg(struct io_kiocb *req, const struct io_uring_sqe *sqe,
 			ret = -EINTR;
 	}
 
-	if (req->fs) {
-		struct fs_struct *fs = req->fs;
-
-		spin_lock(&req->fs->lock);
-		if (--fs->users)
-			fs = NULL;
-		spin_unlock(&req->fs->lock);
-		if (fs)
-			free_fs_struct(fs);
-	}
+	io_req_put_fs(req);
 	io_cqring_add_event(req->ctx, sqe->user_data, ret);
 	io_put_req(req);
 	return 0;