--- /dev/null
+From b469e7e47c8a075cc08bcd1e85d4365134bdcdd5 Mon Sep 17 00:00:00 2001
+From: Amir Goldstein <amir73il@gmail.com>
+Date: Tue, 30 Oct 2018 20:29:53 +0200
+Subject: fanotify: fix handling of events on child sub-directory
+
+From: Amir Goldstein <amir73il@gmail.com>
+
+commit b469e7e47c8a075cc08bcd1e85d4365134bdcdd5 upstream.
+
+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>
+[amir: backport to v4.9]
+Signed-off-by: Amir Goldstein <amir73il@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/notify/fsnotify.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/fs/notify/fsnotify.c
++++ b/fs/notify/fsnotify.c
+@@ -101,9 +101,9 @@ int __fsnotify_parent(struct path *path,
+ parent = dget_parent(dentry);
+ p_inode = parent->d_inode;
+
+- if (unlikely(!fsnotify_inode_watches_children(p_inode)))
++ if (unlikely(!fsnotify_inode_watches_children(p_inode))) {
+ __fsnotify_update_child_dentry_flags(p_inode);
+- else if (p_inode->i_fsnotify_mask & mask) {
++ } else if (p_inode->i_fsnotify_mask & mask & ~FS_EVENT_ON_CHILD) {
+ struct name_snapshot name;
+
+ /* we are notifying a parent so come up with the new mask which
+@@ -207,6 +207,10 @@ int fsnotify(struct inode *to_tell, __u3
+ else
+ mnt = NULL;
+
++ /* An event "on child" is not intended for a mount mark */
++ if (mask & FS_EVENT_ON_CHILD)
++ mnt = NULL;
++
+ /*
+ * Optimization: srcu_read_lock() has a memory barrier which can
+ * be expensive. It protects walking the *_fsnotify_marks lists.