From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wr1-f67.google.com ([209.85.221.67]:40644 "EHLO mail-wr1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726356AbeKZAfZ (ORCPT ); Sun, 25 Nov 2018 19:35:25 -0500 Received: by mail-wr1-f67.google.com with SMTP id p4so16223909wrt.7 for ; Sun, 25 Nov 2018 05:44:18 -0800 (PST) From: Amir Goldstein To: Jan Kara Cc: Matthew Bobrowski , linux-fsdevel@vger.kernel.org Subject: [PATCH v3 07/13] fanotify: copy event fid info to user Date: Sun, 25 Nov 2018 15:43:46 +0200 Message-Id: <20181125134352.21499-8-amir73il@gmail.com> In-Reply-To: <20181125134352.21499-1-amir73il@gmail.com> References: <20181125134352.21499-1-amir73il@gmail.com> Sender: linux-fsdevel-owner@vger.kernel.org List-ID: If group requested FAN_REPORT_FID and event has file identifier copy that information to user reading the event after reading event metadata. metadata->event_len includes the length of the fid information. Signed-off-by: Amir Goldstein --- fs/notify/fanotify/fanotify.h | 3 ++ fs/notify/fanotify/fanotify_user.c | 72 +++++++++++++++++++++++++++--- 2 files changed, 68 insertions(+), 7 deletions(-) diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h index a79dcbd41702..0e57fa0674d7 100644 --- a/fs/notify/fanotify/fanotify.h +++ b/fs/notify/fanotify/fanotify.h @@ -10,6 +10,9 @@ extern struct kmem_cache *fanotify_perm_event_cachep; /* The size of the variable length buffer storing fsid and file handle */ #define FANOTIFY_FID_LEN(handle_bytes) \ (sizeof(struct fanotify_event_fid) + (handle_bytes)) +#define FANOTIFY_FID_INFO_LEN(event) \ + (sizeof(struct fanotify_event_info) + \ + FANOTIFY_FID_LEN((event)->info.fid->handle_bytes)) struct fanotify_info { struct fanotify_event_fid *fid; diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 47e8bf3bcd28..ea8e81a3e80b 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -47,6 +47,16 @@ struct kmem_cache *fanotify_mark_cache __read_mostly; struct kmem_cache *fanotify_event_cachep __read_mostly; struct kmem_cache *fanotify_perm_event_cachep __read_mostly; +static int round_event_fid_len(struct fsnotify_event *fsn_event) +{ + struct fanotify_event *event = FANOTIFY_E(fsn_event); + + if (!FANOTIFY_HAS_FID(event)) + return 0; + + return roundup(FANOTIFY_FID_INFO_LEN(event), FAN_EVENT_METADATA_LEN); +} + /* * Get an fsnotify notification event if one exists and is small * enough to fit in "count". Return an error pointer if the count @@ -57,6 +67,9 @@ struct kmem_cache *fanotify_perm_event_cachep __read_mostly; static struct fsnotify_event *get_one_event(struct fsnotify_group *group, size_t count) { + size_t event_size = FAN_EVENT_METADATA_LEN; + struct fsnotify_event *event; + assert_spin_locked(&group->notification_lock); pr_debug("%s: group=%p count=%zd\n", __func__, group, count); @@ -64,11 +77,18 @@ static struct fsnotify_event *get_one_event(struct fsnotify_group *group, if (fsnotify_notify_queue_is_empty(group)) return NULL; - if (FAN_EVENT_METADATA_LEN > count) + if (FAN_GROUP_FLAG(group, FAN_REPORT_FID)) { + event = fsnotify_peek_first_event(group); + event_size += round_event_fid_len(event); + } + + if (event_size > count) return ERR_PTR(-EINVAL); - /* held the notification_lock the whole time, so this is the - * same event we peeked above */ + /* + * Held the notification_lock the whole time, so this is the + * same event we peeked above + */ return fsnotify_remove_first_event(group); } @@ -129,7 +149,7 @@ static int fill_event_metadata(struct fsnotify_group *group, group, metadata, fsn_event); *file = NULL; - event = container_of(fsn_event, struct fanotify_event, fse); + event = FANOTIFY_E(fsn_event); metadata->event_len = FAN_EVENT_METADATA_LEN; metadata->metadata_len = FAN_EVENT_METADATA_LEN; metadata->vers = FANOTIFY_METADATA_VERSION; @@ -139,6 +159,7 @@ static int fill_event_metadata(struct fsnotify_group *group, if (FAN_GROUP_FLAG(group, FAN_REPORT_FID) || unlikely(fsn_event->mask & FAN_Q_OVERFLOW)) { metadata->fd = FAN_NOFD; + metadata->event_len += round_event_fid_len(fsn_event); } else { metadata->fd = create_fd(group, event, file); if (metadata->fd < 0) @@ -208,6 +229,38 @@ static int process_access_response(struct fsnotify_group *group, return 0; } +static int copy_fid_to_user(struct fsnotify_event *fsn_event, char __user *buf) +{ + struct fanotify_event *event = FANOTIFY_E(fsn_event); + struct fanotify_event_info ei; + size_t fid_len; + size_t pad_len = round_event_fid_len(fsn_event); + + if (!pad_len) + return 0; + + /* Copy event info header followed by fid buffer */ + fid_len = FANOTIFY_FID_INFO_LEN(event); + pad_len -= fid_len; + ei.info_type = FAN_EVENT_INFO_TYPE_FID; + ei.reserved = 0; + ei.info_len = fid_len; + if (copy_to_user(buf, &ei, sizeof(ei))) + return -EFAULT; + + buf += sizeof(ei); + fid_len -= sizeof(ei); + if (copy_to_user(buf, event->info.fid, fid_len)) + return -EFAULT; + + /* Pad with 0's */ + buf += fid_len; + if (pad_len && clear_user(buf, pad_len)) + return -EFAULT; + + return 0; +} + static ssize_t copy_event_to_user(struct fsnotify_group *group, struct fsnotify_event *event, char __user *buf) @@ -224,15 +277,20 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, fd = fanotify_event_metadata.fd; ret = -EFAULT; - if (copy_to_user(buf, &fanotify_event_metadata, - fanotify_event_metadata.event_len)) + if (copy_to_user(buf, &fanotify_event_metadata, FAN_EVENT_METADATA_LEN)) goto out_close_fd; if (fanotify_is_perm_event(event->mask)) FANOTIFY_PE(event)->fd = fd; - if (fd != FAN_NOFD) + if (fd != FAN_NOFD) { fd_install(fd, f); + } else if (FAN_GROUP_FLAG(group, FAN_REPORT_FID)) { + ret = copy_fid_to_user(event, buf + FAN_EVENT_METADATA_LEN); + if (ret < 0) + return ret; + } + return fanotify_event_metadata.event_len; out_close_fd: -- 2.17.1