Allocate and encode event->info.fid for a group with FAN_REPORT_FID. Treat failure to allocate fid buffer as failure to allocate event. Treat failure to encode fid by printing a warning but queueing the event without the fid information. Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx> --- fs/notify/fanotify/fanotify.c | 59 +++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index 8192d4b1db21..844b748f0b74 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -13,6 +13,8 @@ #include <linux/wait.h> #include <linux/audit.h> #include <linux/sched/mm.h> +#include <linux/statfs.h> +#include <linux/exportfs.h> #include "fanotify.h" @@ -146,11 +148,55 @@ static u32 fanotify_group_event_mask(struct fsnotify_iter_info *iter_info, ~marks_ignored_mask; } +static struct fanotify_event_fid *fanotify_alloc_fid(const struct path *path, + gfp_t gfp) +{ + struct fanotify_event_fid *fid = NULL; + int dwords, bytes = 0; + struct kstatfs stat; + int err, type; + + dwords = 0; + err = -ENOENT; + type = exportfs_encode_fh(path->dentry, NULL, &dwords, 0); + if (!dwords) + goto out_err; + + err = vfs_statfs(path, &stat); + if (err) + goto out_err; + + /* Treat failure to allocate fid as failure to allocate event */ + bytes = dwords << 2; + fid = kmalloc(FANOTIFY_FID_LEN(bytes), gfp); + if (!fid) + return NULL; + + type = exportfs_encode_fh(path->dentry, (struct fid *)fid->f_handle, + &dwords, 0); + err = -EINVAL; + if (type == FILEID_INVALID || bytes != dwords << 2) + goto out_err; + + fid->handle_bytes = bytes; + fid->handle_type = type; + fid->fsid = stat.f_fsid; + + return fid; + +out_err: + pr_warn_ratelimited("fanotify: failed to encode fid of %pd2 (bytes=%d, err=%i)\n", + path->dentry, bytes, err); + kfree(fid); + return ERR_PTR(err); +} + struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, struct inode *inode, u32 mask, const struct path *path) { struct fanotify_event *event = NULL; + struct fanotify_event_fid *fid = NULL; gfp_t gfp = GFP_KERNEL_ACCOUNT; /* @@ -164,6 +210,16 @@ struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, /* Whoever is interested in the event, pays for the allocation. */ memalloc_use_memcg(group->memcg); + if (path && FAN_GROUP_FLAG(group, FAN_REPORT_FID)) { + fid = fanotify_alloc_fid(path, gfp); + /* Treat failure to allocate fid as failure to allocate event */ + if (!fid) + goto out; + /* Report the event without a file identifier on encode error */ + if (IS_ERR(fid)) + fid = NULL; + } + if (fanotify_is_perm_event(mask)) { struct fanotify_perm_event *pevent; @@ -184,8 +240,7 @@ init: __maybe_unused else event->pid = get_pid(task_tgid(current)); if (FAN_GROUP_FLAG(group, FAN_REPORT_FID)) { - /* TODO: allocate buffer and encode file handle */ - fanotify_set_fid(event, NULL); + fanotify_set_fid(event, fid); } else if (path) { event->path = *path; path_get(&event->path); -- 2.17.1