This fanotify_init() flag is similar to FAN_REPORT_MNT, but instead of enabling the legacy FAN_MNT_* events, it enabled the new FAN_NS_MNT_* events which also report the watcher type bits in event->mask. FAN_REPORT_MNT and FAN_REPORT_MNTID are mutually exclusive and therefore the group accepts either the legacy FAN_MNT_* events or the new FAN_NS_MNT_* events in fanotify_mark(). Signed-off-by: Amir Goldstein --- fs/notify/fanotify/fanotify_user.c | 21 ++++++++++++++------- include/linux/fanotify.h | 9 +++++++-- include/uapi/linux/fanotify.h | 3 ++- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 76bb2574c8239..57cae2b3c96f8 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -852,6 +852,9 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, metadata.vers = FANOTIFY_METADATA_VERSION; metadata.reserved = 0; metadata.mask = fanotify_group_outgoing_events(group, event->mask); + /* Report watcher type part of the event mask */ + if (FAN_GROUP_FLAG(group, FANOTIFY_REPORT_TYPE)) + metadata.mask |= (u64)group->type << FAN_EVENT_TYPE_SHIFT; metadata.pid = pid_vnr(event->pid); /* * For an unprivileged listener, event->pid can be used to identify the @@ -1669,6 +1672,9 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) return -EINVAL; if (flags & (FANOTIFY_FID_BITS | FAN_REPORT_FD_ERROR)) return -EINVAL; + /* The old and new mount event modes are mutually exclusive */ + if ((flags & FAN_REPORT_MNT) && (flags & FAN_REPORT_MNTID)) + return -EINVAL; } if (event_f_flags & ~FANOTIFY_INIT_ALL_EVENT_F_BITS) @@ -1913,6 +1919,10 @@ static bool fanotify_is_valid_mask(struct fsnotify_group *group, int mark_type, BUILD_BUG_ON(FANOTIFY_EVENTS_ON_FILESYSTEM & FANOTIFY_EVENT_FLAGS); BUILD_BUG_ON(FANOTIFY_EVENTS_ON_NAMESPACE & FANOTIFY_EVENT_FLAGS); + /* Only allow high bits in mask when reporting them in event->mask */ + if (!FAN_GROUP_FLAG(group, FANOTIFY_REPORT_TYPE) && fan_mask.type) + return false; + switch (group->type) { case FSNOTIFY_GROUP_TYPE_FILESYSTEM: valid_mask = FANOTIFY_EVENTS_ON_FILESYSTEM | @@ -1923,10 +1933,11 @@ static bool fanotify_is_valid_mask(struct fsnotify_group *group, int mark_type, case FSNOTIFY_GROUP_TYPE_NAMESPACE: /* Only report mount events on mntns mark */ if (mark_type == FAN_MARK_MNTNS && - FAN_GROUP_FLAG(group, FAN_REPORT_MNT)) + FAN_GROUP_FLAG(group, FANOTIFY_MNT_MODES)) valid_mask = FANOTIFY_MOUNT_EVENTS; /* Classify the legacy mount events as namespace events */ - if (fan_mask.mask & (FAN_MNT_ATTACH | FAN_MNT_DETACH)) + if (fan_mask.mask & (FAN_MNT_ATTACH | FAN_MNT_DETACH) && + FAN_GROUP_FLAG(group, FAN_REPORT_MNT)) fan_mask.type = FSNOTIFY_GROUP_TYPE_NAMESPACE; break; } @@ -1963,10 +1974,6 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 __mask, if (ret) return ret; - /* we only use the lower 32 bits as of right now. */ - if (fan_mask.type) - return -EINVAL; - if (flags & ~FANOTIFY_MARK_FLAGS) return -EINVAL; @@ -2251,7 +2258,7 @@ static int __init fanotify_user_setup(void) FANOTIFY_DEFAULT_MAX_USER_MARKS); BUILD_BUG_ON(FANOTIFY_INIT_FLAGS & FANOTIFY_INTERNAL_GROUP_FLAGS); - BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 14); + BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 15); BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 11); fanotify_mark_cache = KMEM_CACHE(fanotify_mark, diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h index 8679f63fd7c97..23c691031cce3 100644 --- a/include/linux/fanotify.h +++ b/include/linux/fanotify.h @@ -25,12 +25,17 @@ #define FANOTIFY_FID_BITS (FAN_REPORT_DFID_NAME_TARGET) +#define FANOTIFY_MNT_MODES (FAN_REPORT_MNT | FAN_REPORT_MNTID) + +/* fanotify_init() flags that report watcher type in event mask */ +#define FANOTIFY_REPORT_TYPE (FAN_REPORT_MNTID) + /* fanotify_init() flags related to information reported with events */ #define FANOTIFY_INFO_MODES (FANOTIFY_FID_BITS | FAN_REPORT_PIDFD | \ - FAN_REPORT_MNT) + FANOTIFY_MNT_MODES) /* fanotify_init() flags that create a namespace watcher */ -#define FANOTIFY_NAMESPACE_INIT_FLAGS (FAN_REPORT_MNT) +#define FANOTIFY_NAMESPACE_INIT_FLAGS (FANOTIFY_MNT_MODES) /* * fanotify_init() flags that require CAP_SYS_ADMIN. diff --git a/include/uapi/linux/fanotify.h b/include/uapi/linux/fanotify.h index b399dd3887299..0744b6770b43d 100644 --- a/include/uapi/linux/fanotify.h +++ b/include/uapi/linux/fanotify.h @@ -90,7 +90,8 @@ #define FAN_REPORT_NAME 0x00000800 /* Report events with name */ #define FAN_REPORT_TARGET_FID 0x00001000 /* Report dirent target id */ #define FAN_REPORT_FD_ERROR 0x00002000 /* event->fd can report error */ -#define FAN_REPORT_MNT 0x00004000 /* Report mount events */ +#define FAN_REPORT_MNT 0x00004000 /* Report FAN_MNT_ events */ +#define FAN_REPORT_MNTID 0x00008000 /* Report FAN_NS_MNT_ events */ /* Convenience macro - FAN_REPORT_NAME requires FAN_REPORT_DIR_FID */ #define FAN_REPORT_DFID_NAME (FAN_REPORT_DIR_FID | FAN_REPORT_NAME) -- 2.55.0