summaryrefslogtreecommitdiffstats
path: root/fs/notify
diff options
context:
space:
mode:
authorAmir Goldstein <amir73il@gmail.com>2018-10-30 14:29:53 -0400
committerJan Kara <jack@suse.cz>2018-11-08 09:43:48 -0500
commitb469e7e47c8a075cc08bcd1e85d4365134bdcdd5 (patch)
tree947395d357c885ed6f02c4c901a2990f9a382137 /fs/notify
parentb00d209241ff7ac336543f92ea764b9d6b03032a (diff)
fanotify: fix handling of events on child sub-directory
When an event is reported on a sub-directory and the parent inode has a mark mask with FS_EVENT_ON_CHILD|FS_ISDIR, the event will be sent to fsnotify() even if the event type is not in the parent mark mask (e.g. FS_OPEN). Further more, if that event happened on a mount or a filesystem with a mount/sb mark that does have that event type in their mask, the "on child" event will be reported on the mount/sb mark. That is not desired, because user will get a duplicate event for the same action. Note that the event reported on the victim inode is never merged with the event reported on the parent inode, because of the check in should_merge(): old_fsn->inode == new_fsn->inode. Fix this by looking for a match of an actual event type (i.e. not just FS_ISDIR) in parent's inode mark mask and by not reporting an "on child" event to group if event type is only found on mount/sb marks. [backport hint: The bug seems to have always been in fanotify, but this patch will only apply cleanly to v4.19.y] Cc: <stable@vger.kernel.org> # v4.19 Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/notify')
-rw-r--r--fs/notify/fanotify/fanotify.c10
-rw-r--r--fs/notify/fsnotify.c7
2 files changed, 10 insertions, 7 deletions
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index 5769cf3ff035..e08a6647267b 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -115,12 +115,12 @@ static bool fanotify_should_send_event(struct fsnotify_iter_info *iter_info,
115 continue; 115 continue;
116 mark = iter_info->marks[type]; 116 mark = iter_info->marks[type];
117 /* 117 /*
118 * if the event is for a child and this inode doesn't care about 118 * If the event is for a child and this mark doesn't care about
119 * events on the child, don't send it! 119 * events on a child, don't send it!
120 */ 120 */
121 if (type == FSNOTIFY_OBJ_TYPE_INODE && 121 if (event_mask & FS_EVENT_ON_CHILD &&
122 (event_mask & FS_EVENT_ON_CHILD) && 122 (type != FSNOTIFY_OBJ_TYPE_INODE ||
123 !(mark->mask & FS_EVENT_ON_CHILD)) 123 !(mark->mask & FS_EVENT_ON_CHILD)))
124 continue; 124 continue;
125 125
126 marks_mask |= mark->mask; 126 marks_mask |= mark->mask;
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index 2172ba516c61..d2c34900ae05 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -167,9 +167,9 @@ int __fsnotify_parent(const struct path *path, struct dentry *dentry, __u32 mask
167 parent = dget_parent(dentry); 167 parent = dget_parent(dentry);
168 p_inode = parent->d_inode; 168 p_inode = parent->d_inode;
169 169
170 if (unlikely(!fsnotify_inode_watches_children(p_inode))) 170 if (unlikely(!fsnotify_inode_watches_children(p_inode))) {
171 __fsnotify_update_child_dentry_flags(p_inode); 171 __fsnotify_update_child_dentry_flags(p_inode);
172 else if (p_inode->i_fsnotify_mask & mask) { 172 } else if (p_inode->i_fsnotify_mask & mask & ALL_FSNOTIFY_EVENTS) {
173 struct name_snapshot name; 173 struct name_snapshot name;
174 174
175 /* we are notifying a parent so come up with the new mask which 175 /* we are notifying a parent so come up with the new mask which
@@ -339,6 +339,9 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is,
339 sb = mnt->mnt.mnt_sb; 339 sb = mnt->mnt.mnt_sb;
340 mnt_or_sb_mask = mnt->mnt_fsnotify_mask | sb->s_fsnotify_mask; 340 mnt_or_sb_mask = mnt->mnt_fsnotify_mask | sb->s_fsnotify_mask;
341 } 341 }
342 /* An event "on child" is not intended for a mount/sb mark */
343 if (mask & FS_EVENT_ON_CHILD)
344 mnt_or_sb_mask = 0;
342 345
343 /* 346 /*
344 * Optimization: srcu_read_lock() has a memory barrier which can 347 * Optimization: srcu_read_lock() has a memory barrier which can