public inbox for linux-fsdevel@vger.kernel.org
 help / color / mirror / Atom feed
From: Amir Goldstein <amir73il@gmail.com>
To: Jan Kara <jack@suse.cz>
Cc: Christian Brauner <brauner@kernel.org>, linux-fsdevel@vger.kernel.org
Subject: [PATCH v2 03/10] fsnotify: separate the events bitmask macros by group type
Date: Fri, 24 Apr 2026 19:04:56 +0200	[thread overview]
Message-ID: <20260424170503.2096847-4-amir73il@gmail.com> (raw)
In-Reply-To: <20260424170503.2096847-1-amir73il@gmail.com>

Fork the macros ALL_FSNOTIFY_EVENTS and FANOTIFY_EVENTS to
*_EVENTS_ON_{FS,NS} and use them to determine the valid mask for
fanotify_mark() and the outgoing mask by the group type.

Use the fanotify_is_valid_mask() helepr to simplifies the check for
reporting mount events IFF group was initialized with FAN_REPORT_MNT
and IFF watching an mntns object.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
 fs/notify/fanotify/fanotify.c      |  3 +-
 fs/notify/fanotify/fanotify_user.c | 68 ++++++++++++++++++++----------
 fs/notify/fsnotify.c               |  6 +--
 include/linux/fanotify.h           | 26 ++++++++----
 include/linux/fsnotify_backend.h   | 42 ++++++++++++------
 include/uapi/linux/fanotify.h      | 25 ++++++++---
 6 files changed, 113 insertions(+), 57 deletions(-)

diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index e768c25262e27..494bba49634e1 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -303,7 +303,7 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group,
 				     struct inode *dir)
 {
 	__u32 marks_mask = 0, marks_ignore_mask = 0;
-	__u32 test_mask, user_mask = FANOTIFY_OUTGOING_EVENTS |
+	__u32 test_mask, user_mask = FANOTIFY_OUTGOING_FS_EVENTS |
 				     FANOTIFY_EVENT_FLAGS;
 	const struct path *path = fsnotify_data_path(data, data_type);
 	unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS);
