linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] inotify: race use after free/double free in inotify inode marks
@ 2010-05-12 16:08 Eric Paris
  2010-05-13  0:16 ` Andrew Morton
  0 siblings, 1 reply; 3+ messages in thread
From: Eric Paris @ 2010-05-12 16:08 UTC (permalink / raw)
  To: linux-kernel

From: root <root@tyan-gt24-04.rhts.eng.bos.redhat.com>

There is a race in the inotify add/rm watch code.  A task can find and
remove a mark which doesn't have all of it's references.  This can
result in a use after free/double free situation.

Task A					Task B
------------				-----------
inotify_new_watch()
 allocate a mark (refcnt == 1)
 add it to the idr
					inotify_rm_watch()
					 inotify_remove_from_idr()
					  fsnotify_put_mark()
					      refcnt hits 0, free
 take reference because we are on idr
 [at this point it is a use after free]
 [time goes on]
 refcnt may hit 0 again, double free

The fix is to take the reference BEFORE the object can be found in the
idr.

Signed-off-by: Eric Paris <eparis@redhat.com>
---
 fs/notify/inotify/inotify_user.c |    9 ++++++---
 1 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index 40da732..e46ca68 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -546,21 +546,24 @@ retry:
 	if (unlikely(!idr_pre_get(&group->inotify_data.idr, GFP_KERNEL)))
 		goto out_err;
 
+	/* we are putting the mark on the idr, take a reference */
+	fsnotify_get_mark(&tmp_ientry->fsn_entry);
+
 	spin_lock(&group->inotify_data.idr_lock);
 	ret = idr_get_new_above(&group->inotify_data.idr, &tmp_ientry->fsn_entry,
 				group->inotify_data.last_wd+1,
 				&tmp_ientry->wd);
 	spin_unlock(&group->inotify_data.idr_lock);
 	if (ret) {
+		/* we didn't get on the idr, drop the idr reference */
+		fsnotify_put_mark(&tmp_ientry->fsn_entry);
+
 		/* idr was out of memory allocate and try again */
 		if (ret == -EAGAIN)
 			goto retry;
 		goto out_err;
 	}
 
-	/* we put the mark on the idr, take a reference */
-	fsnotify_get_mark(&tmp_ientry->fsn_entry);
-
 	/* we are on the idr, now get on the inode */
 	ret = fsnotify_add_mark(&tmp_ientry->fsn_entry, group, inode);
 	if (ret) {
-- 
1.6.5.3


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

* Re: [PATCH] inotify: race use after free/double free in inotify inode marks
  2010-05-12 16:08 [PATCH] inotify: race use after free/double free in inotify inode marks Eric Paris
@ 2010-05-13  0:16 ` Andrew Morton
  2010-05-13 11:31   ` Eric Paris
  0 siblings, 1 reply; 3+ messages in thread
From: Andrew Morton @ 2010-05-13  0:16 UTC (permalink / raw)
  To: Eric Paris; +Cc: linux-kernel

On Wed, 12 May 2010 12:08:00 -0400 Eric Paris <eparis@redhat.com> wrote:

> From: root <root@tyan-gt24-04.rhts.eng.bos.redhat.com>

hm.

> There is a race in the inotify add/rm watch code.  A task can find and
> remove a mark which doesn't have all of it's references.  This can
> result in a use after free/double free situation.
> 
> Task A					Task B
> ------------				-----------
> inotify_new_watch()
>  allocate a mark (refcnt == 1)
>  add it to the idr
> 					inotify_rm_watch()
> 					 inotify_remove_from_idr()
> 					  fsnotify_put_mark()
> 					      refcnt hits 0, free
>  take reference because we are on idr
>  [at this point it is a use after free]
>  [time goes on]
>  refcnt may hit 0 again, double free
> 
> The fix is to take the reference BEFORE the object can be found in the
> idr.
> 
> Signed-off-by: Eric Paris <eparis@redhat.com>

The changelog has no "Cc: <stable@kernel.org>".  I suspect it should
have that?


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

* Re: [PATCH] inotify: race use after free/double free in inotify inode marks
  2010-05-13  0:16 ` Andrew Morton
@ 2010-05-13 11:31   ` Eric Paris
  0 siblings, 0 replies; 3+ messages in thread
From: Eric Paris @ 2010-05-13 11:31 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel

On Wed, 2010-05-12 at 20:16 -0400, Andrew Morton wrote:
> On Wed, 12 May 2010 12:08:00 -0400 Eric Paris <eparis@redhat.com> wrote:
> 
> > From: root <root@tyan-gt24-04.rhts.eng.bos.redhat.com>
> 
> hm.

Well poop.  That's what I get for using git on a random test box.  I
moved it to my real tree with git-format-patch > git-am.  I'll fix the
author.

> > There is a race in the inotify add/rm watch code.  A task can find and
> > remove a mark which doesn't have all of it's references.  This can
> > result in a use after free/double free situation.
> > 
> > Task A					Task B
> > ------------				-----------
> > inotify_new_watch()
> >  allocate a mark (refcnt == 1)
> >  add it to the idr
> > 					inotify_rm_watch()
> > 					 inotify_remove_from_idr()
> > 					  fsnotify_put_mark()
> > 					      refcnt hits 0, free
> >  take reference because we are on idr
> >  [at this point it is a use after free]
> >  [time goes on]
> >  refcnt may hit 0 again, double free
> > 
> > The fix is to take the reference BEFORE the object can be found in the
> > idr.
> > 
> > Signed-off-by: Eric Paris <eparis@redhat.com>
> 
> The changelog has no "Cc: <stable@kernel.org>".  I suspect it should
> have that?

Will fix before I ask Linus to pull....

-Eric


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

end of thread, other threads:[~2010-05-13 11:31 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-05-12 16:08 [PATCH] inotify: race use after free/double free in inotify inode marks Eric Paris
2010-05-13  0:16 ` Andrew Morton
2010-05-13 11:31   ` Eric Paris

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).