From: Dave Chinner <david@fromorbit.com>
To: Christoph Hellwig <hch@lst.de>
Cc: "Darrick J. Wong" <darrick.wong@oracle.com>,
Chandan Rajendra <chandan@linux.ibm.com>,
linux-xfs@vger.kernel.org
Subject: Re: BUG: iomap_dio_rw() accesses freed memory
Date: Wed, 16 Jan 2019 07:51:41 +1100 [thread overview]
Message-ID: <20190115205141.GL4205@dastard> (raw)
In-Reply-To: <20190115182745.GA12295@lst.de>
On Tue, Jan 15, 2019 at 07:27:45PM +0100, Christoph Hellwig wrote:
> So after review that thread and this thread I still don't really
> see a refcounting problem, just a use after free of the
> wait_for_completion member for fast aio completions.
>
> Chandan, can you give this patch a spin?
>
> diff --git a/fs/iomap.c b/fs/iomap.c
> index cb184ff68680..47362397cb82 100644
> --- a/fs/iomap.c
> +++ b/fs/iomap.c
> @@ -1813,6 +1813,7 @@ iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
> loff_t pos = iocb->ki_pos, start = pos;
> loff_t end = iocb->ki_pos + count - 1, ret = 0;
> unsigned int flags = IOMAP_DIRECT;
> + bool wait_for_completion = is_sync_kiocb(iocb);
> struct blk_plug plug;
> struct iomap_dio *dio;
>
> @@ -1832,7 +1833,6 @@ iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
> dio->end_io = end_io;
> dio->error = 0;
> dio->flags = 0;
> - dio->wait_for_completion = is_sync_kiocb(iocb);
>
> dio->submit.iter = iter;
> dio->submit.waiter = current;
> @@ -1887,7 +1887,7 @@ iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
> dio_warn_stale_pagecache(iocb->ki_filp);
> ret = 0;
>
> - if (iov_iter_rw(iter) == WRITE && !dio->wait_for_completion &&
> + if (iov_iter_rw(iter) == WRITE && !wait_for_completion &&
> !inode->i_sb->s_dio_done_wq) {
> ret = sb_init_dio_done_wq(inode->i_sb);
> if (ret < 0)
> @@ -1903,7 +1903,7 @@ iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
> if (ret <= 0) {
> /* magic error code to fall back to buffered I/O */
> if (ret == -ENOTBLK) {
> - dio->wait_for_completion = true;
> + wait_for_completion = true;
> ret = 0;
> }
> break;
> @@ -1925,8 +1925,24 @@ iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
> if (dio->flags & IOMAP_DIO_WRITE_FUA)
> dio->flags &= ~IOMAP_DIO_NEED_SYNC;
>
> + /*
> + * We are about to drop our additional submission reference, which
> + * might be the last reference to the dio. There are three three
> + * different ways we can progress here:
> + *
> + * (a) If this is the last reference we will always complete and free
> + * the dio ourselves. right here.
> + * (b) If this is not the last reference, and we serve an asynchronous
> + * iocb, we must never touch the dio after the decrement, the
> + * I/O completion handler will complete and free it.
> + * (c) If this is not the last reference, but we serve a synchronous
> + * iocb, the I/O completion handler will wake us up on the drop
> + * of the final reference, and we will complete and free it here
> + * after we got woken by the I/O completion handler.
> + */
> + dio->wait_for_completion = wait_for_completion;
> if (!atomic_dec_and_test(&dio->ref)) {
Atomic operations don't imply a memory barrier for dependent data,
right? So in completion we do:
if (atomic_dec_and_test(&dio->ref)) {
if (dio->wait_for_completion) {
/* do wakeup */
} else ....
So if we get:
CPU 0 (submission) CPU 1 (completion)
set dio->wfc
dec dio->ref, val = 1 dec dio->ref, val = 0
enter wait loop check dio->wfc
Where's the memory barrier to ensure that CPU 1 sees the value
that CPU 0 set in dio->wait_for_completion?
Cheers,
Dave.
--
Dave Chinner
david@fromorbit.com
next prev parent reply other threads:[~2019-01-15 20:51 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-01-10 10:17 BUG: iomap_dio_rw() accesses freed memory Chandan Rajendra
2019-01-10 14:25 ` Christoph Hellwig
2019-01-10 16:49 ` Chandan Rajendra
2019-01-10 17:09 ` Darrick J. Wong
2019-01-15 18:27 ` Christoph Hellwig
2019-01-15 20:51 ` Dave Chinner [this message]
2019-01-15 21:09 ` Christoph Hellwig
2019-01-15 23:18 ` Dave Chinner
2019-01-15 23:24 ` Darrick J. Wong
2019-01-16 5:59 ` Chandan Rajendra
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190115205141.GL4205@dastard \
--to=david@fromorbit.com \
--cc=chandan@linux.ibm.com \
--cc=darrick.wong@oracle.com \
--cc=hch@lst.de \
--cc=linux-xfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.