@@ -315,6 +315,7 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group,
 		 __func__, iter_info->report_mask, event_mask, data, data_type);
 
 	if (fsnotify_is_ns_watcher(group)) {
+		user_mask = FANOTIFY_OUTGOING_NS_EVENTS;
 		if (data_type != FSNOTIFY_EVENT_MNT)
 			return 0;
 	} else if (WARN_ON_ONCE(!fsnotify_is_fs_watcher(group))) {
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index 95e7c24c70249..7afb017d40f50 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -830,6 +830,19 @@ static int copy_info_records_to_user(struct fanotify_event *event,
 	return total_bytes;
 }
 
+static __u64 fanotify_event_mask(struct fsnotify_group *group,
+				 struct fanotify_event *event)
+{
+	switch (group->type) {
+	case FSNOTIFY_GROUP_TYPE_FS:
+		return event->mask & FANOTIFY_OUTGOING_FS_EVENTS;
+	case FSNOTIFY_GROUP_TYPE_NS:
+		return event->mask & FANOTIFY_OUTGOING_NS_EVENTS;
+	}
+
+	return 0;
+}
+
 static ssize_t copy_event_to_user(struct fsnotify_group *group,
 				  struct fanotify_event *event,
 				  char __user *buf, size_t count)
@@ -848,7 +861,7 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
 	metadata.metadata_len = FAN_EVENT_METADATA_LEN;
 	metadata.vers = FANOTIFY_METADATA_VERSION;
 	metadata.reserved = 0;
-	metadata.mask = event->mask & FANOTIFY_OUTGOING_EVENTS;
+	metadata.mask = fanotify_event_mask(group, event);
 	metadata.pid = pid_vnr(event->pid);
 	/*
 	 * For an unprivileged listener, event->pid can be used to identify the
@@ -1881,6 +1894,35 @@ static int fanotify_events_supported(struct fsnotify_group *group,
 	return 0;
 }
 
+static bool fanotify_is_valid_mask(struct fsnotify_group *group, int mark_type,
+				   __u64 mask)
+{
+	u32 valid_mask = 0;
+
+	/*
+	 * Event bits for different group type may be overloaded but event
+	 * flags are common to all group types.
+	 */
+	BUILD_BUG_ON(FANOTIFY_EVENTS_ON_FS & FANOTIFY_EVENT_FLAGS);
+	BUILD_BUG_ON(FANOTIFY_EVENTS_ON_NS & FANOTIFY_EVENT_FLAGS);
+
+	switch (group->type) {
+	case FSNOTIFY_GROUP_TYPE_FS:
+		valid_mask = FANOTIFY_EVENTS_ON_FS | FANOTIFY_EVENT_FLAGS;
+		if (!IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS))
+			valid_mask &= ~FANOTIFY_PERM_EVENTS;
+		break;
+	case FSNOTIFY_GROUP_TYPE_NS:
+		/* Only report mount events on mntns mark */
+		if (mark_type == FAN_MARK_MNTNS &&
+		    FAN_GROUP_FLAG(group, FAN_REPORT_MNT))
+			valid_mask = FANOTIFY_MOUNT_EVENTS;
+		break;
+	}
+
+	return !(mask & ~valid_mask);
+}
+
 static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
 			    int dfd, const char  __user *pathname)
 {
@@ -1890,7 +1932,6 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
 	struct fan_fsid __fsid, *fsid = NULL;
 	struct user_namespace *user_ns = NULL;
 	struct mnt_namespace *mntns;
-	u32 valid_mask = FANOTIFY_EVENTS | FANOTIFY_EVENT_FLAGS;
 	unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS;
 	unsigned int mark_cmd = flags & FANOTIFY_MARK_CMD_BITS;
 	unsigned int ignore = flags & FANOTIFY_MARK_IGNORE_BITS;
@@ -1945,13 +1986,6 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
 		return -EINVAL;
 	}
 
-	if (IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS))
-		valid_mask |= FANOTIFY_PERM_EVENTS;
-
-	if (mask & ~valid_mask)
-		return -EINVAL;
-
-
 	/* We don't allow FAN_MARK_IGNORE & FAN_MARK_IGNORED_MASK together */
 	if (ignore == (FAN_MARK_IGNORE | FAN_MARK_IGNORED_MASK))
 		return -EINVAL;
@@ -1974,22 +2008,10 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
 		return -EINVAL;
 	group = fd_file(f)->private_data;
 
-	if (group->type != group_type)
+	if (group->type != group_type ||
+	    !fanotify_is_valid_mask(group, mark_type, mask))
 		return -EINVAL;
 
-	/* Only report mount events on mnt namespace */
-	if (FAN_GROUP_FLAG(group, FAN_REPORT_MNT)) {
-		if (mask & ~FANOTIFY_MOUNT_EVENTS)
-			return -EINVAL;
-		if (mark_type != FAN_MARK_MNTNS)
-			return -EINVAL;
-	} else {
-		if (mask & FANOTIFY_MOUNT_EVENTS)
-			return -EINVAL;
-		if (mark_type == FAN_MARK_MNTNS)
-			return -EINVAL;
-	}
-
 	/*
 	 * A user is allowed to setup sb/mount/mntns marks only if it is
 	 * capable in the user ns where the group was created.
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index b646a861a84c6..429ce614233ce 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -149,7 +149,7 @@ static inline __u32 fsnotify_object_watched(struct inode *inode, __u32 mnt_mask,
 	__u32 marks_mask = READ_ONCE(inode->i_fsnotify_mask) | mnt_mask |
 			   READ_ONCE(inode->i_sb->s_fsnotify_mask);
 
-	return mask & marks_mask & ALL_FSNOTIFY_EVENTS;
+	return mask & marks_mask & FSNOTIFY_EVENTS_ON_FS;
 }
 
 /* Report pre-content event with optional range info */
