linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] aio: Fix use after free bugs
@ 2011-02-15 12:59 Jan Kara
  2011-02-15 13:55 ` Jeff Moyer
  0 siblings, 1 reply; 5+ messages in thread
From: Jan Kara @ 2011-02-15 12:59 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel, LKML


  Hi Al,

  The following two patches fix use after free bugs in AIO code.  I'm not
completely sure you're the right one to merge these but hopefully yes ;).
Could you please merge them? Thanks.

								Honza

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 0/2] aio: Fix use after free bugs
  2011-02-15 12:59 [PATCH 0/2] aio: Fix use after free bugs Jan Kara
@ 2011-02-15 13:55 ` Jeff Moyer
  0 siblings, 0 replies; 5+ messages in thread
From: Jeff Moyer @ 2011-02-15 13:55 UTC (permalink / raw)
  To: Jan Kara; +Cc: Al Viro, linux-fsdevel, LKML

Jan Kara <jack@suse.cz> writes:

>   Hi Al,
>
>   The following two patches fix use after free bugs in AIO code.  I'm not
> completely sure you're the right one to merge these but hopefully yes ;).
> Could you please merge them? Thanks.

I've always pushed aio changes through akpm, fwiw.

Cheers,
Jeff

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 0/2] aio: Fix use after free bugs
@ 2011-02-21 15:58 Jan Kara
  2011-02-21 15:58 ` [PATCH 1/2] fs: Fix aio rcu ioctx lookup Jan Kara
  2011-02-21 15:58 ` [PATCH 2/2] fs: Fix race between io_destroy() and io_submit() in AIO Jan Kara
  0 siblings, 2 replies; 5+ messages in thread
From: Jan Kara @ 2011-02-21 15:58 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Jeff Moyer, Nick Piggin, Milton Miller, linux-fsdevel, LKML


  Hi Andrew,

  The following two patches fix use after free bugs in AIO code.  Could you
please merge them? Thanks.

								Honza

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] fs: Fix aio rcu ioctx lookup
  2011-02-21 15:58 [PATCH 0/2] aio: Fix use after free bugs Jan Kara
@ 2011-02-21 15:58 ` Jan Kara
  2011-02-21 15:58 ` [PATCH 2/2] fs: Fix race between io_destroy() and io_submit() in AIO Jan Kara
  1 sibling, 0 replies; 5+ messages in thread
From: Jan Kara @ 2011-02-21 15:58 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Jeff Moyer, Nick Piggin, Milton Miller, linux-fsdevel, LKML,
	Nick Piggin, Jan Kara

From: Nick Piggin <npiggin@gmail.com>

aio-dio-invalidate-failure GPFs in aio_put_req from io_submit.

lookup_ioctx doesn't implement the rcu lookup pattern properly.  rcu_read_lock
does not prevent refcount going to zero, so we might take a refcount on a zero
count ioctx.

Fix the bug by atomically testing for zero refcount before incrementing.

[JK: Added comment into the code]

Reviewed-by: Jeff Moyer <jmoyer@redhat.com>
Signed-off-by: Nick Piggin <npiggin@kernel.dk>
Signed-off-by: Jan Kara <jack@suse.cz>
---
 fs/aio.c |   35 ++++++++++++++++++++++++-----------
 1 files changed, 24 insertions(+), 11 deletions(-)

diff --git a/fs/aio.c b/fs/aio.c
index fc557a3..b4dd668 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -239,15 +239,23 @@ static void __put_ioctx(struct kioctx *ctx)
 	call_rcu(&ctx->rcu_head, ctx_rcu_free);
 }
 
