@@ -202,6 +202,32 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group,
!(mark->mask & FS_EVENT_ON_CHILD)))
continue;
+ /*
+ * fanotify_alloc_event() uses the "on child" flag as indication
+ * for reporting name, but the flag will be masked out before
+ * reporting to user.
+ *
+ * With FAN_REPORT_NAME, name will be reported if event is in
+ * the mask of a watching parent or filesystem mark.
+ * name will not be reported if event is only in the mask of a
+ * mark on the victim inode itself.
+ * If event is only in the mask of a marked mount, name will be
+ * reported if the victim inode is not the mount's root. Note
+ * that the mount's root could be a non-directory in case of
+ * bind mount.
+ */
+ if (FAN_GROUP_FLAG(group, FAN_REPORT_NAME) &&
+ event_mask & mark->mask & FS_EVENTS_POSS_ON_CHILD) {
+ user_mask |= FS_EVENT_ON_CHILD;
+ if (type == FSNOTIFY_OBJ_TYPE_SB ||
+ (type == FSNOTIFY_OBJ_TYPE_VFSMOUNT &&
+ !WARN_ON_ONCE(data_type != FSNOTIFY_EVENT_PATH) &&
+ path->dentry != path->mnt->mnt_root)) {
+ event_mask |= FS_EVENT_ON_CHILD;
+ marks_mask |= FS_EVENT_ON_CHILD;
+ }
+ }
+
marks_mask |= mark->mask;
marks_ignored_mask |= mark->ignored_mask;
}
@@ -344,9 +370,8 @@ struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
* With flag FAN_REPORT_NAME, we report the parent fid and name for
* events possible "on child" in addition to reporting the child fid.
* If parent is unknown (dentry is disconnected) or parent is not on the
- * same filesystem as child (dentry is sb root), only "child" fid is
- * reported. Events are reported the same way when reported to sb, mount
- * or inode marks and when reported to a directory watching children.
+ * same filesystem/mount as child (dentry is sb/mount root), only the
+ * "child" fid is reported.
* Allocate an fanotify_name_event struct and copy the name.
*/
if (mask & FAN_DIR_MODIFY && !(WARN_ON_ONCE(!file_name))) {
@@ -357,7 +382,7 @@ struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
id = NULL;
dir = inode;
} else if (FAN_GROUP_FLAG(group, FAN_REPORT_NAME) &&
- mask & FS_EVENTS_POSS_ON_CHILD &&
+ mask & FS_EVENT_ON_CHILD &&
likely(dentry && !IS_ROOT(dentry))) {
parent = dget_parent(dentry);
dir = d_inode(parent);
@@ -400,7 +425,7 @@ struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
* directory and child watches exist.
*/
fsnotify_init_event(&event->fse, (void *)dentry ?: inode);
- event->mask = mask;
+ event->mask = mask & FANOTIFY_OUTGOING_EVENTS;
if (FAN_GROUP_FLAG(group, FAN_REPORT_TID))
event->pid = get_pid(task_pid(current));
else
@@ -503,7 +528,7 @@ static int fanotify_handle_event(struct fsnotify_group *group,
mask = fanotify_group_event_mask(group, iter_info, mask, data,
data_type);
- if (!mask)
+ if (!(mask & FANOTIFY_OUTGOING_EVENTS))
return 0;
pr_debug("%s: group=%p inode=%p mask=%x\n", __func__, group, inode,
With FAN_REPORT_NAME, name will be reported if event is in the mask of a watching parent or filesystem mark. Name will not be reported if event is only in the mask of a mark on the victim inode itself. If event is only in the mask of a marked mount, name will be reported if the victim inode is not the mount's root. Note that the mount's root could be a non-directory in case of bind mount. Signed-off-by: Amir Goldstein <amir73il@gmail.com> --- fs/notify/fanotify/fanotify.c | 37 +++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-)