Re: [PATCH 4.14 00/68] 4.14.97-stable review

From: Amir Goldstein
Date: Mon Feb 04 2019 - 05:12:54 EST


> > > fanotify09 failed on arm64 devices running 4.14 version kernel
> > > fanotify09.c:202: FAIL: first group got more than 2 events (72 > 48)
> > > https://bugs.linaro.org/show_bug.cgi?id=4271
> > >
> >
> > fanotify09 was added a new regression test case for commit
> > b469e7e47c8a: fanotify: fix handling of events on child sub-directory
> >
> > That commit was backported to v4.19. As I wrote in "backport hint", the bug
> > exists in older kernels, but fix does not apply cleanly to older kernels.
>
> If someone were to provide a tested backport to 4.14 and older, I'll be
> glad to queue it up (hint hint hint...)
>

Attached backport applies and tested on 4.14 and 4.9

Thanks,
Amir.
From 69f364bd1421d7e79b63e62cfd7ea6044249bcef Mon Sep 17 00:00:00 2001
From: Amir Goldstein <amir73il@xxxxxxxxx>
Date: Tue, 30 Oct 2018 20:29:53 +0200
Subject: [PATCH] fanotify: fix handling of events on child sub-directory

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 mark that does have that event type in their mask, the "on
child" event will be reported on the mount 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 marks.

Cc: <stable@xxxxxxxxxxxxxxx>
Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx>
Signed-off-by: Jan Kara <jack@xxxxxxx>
[amir: backport to v4.9]
Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx>
---
fs/notify/fsnotify.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index a64adc2fced9..56b4f855fa9b 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -101,9 +101,9 @@ int __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
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, __u32 mask, void *data, int data_is,
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.
--
2.7.4