diff mbox series

[v2,15/16] fanotify: refine rules for when name is reported

Message ID 20200217131455.31107-16-amir73il@gmail.com
State New, archived
Headers show
Series Fanotify event with name info | expand

Commit Message

Amir Goldstein Feb. 17, 2020, 1:14 p.m. UTC
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(-)
diff mbox series

Patch

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,