@@ -47,6 +47,18 @@ struct kmem_cache *fanotify_mark_cache __read_mostly;
47
47
struct kmem_cache * fanotify_event_cachep __read_mostly ;
48
48
struct kmem_cache * fanotify_perm_event_cachep __read_mostly ;
49
49
50
+ #define FANOTIFY_EVENT_ALIGN 4
51
+
52
+ static int fanotify_event_info_len (struct fanotify_event * event )
53
+ {
54
+ if (!fanotify_event_has_fid (event ))
55
+ return 0 ;
56
+
57
+ return roundup (sizeof (struct fanotify_event_info_fid ) +
58
+ sizeof (struct file_handle ) + event -> fh_len ,
59
+ FANOTIFY_EVENT_ALIGN );
60
+ }
61
+
50
62
/*
51
63
* Get an fsnotify notification event if one exists and is small
52
64
* enough to fit in "count". Return an error pointer if the count
@@ -57,18 +69,28 @@ struct kmem_cache *fanotify_perm_event_cachep __read_mostly;
57
69
static struct fsnotify_event * get_one_event (struct fsnotify_group * group ,
58
70
size_t count )
59
71
{
72
+ size_t event_size = FAN_EVENT_METADATA_LEN ;
73
+ struct fanotify_event * event ;
74
+
60
75
assert_spin_locked (& group -> notification_lock );
61
76
62
77
pr_debug ("%s: group=%p count=%zd\n" , __func__ , group , count );
63
78
64
79
if (fsnotify_notify_queue_is_empty (group ))
65
80
return NULL ;
66
81
67
- if (FAN_EVENT_METADATA_LEN > count )
82
+ if (FAN_GROUP_FLAG (group , FAN_REPORT_FID )) {
83
+ event = FANOTIFY_E (fsnotify_peek_first_event (group ));
84
+ event_size += fanotify_event_info_len (event );
85
+ }
86
+
87
+ if (event_size > count )
68
88
return ERR_PTR (- EINVAL );
69
89
70
- /* held the notification_lock the whole time, so this is the
71
- * same event we peeked above */
90
+ /*
91
+ * Held the notification_lock the whole time, so this is the
92
+ * same event we peeked above
93
+ */
72
94
return fsnotify_remove_first_event (group );
73
95
}
74
96
@@ -174,6 +196,48 @@ static int process_access_response(struct fsnotify_group *group,
174
196
return 0 ;
175
197
}
176
198
199
+ static int copy_fid_to_user (struct fanotify_event * event , char __user * buf )
200
+ {
201
+ struct fanotify_event_info_fid info = { };
202
+ struct file_handle handle = { };
203
+ size_t fh_len = event -> fh_len ;
204
+ size_t len = fanotify_event_info_len (event );
205
+
206
+ if (!len )
207
+ return 0 ;
208
+
209
+ if (WARN_ON_ONCE (len < sizeof (info ) + sizeof (handle ) + fh_len ))
210
+ return - EFAULT ;
211
+
212
+ /* Copy event info fid header followed by vaiable sized file handle */
213
+ info .hdr .info_type = FAN_EVENT_INFO_TYPE_FID ;
214
+ info .hdr .len = len ;
215
+ info .fsid = event -> fid .fsid ;
216
+ if (copy_to_user (buf , & info , sizeof (info )))
217
+ return - EFAULT ;
218
+
219
+ buf += sizeof (info );
220
+ len -= sizeof (info );
221
+ handle .handle_type = event -> fh_type ;
222
+ handle .handle_bytes = fh_len ;
223
+ if (copy_to_user (buf , & handle , sizeof (handle )))
224
+ return - EFAULT ;
225
+
226
+ buf += sizeof (handle );
227
+ len -= sizeof (handle );
228
+ if (copy_to_user (buf , fanotify_event_fh (event ), fh_len ))
229
+ return - EFAULT ;
230
+
231
+ /* Pad with 0's */
232
+ buf += fh_len ;
233
+ len -= fh_len ;
234
+ WARN_ON_ONCE (len < 0 || len >= FANOTIFY_EVENT_ALIGN );
235
+ if (len > 0 && clear_user (buf , len ))
236
+ return - EFAULT ;
237
+
238
+ return 0 ;
239
+ }
240
+
177
241
static ssize_t copy_event_to_user (struct fsnotify_group * group ,
178
242
struct fsnotify_event * fsn_event ,
179
243
char __user * buf , size_t count )
@@ -197,6 +261,8 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
197
261
fd = create_fd (group , event , & f );
198
262
if (fd < 0 )
199
263
return fd ;
264
+ } else if (fanotify_event_has_fid (event )) {
265
+ metadata .event_len += fanotify_event_info_len (event );
200
266
}
201
267
metadata .fd = fd ;
202
268
@@ -208,14 +274,20 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
208
274
if (WARN_ON_ONCE (metadata .event_len > count ))
209
275
goto out_close_fd ;
210
276
211
- if (copy_to_user (buf , & metadata , metadata . event_len ))
277
+ if (copy_to_user (buf , & metadata , FAN_EVENT_METADATA_LEN ))
212
278
goto out_close_fd ;
213
279
214
280
if (fanotify_is_perm_event (event -> mask ))
215
281
FANOTIFY_PE (fsn_event )-> fd = fd ;
216
282
217
- if (fd != FAN_NOFD )
283
+ if (fanotify_event_has_path ( event )) {
218
284
fd_install (fd , f );
285
+ } else if (fanotify_event_has_fid (event )) {
286
+ ret = copy_fid_to_user (event , buf + FAN_EVENT_METADATA_LEN );
287
+ if (ret < 0 )
288
+ return ret ;
289
+ }
290
+
219
291
return metadata .event_len ;
220
292
221
293
out_close_fd :
0 commit comments