@@ -219,7 +219,7 @@ int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data,
 	 * events can provide an undesirable side-channel for information
 	 * exfiltration.
 	 */
-	parent_interested = mask & p_mask & ALL_FSNOTIFY_EVENTS &&
+	parent_interested = mask & p_mask & FSNOTIFY_EVENTS_ON_FS &&
 			    !(data_type == FSNOTIFY_EVENT_PATH &&
 			      d_is_special(dentry) &&
 			      (mask & (FS_ACCESS | FS_MODIFY)));
@@ -266,7 +266,7 @@ static int fsnotify_handle_inode_event(struct fsnotify_group *group,
 		return 0;
 
 	/* Check interest of this mark in case event was sent with two marks */
-	if (!(mask & inode_mark->mask & ALL_FSNOTIFY_EVENTS))
+	if (!(mask & inode_mark->mask & FSNOTIFY_EVENTS_ON_FS))
 		return 0;
 
 	return ops->handle_inode_event(inode_mark, mask, inode, dir, name, cookie);
diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h
index 1a09400b843b5..224303a0c31e1 100644
--- a/include/linux/fanotify.h
+++ b/include/linux/fanotify.h
@@ -113,27 +113,35 @@
 /* Events that can only be reported with data type FSNOTIFY_EVENT_ERROR */
 #define FANOTIFY_ERROR_EVENTS	(FAN_FS_ERROR)
 
+/* Events that user can request to be notified on filesystem watchers */
+#define FANOTIFY_EVENTS_ON_FS	(FANOTIFY_PATH_EVENTS | \
+				 FANOTIFY_PERM_EVENTS | \
+				 FANOTIFY_INODE_EVENTS | \
+				 FANOTIFY_ERROR_EVENTS)
+
+/* Mount tree monitoring events */
 #define FANOTIFY_MOUNT_EVENTS	(FAN_MNT_ATTACH | FAN_MNT_DETACH)
 
-/* Events that user can request to be notified on */
-#define FANOTIFY_EVENTS		(FANOTIFY_PATH_EVENTS | \
-				 FANOTIFY_INODE_EVENTS | \
-				 FANOTIFY_ERROR_EVENTS | \
-				 FANOTIFY_MOUNT_EVENTS)
+/* Events that user can request to be notified on namepsace watchers */
+#define FANOTIFY_EVENTS_ON_NS	(FANOTIFY_MOUNT_EVENTS)
 
 /* Extra flags that may be reported with event or control handling of events */
 #define FANOTIFY_EVENT_FLAGS	(FAN_EVENT_ON_CHILD | FAN_ONDIR)
 
-/* Events that may be reported to user */
-#define FANOTIFY_OUTGOING_EVENTS	(FANOTIFY_EVENTS | \
-					 FANOTIFY_PERM_EVENTS | \
+/* Events that may be reported to user on filesystem watchers */
+#define FANOTIFY_OUTGOING_FS_EVENTS	(FANOTIFY_EVENTS_ON_FS | \
 					 FAN_Q_OVERFLOW | FAN_ONDIR)
 
+/* Events that may be reported to user on namepsace watchers */
+#define FANOTIFY_OUTGOING_NS_EVENTS	(FANOTIFY_EVENTS_ON_NS | \
+					 FAN_Q_OVERFLOW)
+
 /* Events and flags relevant only for directories */
 #define FANOTIFY_DIRONLY_EVENT_BITS	(FANOTIFY_DIRENT_EVENTS | \
 					 FAN_EVENT_ON_CHILD | FAN_ONDIR)
 
-#define ALL_FANOTIFY_EVENT_BITS		(FANOTIFY_OUTGOING_EVENTS | \
+#define ALL_FANOTIFY_EVENT_BITS		(FANOTIFY_OUTGOING_FS_EVENTS | \
+					 FANOTIFY_OUTGOING_NS_EVENTS | \
 					 FANOTIFY_EVENT_FLAGS)
 
 /* These masks check for invalid bits in permission responses. */
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index 698fc75b0b6d4..8f2821735f068 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -59,22 +59,30 @@
 
 #define FS_PRE_ACCESS		0x00100000	/* Pre-content access hook */
 
