From: Amir Goldstein <amir73il@xxxxxxxxx> In preparation for pre-content events that report fid info + name, we need a new event type that is both variable length and can be put on a user response wait list. Create an event type FANOTIFY_EVENT_TYPE_FID_NAME_PERM with is a combination of the variable length fanotify_name_event prefixed with a fix length fanotify_perm_event and they share the common fanotify_event memeber. Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx> --- fs/notify/fanotify/fanotify.c | 68 +++++++++++++++++++++++++++-------- fs/notify/fanotify/fanotify.h | 19 +++++++--- 2 files changed, 67 insertions(+), 20 deletions(-) diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index bfe884d624e7..34acb7c16e8b 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -582,20 +582,13 @@ static struct fanotify_event *fanotify_alloc_mnt_event(u64 mnt_id, gfp_t gfp) return &pevent->fae; } -static struct fanotify_event *fanotify_alloc_perm_event(const void *data, - int data_type, - gfp_t gfp) +static void fanotify_init_perm_event(struct fanotify_perm_event *pevent, + const void *data, int data_type) { const struct path *path = fsnotify_data_path(data, data_type); const struct file_range *range = fsnotify_data_file_range(data, data_type); - struct fanotify_perm_event *pevent; - - pevent = kmem_cache_alloc(fanotify_perm_event_cachep, gfp); - if (!pevent) - return NULL; - pevent->fae.type = FANOTIFY_EVENT_TYPE_PATH_PERM; pevent->response = 0; pevent->hdr.type = FAN_RESPONSE_INFO_NONE; pevent->hdr.pad = 0; @@ -606,6 +599,20 @@ static struct fanotify_event *fanotify_alloc_perm_event(const void *data, pevent->ppos = range ? &range->pos : NULL; pevent->count = range ? range->count : 0; path_get(path); +} + +static struct fanotify_event *fanotify_alloc_perm_event(const void *data, + int data_type, + gfp_t gfp) +{ + struct fanotify_perm_event *pevent; + + pevent = kmem_cache_alloc(fanotify_perm_event_cachep, gfp); + if (!pevent) + return NULL; + + pevent->fae.type = FANOTIFY_EVENT_TYPE_PATH_PERM; + fanotify_init_perm_event(pevent, data, data_type); return &pevent->fae; } @@ -636,11 +643,12 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *dir, struct inode *child, struct dentry *moved, unsigned int *hash, - gfp_t gfp) + gfp_t gfp, bool perm) { struct fanotify_name_event *fne; struct fanotify_info *info; struct fanotify_fh *dfh, *ffh; + struct fanotify_perm_event *pevent; struct inode *dir2 = moved ? d_inode(moved->d_parent) : NULL; const struct qstr *name2 = moved ? &moved->d_name : NULL; unsigned int dir_fh_len = fanotify_encode_fh_len(dir); @@ -658,11 +666,26 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *dir, size += FANOTIFY_FH_HDR_LEN + dir2_fh_len; if (child_fh_len) size += FANOTIFY_FH_HDR_LEN + child_fh_len; + if (perm) { + BUILD_BUG_ON(offsetof(struct fanotify_perm_event, fae) + + sizeof(struct fanotify_event) != sizeof(*pevent)); + size += offsetof(struct fanotify_perm_event, fae); + } fne = kmalloc(size, gfp); if (!fne) return NULL; - fne->fae.type = FANOTIFY_EVENT_TYPE_FID_NAME; + /* + * fanotify_name_event follows fanotify_perm_event and they share the + * fae member. + */ + if (perm) { + pevent = (void *)fne; + fne = FANOTIFY_NE(&pevent->fae); + fne->fae.type = FANOTIFY_EVENT_TYPE_FID_NAME_PERM; + } else { + fne->fae.type = FANOTIFY_EVENT_TYPE_FID_NAME; + } fne->fsid = *fsid; *hash ^= fanotify_hash_fsid(fsid); info = &fne->info; @@ -757,6 +780,7 @@ static struct fanotify_event *fanotify_alloc_event( struct inode *dirid = fanotify_dfid_inode(mask, data, data_type, dir); const struct path *path = fsnotify_data_path(data, data_type); u64 mnt_id = fsnotify_data_mnt_id(data, data_type); + bool perm = fanotify_is_perm_event(mask); struct mem_cgroup *old_memcg; struct dentry *moved = NULL; struct inode *child = NULL; @@ -842,14 +866,18 @@ static struct fanotify_event *fanotify_alloc_event( /* Whoever is interested in the event, pays for the allocation. */ old_memcg = set_active_memcg(group->memcg); - if (fanotify_is_perm_event(mask)) { + if (name_event && (file_name || moved || child || perm)) { + event = fanotify_alloc_name_event(dirid, fsid, file_name, child, + moved, &hash, gfp, perm); + if (event && perm) { + fanotify_init_perm_event(FANOTIFY_PERM(event), + data, data_type); + } + } else if (perm) { event = fanotify_alloc_perm_event(data, data_type, gfp); } else if (fanotify_is_error_event(mask)) { event = fanotify_alloc_error_event(group, fsid, data, data_type, &hash); - } else if (name_event && (file_name || moved || child)) { - event = fanotify_alloc_name_event(dirid, fsid, file_name, child, - moved, &hash, gfp); } else if (fid_mode) { event = fanotify_alloc_fid_event(id, fsid, &hash, gfp); } else if (path) { @@ -1037,6 +1065,13 @@ static void fanotify_free_perm_event(struct fanotify_event *event) kmem_cache_free(fanotify_perm_event_cachep, FANOTIFY_PERM(event)); } +static void fanotify_free_name_perm_event(struct fanotify_event *event) +{ + path_put(fanotify_event_path(event)); + /* Variable length perm event */ + kfree(FANOTIFY_PERM(event)); +} + static void fanotify_free_fid_event(struct fanotify_event *event) { struct fanotify_fid_event *ffe = FANOTIFY_FE(event); @@ -1084,6 +1119,9 @@ static void fanotify_free_event(struct fsnotify_group *group, case FANOTIFY_EVENT_TYPE_FID_NAME: fanotify_free_name_event(event); break; + case FANOTIFY_EVENT_TYPE_FID_NAME_PERM: + fanotify_free_name_perm_event(event); + break; case FANOTIFY_EVENT_TYPE_OVERFLOW: kfree(event); break; diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h index b78308975082..f6d25fcf8692 100644 --- a/fs/notify/fanotify/fanotify.h +++ b/fs/notify/fanotify/fanotify.h @@ -240,6 +240,7 @@ static inline void fanotify_info_copy_name2(struct fanotify_info *info, enum fanotify_event_type { FANOTIFY_EVENT_TYPE_FID, /* fixed length */ FANOTIFY_EVENT_TYPE_FID_NAME, /* variable length */ + FANOTIFY_EVENT_TYPE_FID_NAME_PERM, /* variable length perm event */ FANOTIFY_EVENT_TYPE_PATH, FANOTIFY_EVENT_TYPE_PATH_PERM, FANOTIFY_EVENT_TYPE_OVERFLOW, /* struct fanotify_event */ @@ -326,7 +327,8 @@ static inline __kernel_fsid_t *fanotify_event_fsid(struct fanotify_event *event) { if (event->type == FANOTIFY_EVENT_TYPE_FID) return &FANOTIFY_FE(event)->fsid; - else if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME) + else if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME || + event->type == FANOTIFY_EVENT_TYPE_FID_NAME_PERM) return &FANOTIFY_NE(event)->fsid; else if (event->type == FANOTIFY_EVENT_TYPE_FS_ERROR) return &FANOTIFY_EE(event)->fsid; @@ -339,7 +341,8 @@ static inline struct fanotify_fh *fanotify_event_object_fh( { if (event->type == FANOTIFY_EVENT_TYPE_FID) return &FANOTIFY_FE(event)->object_fh; - else if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME) + else if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME || + event->type == FANOTIFY_EVENT_TYPE_FID_NAME_PERM) return fanotify_info_file_fh(&FANOTIFY_NE(event)->info); else if (event->type == FANOTIFY_EVENT_TYPE_FS_ERROR) return &FANOTIFY_EE(event)->object_fh; @@ -350,7 +353,8 @@ static inline struct fanotify_fh *fanotify_event_object_fh( static inline struct fanotify_info *fanotify_event_info( struct fanotify_event *event) { - if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME) + if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME || + event->type == FANOTIFY_EVENT_TYPE_FID_NAME_PERM) return &FANOTIFY_NE(event)->info; else return NULL; @@ -435,7 +439,6 @@ FANOTIFY_ME(struct fanotify_event *event) * user response. */ struct fanotify_perm_event { - struct fanotify_event fae; struct path path; const loff_t *ppos; /* optional file range info */ size_t count; @@ -446,6 +449,11 @@ struct fanotify_perm_event { struct fanotify_response_info_header hdr; struct fanotify_response_info_audit_rule audit_rule; }; + /* + * Overlaps with fanotify_name_event::fae when type is + * FANOTIFY_EVENT_TYPE_FID_NAME_PERM - Keep at the end! + */ + struct fanotify_event fae; }; static inline struct fanotify_perm_event * @@ -487,7 +495,8 @@ static inline const struct path *fanotify_event_path(struct fanotify_event *even { if (event->type == FANOTIFY_EVENT_TYPE_PATH) return &FANOTIFY_PE(event)->path; - else if (event->type == FANOTIFY_EVENT_TYPE_PATH_PERM) + else if (event->type == FANOTIFY_EVENT_TYPE_PATH_PERM || + event->type == FANOTIFY_EVENT_TYPE_FID_NAME_PERM) return &FANOTIFY_PERM(event)->path; else return NULL; -- 2.47.1