Skip to content

Commit b469e7e

Browse files
amir73iljankara
authored andcommitted
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>
1 parent b00d209 commit b469e7e

File tree

2 files changed

+10
-7
lines changed

2 files changed

+10
-7
lines changed

fs/notify/fanotify/fanotify.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,12 +115,12 @@ static bool fanotify_should_send_event(struct fsnotify_iter_info *iter_info,
115115
continue;
116116
mark = iter_info->marks[type];
117117
/*
118-
* if the event is for a child and this inode doesn't care about
119-
* events on the child, don't send it!
118+
* If the event is for a child and this mark doesn't care about
119+
* events on a child, don't send it!
120120
*/
121-
if (type == FSNOTIFY_OBJ_TYPE_INODE &&
122-
(event_mask & FS_EVENT_ON_CHILD) &&
123-
!(mark->mask & FS_EVENT_ON_CHILD))
121+
if (event_mask & FS_EVENT_ON_CHILD &&
122+
(type != FSNOTIFY_OBJ_TYPE_INODE ||
123+
!(mark->mask & FS_EVENT_ON_CHILD)))
124124
continue;
125125

126126
marks_mask |= mark->mask;

fs/notify/fsnotify.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,9 @@ int __fsnotify_parent(const struct path *path, struct dentry *dentry, __u32 mask
167167
parent = dget_parent(dentry);
168168
p_inode = parent->d_inode;
169169

170-
if (unlikely(!fsnotify_inode_watches_children(p_inode)))
170+
if (unlikely(!fsnotify_inode_watches_children(p_inode))) {
171171
__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) {
173173
struct name_snapshot name;
174174

175175
/* 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,
339339
sb = mnt->mnt.mnt_sb;
340340
mnt_or_sb_mask = mnt->mnt_fsnotify_mask | sb->s_fsnotify_mask;
341341
}
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;
342345

343346
/*
344347
* Optimization: srcu_read_lock() has a memory barrier which can

0 commit comments

Comments
 (0)