summaryrefslogtreecommitdiffstats
path: root/fs/notify
diff options
context:
space:
mode:
authorAmir Goldstein <amir73il@gmail.com>2019-01-10 12:04:42 -0500
committerJan Kara <jack@suse.cz>2019-02-07 10:38:36 -0500
commit83b535d2897d1d4ce22c2f656a53bdd7865d1df3 (patch)
tree4947d4867aa2f09e2d10d1de0657466b3e4e720e /fs/notify
parent0321e03cb4572fb3b56582bcb4927c1fe985b191 (diff)
fanotify: support events with data type FSNOTIFY_EVENT_INODE
When event data type is FSNOTIFY_EVENT_INODE, we don't have a refernece to the mount, so we will not be able to open a file descriptor when user reads the event. However, if the listener has enabled reporting file identifier with the FAN_REPORT_FID init flag, we allow reporting those events and we use an identifier inode to encode fid. The inode to use as identifier when reporting fid depends on the event. For dirent modification events, we report the modified directory inode and we report the "victim" inode otherwise. For example: FS_ATTRIB reports the child inode even if reported on a watched parent. FS_CREATE reports the modified dir inode and not the created inode. [JK: Fixup condition in fanotify_group_event_mask()] Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/notify')
-rw-r--r--fs/notify/fanotify/fanotify.c63
-rw-r--r--fs/notify/fanotify/fanotify.h2
-rw-r--r--fs/notify/fanotify/fanotify_user.c3
3 files changed, 46 insertions, 22 deletions
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index 195fc9fe0150..974239b03442 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -96,7 +96,7 @@ static int fanotify_get_response(struct fsnotify_group *group,
96 96
97 pr_debug("%s: group=%p event=%p about to return ret=%d\n", __func__, 97 pr_debug("%s: group=%p event=%p about to return ret=%d\n", __func__,
98 group, event, ret); 98 group, event, ret);
99 99
100 return ret; 100 return ret;
101} 101}
102 102
@@ -106,9 +106,10 @@ static int fanotify_get_response(struct fsnotify_group *group,
106 * been included within the event mask, but have not been explicitly 106 * been included within the event mask, but have not been explicitly
107 * requested by the user, will not be present in the returned mask. 107 * requested by the user, will not be present in the returned mask.
108 */ 108 */
109static u32 fanotify_group_event_mask(struct fsnotify_iter_info *iter_info, 109static u32 fanotify_group_event_mask(struct fsnotify_group *group,
110 u32 event_mask, const void *data, 110 struct fsnotify_iter_info *iter_info,
111 int data_type) 111 u32 event_mask, const void *data,
112 int data_type)
112{ 113{
113 __u32 marks_mask = 0, marks_ignored_mask = 0; 114 __u32 marks_mask = 0, marks_ignored_mask = 0;
114 const struct path *path = data; 115 const struct path *path = data;
@@ -118,14 +119,14 @@ static u32 fanotify_group_event_mask(struct fsnotify_iter_info *iter_info,
118 pr_debug("%s: report_mask=%x mask=%x data=%p data_type=%d\n", 119 pr_debug("%s: report_mask=%x mask=%x data=%p data_type=%d\n",
119 __func__, iter_info->report_mask, event_mask, data, data_type); 120 __func__, iter_info->report_mask, event_mask, data, data_type);
120 121
121 /* If we don't have enough info to send an event to userspace say no */ 122 if (!FAN_GROUP_FLAG(group, FAN_REPORT_FID)) {
122 if (data_type != FSNOTIFY_EVENT_PATH) 123 /* Do we have path to open a file descriptor? */
123 return 0; 124 if (data_type != FSNOTIFY_EVENT_PATH)
124 125 return 0;
125 /* Sorry, fanotify only gives a damn about files and dirs */ 126 /* Path type events are only relevant for files and dirs */
126 if (!d_is_reg(path->dentry) && 127 if (!d_is_reg(path->dentry) && !d_can_lookup(path->dentry))
127 !d_can_lookup(path->dentry)) 128 return 0;
128 return 0; 129 }
129 130
130 fsnotify_foreach_obj_type(type) { 131 fsnotify_foreach_obj_type(type) {
131 if (!fsnotify_iter_should_report_type(iter_info, type)) 132 if (!fsnotify_iter_should_report_type(iter_info, type))
@@ -198,13 +199,34 @@ out_err:
198 return FILEID_INVALID; 199 return FILEID_INVALID;
199} 200}
200 201
202/*
203 * The inode to use as identifier when reporting fid depends on the event.
204 * Report the modified directory inode on dirent modification events.
205 * Report the "victim" inode otherwise.
206 * For example:
207 * FS_ATTRIB reports the child inode even if reported on a watched parent.
208 * FS_CREATE reports the modified dir inode and not the created inode.
209 */
210static struct inode *fanotify_fid_inode(struct inode *to_tell, u32 event_mask,
211 const void *data, int data_type)
212{
213 if (event_mask & ALL_FSNOTIFY_DIRENT_EVENTS)
214 return to_tell;
215 else if (data_type == FSNOTIFY_EVENT_INODE)
216 return (struct inode *)data;
217 else if (data_type == FSNOTIFY_EVENT_PATH)
218 return d_inode(((struct path *)data)->dentry);
219 return NULL;
220}
221
201struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, 222struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
202 struct inode *inode, u32 mask, 223 struct inode *inode, u32 mask,
203 const struct path *path, 224 const void *data, int data_type,
204 __kernel_fsid_t *fsid) 225 __kernel_fsid_t *fsid)
205{ 226{
206 struct fanotify_event *event = NULL; 227 struct fanotify_event *event = NULL;
207 gfp_t gfp = GFP_KERNEL_ACCOUNT; 228 gfp_t gfp = GFP_KERNEL_ACCOUNT;
229 struct inode *id = fanotify_fid_inode(inode, mask, data, data_type);
208 230
209 /* 231 /*
210 * For queues with unlimited length lost events are not expected and 232 * For queues with unlimited length lost events are not expected and
@@ -238,13 +260,12 @@ init: __maybe_unused
238 else 260 else
239 event->pid = get_pid(task_tgid(current)); 261 event->pid = get_pid(task_tgid(current));
240 event->fh_len = 0; 262 event->fh_len = 0;
241 if (path && FAN_GROUP_FLAG(group, FAN_REPORT_FID)) { 263 if (id && FAN_GROUP_FLAG(group, FAN_REPORT_FID)) {
242 /* Report the event without a file identifier on encode error */ 264 /* Report the event without a file identifier on encode error */
243 event->fh_type = fanotify_encode_fid(event, 265 event->fh_type = fanotify_encode_fid(event, id, gfp, fsid);
244 d_inode(path->dentry), gfp, fsid); 266 } else if (data_type == FSNOTIFY_EVENT_PATH) {
245 } else if (path) {
246 event->fh_type = FILEID_ROOT; 267 event->fh_type = FILEID_ROOT;
247 event->path = *path; 268 event->path = *((struct path *)data);
248 path_get(&event->path); 269 path_get(&event->path);
249 } else { 270 } else {
250 event->fh_type = FILEID_INVALID; 271 event->fh_type = FILEID_INVALID;
@@ -305,7 +326,8 @@ static int fanotify_handle_event(struct fsnotify_group *group,
305 326
306 BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 12); 327 BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 12);
307 328
308 mask = fanotify_group_event_mask(iter_info, mask, data, data_type); 329 mask = fanotify_group_event_mask(group, iter_info, mask, data,
330 data_type);
309 if (!mask) 331 if (!mask)
310 return 0; 332 return 0;
311 333
@@ -324,7 +346,8 @@ static int fanotify_handle_event(struct fsnotify_group *group,
324 if (FAN_GROUP_FLAG(group, FAN_REPORT_FID)) 346 if (FAN_GROUP_FLAG(group, FAN_REPORT_FID))
325 fsid = fanotify_get_fsid(iter_info); 347 fsid = fanotify_get_fsid(iter_info);
326 348
327 event = fanotify_alloc_event(group, inode, mask, data, &fsid); 349 event = fanotify_alloc_event(group, inode, mask, data, data_type,
350 &fsid);
328 ret = -ENOMEM; 351 ret = -ENOMEM;
329 if (unlikely(!event)) { 352 if (unlikely(!event)) {
330 /* 353 /*
diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h
index 5b072afa4e19..e84d68c6840a 100644
--- a/fs/notify/fanotify/fanotify.h
+++ b/fs/notify/fanotify/fanotify.h
@@ -132,5 +132,5 @@ static inline struct fanotify_event *FANOTIFY_E(struct fsnotify_event *fse)
132 132
133struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, 133struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
134 struct inode *inode, u32 mask, 134 struct inode *inode, u32 mask,
135 const struct path *path, 135 const void *data, int data_type,
136 __kernel_fsid_t *fsid); 136 __kernel_fsid_t *fsid);
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index 396de6edad2b..bf06fd6ef761 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -800,7 +800,8 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
800 atomic_inc(&user->fanotify_listeners); 800 atomic_inc(&user->fanotify_listeners);
801 group->memcg = get_mem_cgroup_from_mm(current->mm); 801 group->memcg = get_mem_cgroup_from_mm(current->mm);
802 802
803 oevent = fanotify_alloc_event(group, NULL, FS_Q_OVERFLOW, NULL, NULL); 803 oevent = fanotify_alloc_event(group, NULL, FS_Q_OVERFLOW, NULL,
804 FSNOTIFY_EVENT_NONE, NULL);
804 if (unlikely(!oevent)) { 805 if (unlikely(!oevent)) {
805 fd = -ENOMEM; 806 fd = -ENOMEM;
806 goto out_destroy_group; 807 goto out_destroy_group;