-#define FS_MNT_ATTACH		0x01000000	/* Mount was attached */
-#define FS_MNT_DETACH		0x02000000	/* Mount was detached */
-#define FS_MNT_MOVE		(FS_MNT_ATTACH | FS_MNT_DETACH)
+#define FS_RENAME		0x10000000	/* File was renamed */
+
+#define FS_MOVE			(FS_MOVED_FROM | FS_MOVED_TO)
 
 /*
- * Set on inode mark that cares about things that happen to its children.
- * Always set for dnotify and inotify.
+ * Filter flags for watching filesystems
+ *
+ * NOTE: The ON_CHILD flag is set on inode mark that cares about things that
+ * happen to its children.  Always set for dnotify and inotify.
  * Set on inode/sb/mount marks that care about parent/name info.
  */
 #define FS_EVENT_ON_CHILD	0x08000000
-
-#define FS_RENAME		0x10000000	/* File was renamed */
 #define FS_DN_MULTISHOT		0x20000000	/* dnotify multishot */
 #define FS_ISDIR		0x40000000	/* event occurred against dir */
 
-#define FS_MOVE			(FS_MOVED_FROM | FS_MOVED_TO)
+/*
+ * Events that user-space can request when watching namespaces
+ *
+ * NOTE: These values may overload filesystem events, but not event flags
+ */
+#define FS_MNT_ATTACH		0x01000000	/* Mount was attached */
+#define FS_MNT_DETACH		0x02000000	/* Mount was detached */
+#define FS_MNT_MOVE		(FS_MNT_ATTACH | FS_MNT_DETACH)
+
 
 /*
  * Directory entry modification events - reported only to directory
@@ -84,9 +92,6 @@
  */
 #define ALL_FSNOTIFY_DIRENT_EVENTS (FS_CREATE | FS_DELETE | FS_MOVE | FS_RENAME)
 
-/* Mount namespace events */
-#define FSNOTIFY_MNT_EVENTS (FS_MNT_ATTACH | FS_MNT_DETACH)
-
 /* Content events can be used to inspect file content */
 #define FSNOTIFY_CONTENT_PERM_EVENTS (FS_OPEN_PERM | FS_OPEN_EXEC_PERM | \
 				      FS_ACCESS_PERM)
@@ -113,14 +118,23 @@
  */
 #define FS_EVENTS_POSS_TO_PARENT (FS_EVENTS_POSS_ON_CHILD)
 
-/* Events that can be reported to backends */
-#define ALL_FSNOTIFY_EVENTS (ALL_FSNOTIFY_DIRENT_EVENTS | \
-			     FSNOTIFY_MNT_EVENTS | \
+/* Events that can be reported to backends on filesystem watchers */
+#define FSNOTIFY_EVENTS_ON_FS (ALL_FSNOTIFY_DIRENT_EVENTS | \
 			     FS_EVENTS_POSS_ON_CHILD | \
 			     FS_DELETE_SELF | FS_MOVE_SELF | \
 			     FS_UNMOUNT | FS_Q_OVERFLOW | FS_IN_IGNORED | \
 			     FS_ERROR)
 
+/* Mount tree monitoring events */
+#define FSNOTIFY_MNT_EVENTS (FS_MNT_ATTACH | FS_MNT_DETACH)
+
+/* Events that can be reported to backends on namepsace watchers */
+#define FSNOTIFY_EVENTS_ON_NS (FSNOTIFY_MNT_EVENTS | \
+			       FS_Q_OVERFLOW)
+
+/* Events that can be reported to backends */
+#define ALL_FSNOTIFY_EVENTS (FSNOTIFY_EVENTS_ON_FS | FSNOTIFY_EVENTS_ON_NS)
+
 /* Extra flags that may be reported with event or control handling of events */
 #define ALL_FSNOTIFY_FLAGS  (FS_ISDIR | FS_EVENT_ON_CHILD | FS_DN_MULTISHOT)
 
