diff options
author | Miklos Szeredi <mszeredi@redhat.com> | 2017-10-30 16:14:55 -0400 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2017-10-31 12:54:56 -0400 |
commit | 0d6ec079d6aaa098b978d6395973bb027c752a03 (patch) | |
tree | 681a9c667b5cf48e6166eecf12c9745ffc717fc4 | |
parent | 24c20305c7fc8959836211cb8c50aab93ae0e54f (diff) |
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.c | 10 |
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, | |||
335 | struct fsnotify_mark, obj_list); | 335 | struct fsnotify_mark, obj_list); |
336 | vfsmount_group = vfsmount_mark->group; | 336 | vfsmount_group = vfsmount_mark->group; |
337 | } | 337 | } |
338 | /* | ||
339 | * Need to protect both marks against freeing so that we can | ||
340 | * continue iteration from this place, regardless of which mark | ||
341 | * we actually happen to send an event for. | ||
342 | */ | ||
343 | iter_info.inode_mark = inode_mark; | ||
344 | iter_info.vfsmount_mark = vfsmount_mark; | ||
338 | 345 | ||
339 | if (inode_group && vfsmount_group) { | 346 | if (inode_group && vfsmount_group) { |
340 | int cmp = fsnotify_compare_groups(inode_group, | 347 | 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, | |||
348 | } | 355 | } |
349 | } | 356 | } |
350 | 357 | ||
351 | iter_info.inode_mark = inode_mark; | ||
352 | iter_info.vfsmount_mark = vfsmount_mark; | ||
353 | |||
354 | ret = send_to_group(to_tell, inode_mark, vfsmount_mark, mask, | 358 | ret = send_to_group(to_tell, inode_mark, vfsmount_mark, mask, |
355 | data, data_is, cookie, file_name, | 359 | data, data_is, cookie, file_name, |
356 | &iter_info); | 360 | &iter_info); |