Message ID | 20200708184711.GA31157@mwanda (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | io_uring: fix a use after free in io_async_task_func() | expand |
On 08/07/2020 21:47, Dan Carpenter wrote: > The "apoll" variable is freed and then used on the next line. We need > to move the free down a few lines. My bad, thanks for spotting that! A comment below > > Fixes: 0be0b0e33b0b ("io_uring: simplify io_async_task_func()") > Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com> > --- > fs/io_uring.c | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > > diff --git a/fs/io_uring.c b/fs/io_uring.c > index 70828e2470e2..f2993070a9e8 100644 > --- a/fs/io_uring.c > +++ b/fs/io_uring.c > @@ -4652,12 +4652,13 @@ static void io_async_task_func(struct callback_head *cb) > /* restore ->work in case we need to retry again */ > if (req->flags & REQ_F_WORK_INITIALIZED) > memcpy(&req->work, &apoll->work, sizeof(req->work)); > - kfree(apoll); __io_req_task_submit() can take some time, e.g. waiting for a mutex, so I'd rather free it before, but save req->poll.canceled in a local var. > > if (!READ_ONCE(apoll->poll.canceled)) > __io_req_task_submit(req); > else > __io_req_task_cancel(req, -ECANCELED); > + > + kfree(apoll); > } > > static int io_async_wake(struct wait_queue_entry *wait, unsigned mode, int sync, >
On 7/8/20 1:01 PM, Pavel Begunkov wrote: > On 08/07/2020 21:47, Dan Carpenter wrote: >> The "apoll" variable is freed and then used on the next line. We need >> to move the free down a few lines. > > My bad, thanks for spotting that! > A comment below > >> >> Fixes: 0be0b0e33b0b ("io_uring: simplify io_async_task_func()") >> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com> >> --- >> fs/io_uring.c | 3 ++- >> 1 file changed, 2 insertions(+), 1 deletion(-) >> >> diff --git a/fs/io_uring.c b/fs/io_uring.c >> index 70828e2470e2..f2993070a9e8 100644 >> --- a/fs/io_uring.c >> +++ b/fs/io_uring.c >> @@ -4652,12 +4652,13 @@ static void io_async_task_func(struct callback_head *cb) >> /* restore ->work in case we need to retry again */ >> if (req->flags & REQ_F_WORK_INITIALIZED) >> memcpy(&req->work, &apoll->work, sizeof(req->work)); >> - kfree(apoll); > > __io_req_task_submit() can take some time, e.g. waiting for a mutex, so > I'd rather free it before, but save req->poll.canceled in a local var. It's 64 bytes of data, really doesn't matter. Let's just keep it simple.
On 7/8/20 12:47 PM, Dan Carpenter wrote: > The "apoll" variable is freed and then used on the next line. We need > to move the free down a few lines. Thanks for spotting this Dan, applied.
On 08/07/2020 22:15, Jens Axboe wrote: > On 7/8/20 12:47 PM, Dan Carpenter wrote: >> The "apoll" variable is freed and then used on the next line. We need >> to move the free down a few lines. > > Thanks for spotting this Dan, applied. I wonder why gcc can't find it... It shouldn't be hard to do after marking free-like functions with an attribute. Are there such tools for the kernel?
On Wed, Jul 08, 2020 at 10:28:51PM +0300, Pavel Begunkov wrote: > On 08/07/2020 22:15, Jens Axboe wrote: > > On 7/8/20 12:47 PM, Dan Carpenter wrote: > >> The "apoll" variable is freed and then used on the next line. We need > >> to move the free down a few lines. > > > > Thanks for spotting this Dan, applied. > > I wonder why gcc can't find it... It shouldn't be hard to do after > marking free-like functions with an attribute. > > Are there such tools for the kernel? GCC doesn't have an __attribute__((free)) yet. Martin Sebor is working on it: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87736 also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94527 (I just confirmed with him on IRC that he's still working on it; it's part of an ongoing larger project)
On 08/07/2020 22:56, Matthew Wilcox wrote: > On Wed, Jul 08, 2020 at 10:28:51PM +0300, Pavel Begunkov wrote: >> On 08/07/2020 22:15, Jens Axboe wrote: >>> On 7/8/20 12:47 PM, Dan Carpenter wrote: >>>> The "apoll" variable is freed and then used on the next line. We need >>>> to move the free down a few lines. >>> >>> Thanks for spotting this Dan, applied. >> >> I wonder why gcc can't find it... It shouldn't be hard to do after >> marking free-like functions with an attribute. >> >> Are there such tools for the kernel? > > GCC doesn't have an __attribute__((free)) yet. Martin Sebor is working on > it: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87736 > also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94527 > > (I just confirmed with him on IRC that he's still working on it; it's > part of an ongoing larger project) Good to know. It looks broader indeed, hence won't probably be here too soon.
diff --git a/fs/io_uring.c b/fs/io_uring.c index 70828e2470e2..f2993070a9e8 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -4652,12 +4652,13 @@ static void io_async_task_func(struct callback_head *cb) /* restore ->work in case we need to retry again */ if (req->flags & REQ_F_WORK_INITIALIZED) memcpy(&req->work, &apoll->work, sizeof(req->work)); - kfree(apoll); if (!READ_ONCE(apoll->poll.canceled)) __io_req_task_submit(req); else __io_req_task_cancel(req, -ECANCELED); + + kfree(apoll); } static int io_async_wake(struct wait_queue_entry *wait, unsigned mode, int sync,
The "apoll" variable is freed and then used on the next line. We need to move the free down a few lines. Fixes: 0be0b0e33b0b ("io_uring: simplify io_async_task_func()") Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com> --- fs/io_uring.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)