-#define get_ioctx(kioctx) do {						\
-	BUG_ON(atomic_read(&(kioctx)->users) <= 0);			\
-	atomic_inc(&(kioctx)->users);					\
-} while (0)
-#define put_ioctx(kioctx) do {						\
-	BUG_ON(atomic_read(&(kioctx)->users) <= 0);			\
-	if (unlikely(atomic_dec_and_test(&(kioctx)->users))) 		\
-		__put_ioctx(kioctx);					\
-} while (0)
+static inline void get_ioctx(struct kioctx *kioctx)
+{
+	BUG_ON(atomic_read(&kioctx->users) <= 0);
+	atomic_inc(&kioctx->users);
+}
+
+static inline int try_get_ioctx(struct kioctx *kioctx)
+{
+	return atomic_inc_not_zero(&kioctx->users);
+}
+
+static inline void put_ioctx(struct kioctx *kioctx)
+{
+	BUG_ON(atomic_read(&kioctx->users) <= 0);
+	if (unlikely(atomic_dec_and_test(&kioctx->users)))
+		__put_ioctx(kioctx);
+}
 
 /* ioctx_alloc
  *	Allocates and initializes an ioctx.  Returns an ERR_PTR if it failed.
@@ -601,8 +609,13 @@ static struct kioctx *lookup_ioctx(unsigned long ctx_id)
 	rcu_read_lock();
 
 	hlist_for_each_entry_rcu(ctx, n, &mm->ioctx_list, list) {
-		if (ctx->user_id == ctx_id && !ctx->dead) {
-			get_ioctx(ctx);
+		/*
+		 * RCU protects us against accessing freed memory but
+		 * we have to be careful not to get a reference when the
+		 * reference count already dropped to 0 (ctx->dead test
+		 * is unreliable because of races).
+		 */
+		if (ctx->user_id == ctx_id && !ctx->dead && try_get_ioctx(ctx)){
 			ret = ctx;
 			break;
 		}
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/2] fs: Fix race between io_destroy() and io_submit() in AIO
  2011-02-21 15:58 [PATCH 0/2] aio: Fix use after free bugs Jan Kara
  2011-02-21 15:58 ` [PATCH 1/2] fs: Fix aio rcu ioctx lookup Jan Kara
@ 2011-02-21 15:58 ` Jan Kara
  1 sibling, 0 replies; 5+ messages in thread
From: Jan Kara @ 2011-02-21 15:58 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Jeff Moyer, Nick Piggin, Milton Miller, linux-fsdevel, LKML,
	Jan Kara

A race can occur when io_submit() races with io_destroy():

 CPU1						CPU2
io_submit()
  do_io_submit()
    ...
    ctx = lookup_ioctx(ctx_id);
						io_destroy()
    Now do_io_submit() holds the last reference to ctx.
    ...
    queue new AIO
    put_ioctx(ctx) - frees ctx with active AIOs

We solve this issue by checking whether ctx is being destroyed
in AIO submission path after adding new AIO to ctx. Then we
are guaranteed that either io_destroy() waits for new AIO or
we see that ctx is being destroyed and bail out.

CC: Nick Piggin <npiggin@kernel.dk>
Reviewed-by: Jeff Moyer <jmoyer@redhat.com>
Signed-off-by: Jan Kara <jack@suse.cz>
---
 fs/aio.c |   17 +++++++++++++++++
 1 files changed, 17 insertions(+), 0 deletions(-)

diff --git a/fs/aio.c b/fs/aio.c
index b4dd668..26869cd 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -1642,6 +1642,23 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
 		goto out_put_req;
 
 	spin_lock_irq(&ctx->ctx_lock);
+	/*
+	 * We could have raced with io_destroy() and are currently holding a
+	 * reference to ctx which should be destroyed. We cannot submit IO
+	 * since ctx gets freed as soon as io_submit() puts its reference.  The
+	 * check here is reliable: io_destroy() sets ctx->dead before waiting
+	 * for outstanding IO and the barrier between these two is realized by
+	 * unlock of mm->ioctx_lock and lock of ctx->ctx_lock.  Analogously we
+	 * increment ctx->reqs_active before checking for ctx->dead and the
+	 * barrier is realized by unlock and lock of ctx->ctx_lock. Thus if we
+	 * don't see ctx->dead set here, io_destroy() waits for our IO to
+	 * finish.
+	 */
+	if (ctx->dead) {
+		spin_unlock_irq(&ctx->ctx_lock);
+		ret = -EINVAL;
+		goto out_put_req;
+	}
 	aio_run_iocb(req);
 	if (!list_empty(&ctx->run_list)) {
 		/* drain the run list */
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2011-02-21 15:58 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-02-21 15:58 [PATCH 0/2] aio: Fix use after free bugs Jan Kara
2011-02-21 15:58 ` [PATCH 1/2] fs: Fix aio rcu ioctx lookup Jan Kara
2011-02-21 15:58 ` [PATCH 2/2] fs: Fix race between io_destroy() and io_submit() in AIO Jan Kara
  -- strict thread matches above, loose matches on Subject: below --
2011-02-15 12:59 [PATCH 0/2] aio: Fix use after free bugs Jan Kara
2011-02-15 13:55 ` Jeff Moyer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).