diff --git a/include/uapi/linux/fanotify.h b/include/uapi/linux/fanotify.h
index e710967c7c263..cfcd193aee3e2 100644
--- a/include/uapi/linux/fanotify.h
+++ b/include/uapi/linux/fanotify.h
@@ -4,7 +4,9 @@
 
 #include <linux/types.h>
 
-/* the following events that user-space can register for */
+/*
+ * Events that user-space can request when watching filesystems
+ */
 #define FAN_ACCESS		0x00000001	/* File was accessed */
 #define FAN_MODIFY		0x00000002	/* File was modified */
 #define FAN_ATTRIB		0x00000004	/* Metadata changed */
@@ -28,19 +30,28 @@
 /* #define FAN_DIR_MODIFY	0x00080000 */	/* Deprecated (reserved) */
 
 #define FAN_PRE_ACCESS		0x00100000	/* Pre-content access hook */
-#define FAN_MNT_ATTACH		0x01000000	/* Mount was attached */
-#define FAN_MNT_DETACH		0x02000000	/* Mount was detached */
-
-#define FAN_EVENT_ON_CHILD	0x08000000	/* Interested in child events */
 
 #define FAN_RENAME		0x10000000	/* File was renamed */
 
-#define FAN_ONDIR		0x40000000	/* Event occurred against dir */
-
 /* helper events */
 #define FAN_CLOSE		(FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE) /* close */
 #define FAN_MOVE		(FAN_MOVED_FROM | FAN_MOVED_TO) /* moves */
 
+/*
+ * Filter flags for watching filesystems
+ */
+#define FAN_EVENT_ON_CHILD	0x08000000	/* Interested in child events */
+#define FAN_ONDIR		0x40000000	/* Event occurred against dir */
+
+/*
+ * Events that user-space can request when watching namespaces
+ *
+ * NOTE: These values may overload filesystem events, but not event flags
+ */
+#define FAN_MNT_ATTACH		0x01000000	/* Mount was attached */
+#define FAN_MNT_DETACH		0x02000000	/* Mount was detached */
+
+
 /* flags used for fanotify_init() */
 #define FAN_CLOEXEC		0x00000001
 #define FAN_NONBLOCK		0x00000002
-- 
2.54.0


  parent reply	other threads:[~2026-04-24 17:05 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-24 17:04 [PATCH v2 00/10] fanotify namespace monitoring Amir Goldstein
2026-04-24 17:04 ` [PATCH v2 01/10] fsnotify: rename fsnotify group flag macros Amir Goldstein
2026-04-24 17:04 ` [PATCH v2 02/10] fsnotify: introduce fsnotify group types Amir Goldstein
2026-04-24 17:04 ` Amir Goldstein [this message]
2026-04-24 17:04 ` [PATCH v2 04/10] fanotify: test event->type instead of event mask when possible Amir Goldstein
2026-04-24 17:04 ` [PATCH v2 05/10] fsnotify: do not report mount events with fsnotify() Amir Goldstein
2026-04-24 17:04 ` [PATCH v2 06/10] fanotify: gate fs event classification by group type Amir Goldstein
2026-04-24 17:05 ` [PATCH v2 07/10] fanotify: gate fs events checks in fanotify_mark() " Amir Goldstein
2026-04-24 17:05 ` [PATCH v2 08/10] fanotify: add support for watching the namespaces tree Amir Goldstein
2026-04-24 17:05 ` [PATCH v2 09/10] selftests/filesystems: create fanotify test dir Amir Goldstein
2026-04-24 17:05 ` [PATCH v2 10/10] selftests/filesystems: add fanotify namespace notifications test Amir Goldstein

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260424170503.2096847-4-amir73il@gmail.com \
    --to=amir73il@gmail.com \
    --cc=brauner@kernel.org \
    --cc=jack@suse.cz \
    --cc=linux-fsdevel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox