In the special case of MOVED_FROM event, if we are reporting the child fid due to FAN_REPORT_TARGET_FID init flag, we also report the new parent and name. The new parent and name are reported using a new info record of type FAN_EVENT_INFO_TYPE_DFID_NAME2 that follows the info record of type FAN_EVENT_INFO_TYPE_DFID_NAME with the old parent and name. Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx> --- fs/notify/fanotify/fanotify.h | 17 +++++++++++++++++ fs/notify/fanotify/fanotify_user.c | 29 +++++++++++++++++++++++++++-- include/uapi/linux/fanotify.h | 1 + 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h index 0864e7efe23c..26d471aab054 100644 --- a/fs/notify/fanotify/fanotify.h +++ b/fs/notify/fanotify/fanotify.h @@ -339,6 +339,13 @@ static inline int fanotify_event_dir_fh_len(struct fanotify_event *event) return info ? fanotify_info_dir_fh_len(info) : 0; } +static inline int fanotify_event_dir2_fh_len(struct fanotify_event *event) +{ + struct fanotify_info *info = fanotify_event_info(event); + + return info ? fanotify_info_dir2_fh_len(info) : 0; +} + static inline bool fanotify_event_has_object_fh(struct fanotify_event *event) { /* For error events, even zeroed fh are reported. */ @@ -352,6 +359,16 @@ static inline bool fanotify_event_has_dir_fh(struct fanotify_event *event) return fanotify_event_dir_fh_len(event) > 0; } +/* For MOVED_FROM event with FAN_REPORT_TARGET_FID */ +static inline bool fanotify_event_has_two_names(struct fanotify_event *event) +{ + struct fanotify_info *info = fanotify_event_info(event); + + return info && info->name_len && info->name2_len && + fanotify_info_dir_fh_len(info) > 0 && + fanotify_info_dir2_fh_len(info) > 0; +} + struct fanotify_path_event { struct fanotify_event fae; struct path path; diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index d973f36676a9..d6420e10740d 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -134,7 +134,7 @@ static size_t fanotify_event_len(unsigned int info_mode, { size_t event_len = FAN_EVENT_METADATA_LEN; struct fanotify_info *info; - int dir_fh_len; + int dir_fh_len, dir2_fh_len; int fh_len; int dot_len = 0; @@ -149,6 +149,11 @@ static size_t fanotify_event_len(unsigned int info_mode, if (fanotify_event_has_dir_fh(event)) { dir_fh_len = fanotify_event_dir_fh_len(event); event_len += fanotify_fid_info_len(dir_fh_len, info->name_len); + if (fanotify_event_has_two_names(event)) { + dir2_fh_len = fanotify_event_dir2_fh_len(event); + event_len += fanotify_fid_info_len(dir2_fh_len, + info->name2_len); + } } else if ((info_mode & FAN_REPORT_NAME) && (event->mask & FAN_ONDIR)) { /* @@ -379,6 +384,7 @@ static int copy_fid_info_to_user(__kernel_fsid_t *fsid, struct fanotify_fh *fh, return -EFAULT; break; case FAN_EVENT_INFO_TYPE_DFID_NAME: + case FAN_EVENT_INFO_TYPE_DFID_NAME2: if (WARN_ON_ONCE(!name || !name_len)) return -EFAULT; break; @@ -478,7 +484,10 @@ static int copy_info_records_to_user(struct fanotify_event *event, unsigned int pidfd_mode = info_mode & FAN_REPORT_PIDFD; /* - * Event info records order is as follows: dir fid + name, child fid. + * Event info records order is as follows: + * 1. dir fid + name + * 2. (optional) new dir fid + new name + * 3. (optional) child fid */ if (fanotify_event_has_dir_fh(event)) { info_type = info->name_len ? FAN_EVENT_INFO_TYPE_DFID_NAME : @@ -496,6 +505,22 @@ static int copy_info_records_to_user(struct fanotify_event *event, total_bytes += ret; } + /* New dir fid + name can only be reported after old dir fid + name */ + if (info_type && fanotify_event_has_two_names(event)) { + info_type = FAN_EVENT_INFO_TYPE_DFID_NAME2; + ret = copy_fid_info_to_user(fanotify_event_fsid(event), + fanotify_info_dir2_fh(info), + info_type, + fanotify_info_name2(info), + info->name2_len, buf, count); + if (ret < 0) + return ret; + + buf += ret; + count -= ret; + total_bytes += ret; + } + if (fanotify_event_has_object_fh(event)) { const char *dot = NULL; int dot_len = 0; diff --git a/include/uapi/linux/fanotify.h b/include/uapi/linux/fanotify.h index f9202ce31b0d..1ac31a912cea 100644 --- a/include/uapi/linux/fanotify.h +++ b/include/uapi/linux/fanotify.h @@ -131,6 +131,7 @@ struct fanotify_event_metadata { #define FAN_EVENT_INFO_TYPE_DFID 3 #define FAN_EVENT_INFO_TYPE_PIDFD 4 #define FAN_EVENT_INFO_TYPE_ERROR 5 +#define FAN_EVENT_INFO_TYPE_DFID_NAME2 6 /* For FAN_MOVED_FROM */ /* Variable length info record following event metadata */ struct fanotify_event_info_header { -- 2.33.1