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
next prev 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