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@xxxxxxxxx> --- fs/notify/fanotify/fanotify.c | 37 +++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index 43c338a8a2f1..45203c1484b9 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -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, -- 2.17.1