| From 86b62a2cb4fc09037bbce2959d2992962396fd7f Mon Sep 17 00:00:00 2001 |
| From: Al Viro <viro@ZenIV.linux.org.uk> |
| Date: Wed, 7 Mar 2012 05:16:35 +0000 |
| Subject: aio: fix io_setup/io_destroy race |
| |
| From: Al Viro <viro@ZenIV.linux.org.uk> |
| |
| commit 86b62a2cb4fc09037bbce2959d2992962396fd7f upstream. |
| |
| Have ioctx_alloc() return an extra reference, so that caller would drop it |
| on success and not bother with re-grabbing it on failure exit. The current |
| code is obviously broken - io_destroy() from another thread that managed |
| to guess the address io_setup() would've returned would free ioctx right |
| under us; gets especially interesting if aio_context_t * we pass to |
| io_setup() points to PROT_READ mapping, so put_user() fails and we end |
| up doing io_destroy() on kioctx another thread has just got freed... |
| |
| Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> |
| Acked-by: Benjamin LaHaise <bcrl@kvack.org> |
| Reviewed-by: Jeff Moyer <jmoyer@redhat.com> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/aio.c | 8 ++++---- |
| 1 file changed, 4 insertions(+), 4 deletions(-) |
| |
| --- a/fs/aio.c |
| +++ b/fs/aio.c |
| @@ -273,7 +273,7 @@ static struct kioctx *ioctx_alloc(unsign |
| mm = ctx->mm = current->mm; |
| atomic_inc(&mm->mm_count); |
| |
| - atomic_set(&ctx->users, 1); |
| + atomic_set(&ctx->users, 2); |
| spin_lock_init(&ctx->ctx_lock); |
| spin_lock_init(&ctx->ring_info.ring_lock); |
| init_waitqueue_head(&ctx->wait); |
| @@ -1338,10 +1338,10 @@ SYSCALL_DEFINE2(io_setup, unsigned, nr_e |
| ret = PTR_ERR(ioctx); |
| if (!IS_ERR(ioctx)) { |
| ret = put_user(ioctx->user_id, ctxp); |
| - if (!ret) |
| + if (!ret) { |
| + put_ioctx(ioctx); |
| return 0; |
| - |
| - get_ioctx(ioctx); /* io_destroy() expects us to hold a ref */ |
| + } |
| io_destroy(ioctx); |
| } |
| |