Skip to content

Commit 39c575b

Browse files
amir73iljb-essential
authored andcommitted
fanotify: fix logic of events on child
commit 54a307ba8d3cd00a3902337ffaae28f436eeb1a4 upstream. When event on child inodes are sent to the parent inode mark and parent inode mark was not marked with FAN_EVENT_ON_CHILD, the event will not be delivered to the listener process. However, if the same process also has a mount mark, the event to the parent inode will be delivered regadless of the mount mark mask. This behavior is incorrect in the case where the mount mark mask does not contain the specific event type. For example, the process adds a mark on a directory with mask FAN_MODIFY (without FAN_EVENT_ON_CHILD) and a mount mark with mask FAN_CLOSE_NOWRITE (without FAN_ONDIR). A modify event on a file inside that directory (and inside that mount) should not create a FAN_MODIFY event, because neither of the marks requested to get that event on the file. Fixes: 1968f5e ("fanotify: use both marks when possible") Cc: stable <[email protected]> Signed-off-by: Amir Goldstein <[email protected]> Signed-off-by: Jan Kara <[email protected]> [natechancellor: Fix small conflict due to lack of 3cd5eca8d7a2f] Signed-off-by: Nathan Chancellor <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent f8d2509 commit 39c575b

File tree

1 file changed

+15
-19
lines changed

1 file changed

+15
-19
lines changed

fs/notify/fanotify/fanotify.c

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark,
9292
u32 event_mask,
9393
void *data, int data_type)
9494
{
95-
__u32 marks_mask, marks_ignored_mask;
95+
__u32 marks_mask = 0, marks_ignored_mask = 0;
9696
struct path *path = data;
9797

9898
pr_debug("%s: inode_mark=%p vfsmnt_mark=%p mask=%x data=%p"
@@ -108,24 +108,20 @@ static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark,
108108
!d_can_lookup(path->dentry))
109109
return false;
110110

111-
if (inode_mark && vfsmnt_mark) {
112-
marks_mask = (vfsmnt_mark->mask | inode_mark->mask);
113-
marks_ignored_mask = (vfsmnt_mark->ignored_mask | inode_mark->ignored_mask);
114-
} else if (inode_mark) {
115-
/*
116-
* if the event is for a child and this inode doesn't care about
117-
* events on the child, don't send it!
118-
*/
119-
if ((event_mask & FS_EVENT_ON_CHILD) &&
120-
!(inode_mark->mask & FS_EVENT_ON_CHILD))
121-
return false;
122-
marks_mask = inode_mark->mask;
123-
marks_ignored_mask = inode_mark->ignored_mask;
124-
} else if (vfsmnt_mark) {
125-
marks_mask = vfsmnt_mark->mask;
126-
marks_ignored_mask = vfsmnt_mark->ignored_mask;
127-
} else {
128-
BUG();
111+
/*
112+
* if the event is for a child and this inode doesn't care about
113+
* events on the child, don't send it!
114+
*/
115+
if (inode_mark &&
116+
(!(event_mask & FS_EVENT_ON_CHILD) ||
117+
(inode_mark->mask & FS_EVENT_ON_CHILD))) {
118+
marks_mask |= inode_mark->mask;
119+
marks_ignored_mask |= inode_mark->ignored_mask;
120+
}
121+
122+
if (vfsmnt_mark) {
123+
marks_mask |= vfsmnt_mark->mask;
124+
marks_ignored_mask |= vfsmnt_mark->ignored_mask;
129125
}
130126

131127
if (d_is_dir(path->dentry) &&

0 commit comments

Comments
 (0)