diff options
author | Eric Paris <eparis@redhat.com> | 2009-06-12 22:04:26 +0200 |
---|---|---|
committer | Eric Paris <eparis@redhat.com> | 2009-06-19 18:42:48 +0200 |
commit | 528da3e9e237059a84a2625e942811cf824a6efd (patch) | |
tree | 7d3de6d5468d6835a4d81bfa1e717100dc7b71bf /fs/notify/inotify/inotify_fsnotify.c | |
parent | Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tyt... (diff) | |
download | linux-528da3e9e237059a84a2625e942811cf824a6efd.tar.xz linux-528da3e9e237059a84a2625e942811cf824a6efd.zip |
inotify: inotify_destroy_mark_entry could get called twice
inotify_destroy_mark_entry could get called twice for the same mark since it
is called directly in inotify_rm_watch and when the mark is being destroyed for
another reason. As an example assume that the file being watched was just
deleted so inotify_destroy_mark_entry would get called from the path
fsnotify_inoderemove() -> fsnotify_destroy_marks_by_inode() ->
fsnotify_destroy_mark_entry() -> inotify_destroy_mark_entry(). If this
happened at the same time as userspace tried to remove a watch via
inotify_rm_watch we could attempt to remove the mark from the idr twice and
could thus double dec the ref cnt and potentially could be in a use after
free/double free situation. The fix is to have inotify_rm_watch use the
generic recursive safe fsnotify_destroy_mark_by_entry() so we are sure the
inotify_destroy_mark_entry() function can only be called one.
This patch also renames the function to inotify_ingored_remove_idr() so it is
clear what is actually going on in the function.
Hopefully this fixes:
[ 20.342058] idr_remove called for id=20 which is not allocated.
[ 20.348000] Pid: 1860, comm: udevd Not tainted 2.6.30-tip #1077
[ 20.353933] Call Trace:
[ 20.356410] [<ffffffff811a82b7>] idr_remove+0x115/0x18f
[ 20.361737] [<ffffffff8134259d>] ? _spin_lock+0x6d/0x75
[ 20.367061] [<ffffffff8111640a>] ? inotify_destroy_mark_entry+0xa3/0xcf
[ 20.373771] [<ffffffff8111641e>] inotify_destroy_mark_entry+0xb7/0xcf
[ 20.380306] [<ffffffff81115913>] inotify_freeing_mark+0xe/0x10
[ 20.386238] [<ffffffff8111410d>] fsnotify_destroy_mark_by_entry+0x143/0x170
[ 20.393293] [<ffffffff811163a3>] inotify_destroy_mark_entry+0x3c/0xcf
[ 20.399829] [<ffffffff811164d1>] sys_inotify_rm_watch+0x9b/0xc6
[ 20.405850] [<ffffffff8100bcdb>] system_call_fastpath+0x16/0x1b
Reported-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Eric Paris <eparis@redhat.com>
Tested-by: Peter Ziljlstra <peterz@infradead.org>
Diffstat (limited to 'fs/notify/inotify/inotify_fsnotify.c')
-rw-r--r-- | fs/notify/inotify/inotify_fsnotify.c | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c index 7ef75b83247e..47cd258fd24d 100644 --- a/fs/notify/inotify/inotify_fsnotify.c +++ b/fs/notify/inotify/inotify_fsnotify.c @@ -81,7 +81,7 @@ static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_ev static void inotify_freeing_mark(struct fsnotify_mark_entry *entry, struct fsnotify_group *group) { - inotify_destroy_mark_entry(entry, group); + inotify_ignored_and_remove_idr(entry, group); } static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode, __u32 mask) |