summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2017-10-30 21:14:55 +0100
committerJan Kara <jack@suse.cz>2017-10-31 17:54:56 +0100
commit0d6ec079d6aaa098b978d6395973bb027c752a03 (patch)
tree681a9c667b5cf48e6166eecf12c9745ffc717fc4
parentfsnotify: clean up fsnotify_prepare/finish_user_wait() (diff)
downloadlinux-0d6ec079d6aaa098b978d6395973bb027c752a03.tar.xz
linux-0d6ec079d6aaa098b978d6395973bb027c752a03.zip
fsnotify: pin both inode and vfsmount mark
We may fail to pin one of the marks in fsnotify_prepare_user_wait() when dropping the srcu read lock, resulting in use after free at the next iteration. Solution is to store both marks in iter_info instead of just the one we'll be sending the event for. Reviewed-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> Fixes: 9385a84d7e1f ("fsnotify: Pass fsnotify_iter_info into handle_event handler") Cc: <stable@vger.kernel.org> # v4.12 Signed-off-by: Jan Kara <jack@suse.cz>
-rw-r--r--fs/notify/fsnotify.c10
1 files changed, 7 insertions, 3 deletions
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index 0c4583b61717..074716293829 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -335,6 +335,13 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is,
struct fsnotify_mark, obj_list);
vfsmount_group = vfsmount_mark->group;
}
+ /*
+ * Need to protect both marks against freeing so that we can
+ * continue iteration from this place, regardless of which mark
+ * we actually happen to send an event for.
+ */
+ iter_info.inode_mark = inode_mark;
+ iter_info.vfsmount_mark = vfsmount_mark;
if (inode_group && vfsmount_group) {
int cmp = fsnotify_compare_groups(inode_group,
@@ -348,9 +355,6 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is,
}
}
- iter_info.inode_mark = inode_mark;
- iter_info.vfsmount_mark = vfsmount_mark;
-
ret = send_to_group(to_tell, inode_mark, vfsmount_mark, mask,
data, data_is, cookie, file_name,
&iter_info);