Message ID | 20220518043020.1089267-2-cascardo@canonical.com |
---|---|
State | New |
Headers | show |
Series | CVE-2022-1116 | expand |
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;
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 --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;