Re: [PATCH v2 04/16] fanotify: introduce FAN_PRE_ACCESS permission event

Christian Brauner
2024-08-09T11:57:22Z

On Thu, Aug 08, 2024 at 03:27:06PM GMT, Josef Bacik wrote:
> From: Amir Goldstein <amir73il@gmail.com>
>
> Similar to FAN_ACCESS_PERM permission event, but it is only allowed with
> class FAN_CLASS_PRE_CONTENT and only allowed on regular files and dirs.
>
> Unlike FAN_ACCESS_PERM, it is safe to write to the file being accessed
> in the context of the event handler.
>
> This pre-content event is meant to be used by hierarchical storage
> managers that want to fill the content of files on first read access.
>
> Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> ---
> fs/notify/fanotify/fanotify.c | 3 ++-
> fs/notify/fanotify/fanotify_user.c | 17 ++++++++++++++---
> include/linux/fanotify.h | 14 ++++++++++----
> include/uapi/linux/fanotify.h | 2 ++
> 4 files changed, 28 insertions(+), 8 deletions(-)
>
> diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
> index 224bccaab4cc..7dac8e4486df 100644
> --- a/fs/notify/fanotify/fanotify.c
> +++ b/fs/notify/fanotify/fanotify.c
> @@ -910,8 +910,9 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask,
> BUILD_BUG_ON(FAN_OPEN_EXEC_PERM != FS_OPEN_EXEC_PERM);
> BUILD_BUG_ON(FAN_FS_ERROR != FS_ERROR);
> BUILD_BUG_ON(FAN_RENAME != FS_RENAME);
> + BUILD_BUG_ON(FAN_PRE_ACCESS != FS_PRE_ACCESS);
>
> - BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 21);
> + BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 22);
>
> mask = fanotify_group_event_mask(group, iter_info, &match_mask,
> mask, data, data_type, dir);
> diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
> index 2e2fba8a9d20..c294849e474f 100644
> --- a/fs/notify/fanotify/fanotify_user.c
> +++ b/fs/notify/fanotify/fanotify_user.c
> @@ -1628,6 +1628,7 @@ static int fanotify_events_supported(struct fsnotify_group *group,
> unsigned int flags)
> {
> unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS;
> + bool is_dir = d_is_dir(path->dentry);
> /* Strict validation of events in non-dir inode mask with v5.17+ APIs */
> bool strict_dir_events = FAN_GROUP_FLAG(group, FAN_REPORT_TARGET_FID) ||
> (mask & FAN_RENAME) ||
> @@ -1665,9 +1666,15 @@ static int fanotify_events_supported(struct fsnotify_group *group,
> * but because we always allowed it, error only when using new APIs.
> */
> if (strict_dir_events && mark_type == FAN_MARK_INODE &&
> - !d_is_dir(path->dentry) && (mask & FANOTIFY_DIRONLY_EVENT_BITS))
> + !is_dir && (mask & FANOTIFY_DIRONLY_EVENT_BITS))
> return -ENOTDIR;
>
> + /* Pre-content events are only supported on regular files and dirs */
> + if (mask & FANOTIFY_PRE_CONTENT_EVENTS) {
> + if (!is_dir && !d_is_reg(path->dentry))
> + return -EINVAL;
> + }
> +
> return 0;
> }
>
> @@ -1769,11 +1776,15 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
> goto fput_and_out;
>
> /*
> - * Permission events require minimum priority FAN_CLASS_CONTENT.
> + * Permission events are not allowed for FAN_CLASS_NOTIF.
> + * Pre-content permission events are not allowed for FAN_CLASS_CONTENT.
> */
> ret = -EINVAL;
> if (mask & FANOTIFY_PERM_EVENTS &&
> - group->priority < FSNOTIFY_PRIO_CONTENT)
> + group->priority == FSNOTIFY_PRIO_NORMAL)
> + goto fput_and_out;
> + else if (mask & FANOTIFY_PRE_CONTENT_EVENTS &&
> + group->priority == FSNOTIFY_PRIO_CONTENT)
> goto fput_and_out;
>
> if (mask & FAN_FS_ERROR &&
> diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h
> index 4f1c4f603118..5c811baf44d2 100644
> --- a/include/linux/fanotify.h
> +++ b/include/linux/fanotify.h
> @@ -88,6 +88,16 @@
> #define FANOTIFY_DIRENT_EVENTS (FAN_MOVE | FAN_CREATE | FAN_DELETE | \
> FAN_RENAME)
>
> +/* Content events can be used to inspect file content */
> +#define FANOTIFY_CONTENT_PERM_EVENTS (FAN_OPEN_PERM | FAN_OPEN_EXEC_PERM | \
> + FAN_ACCESS_PERM)
> +/* Pre-content events can be used to fill file content */
> +#define FANOTIFY_PRE_CONTENT_EVENTS (FAN_PRE_ACCESS)
> +
> +/* Events that require a permission response from user */
> +#define FANOTIFY_PERM_EVENTS (FANOTIFY_CONTENT_PERM_EVENTS | \
> + FANOTIFY_PRE_CONTENT_EVENTS)
> +

Fwiw, this is one of my pet peeves with fanotify. It uses nesting of
defines very liberally. For the occasional reader that needs to
understand what flags are checked for its quite an excercise having to
go back and resolving multiple levels of defines. I would humbly urge
some restraint in that area.

Reviewed-by: Christian Brauner <brauner@kernel.org>