@@ -216,7 +216,7 @@ static int process_access_response(struct fsnotify_group *group,
216
216
}
217
217
218
218
static int copy_info_to_user (__kernel_fsid_t * fsid , struct fanotify_fh * fh ,
219
- const char * name , size_t name_len ,
219
+ int info_type , const char * name , size_t name_len ,
220
220
char __user * buf , size_t count )
221
221
{
222
222
struct fanotify_event_info_fid info = { };
@@ -229,7 +229,7 @@ static int copy_info_to_user(__kernel_fsid_t *fsid, struct fanotify_fh *fh,
229
229
pr_debug ("%s: fh_len=%zu name_len=%zu, info_len=%zu, count=%zu\n" ,
230
230
__func__ , fh_len , name_len , info_len , count );
231
231
232
- if (!fh_len || ( name && ! name_len ) )
232
+ if (!fh_len )
233
233
return 0 ;
234
234
235
235
if (WARN_ON_ONCE (len < sizeof (info ) || len > count ))
@@ -239,8 +239,21 @@ static int copy_info_to_user(__kernel_fsid_t *fsid, struct fanotify_fh *fh,
239
239
* Copy event info fid header followed by variable sized file handle
240
240
* and optionally followed by variable sized filename.
241
241
*/
242
- info .hdr .info_type = name_len ? FAN_EVENT_INFO_TYPE_DFID_NAME :
243
- FAN_EVENT_INFO_TYPE_FID ;
242
+ switch (info_type ) {
243
+ case FAN_EVENT_INFO_TYPE_FID :
244
+ case FAN_EVENT_INFO_TYPE_DFID :
245
+ if (WARN_ON_ONCE (name_len ))
246
+ return - EFAULT ;
247
+ break ;
248
+ case FAN_EVENT_INFO_TYPE_DFID_NAME :
249
+ if (WARN_ON_ONCE (!name || !name_len ))
250
+ return - EFAULT ;
251
+ break ;
252
+ default :
253
+ return - EFAULT ;
254
+ }
255
+
256
+ info .hdr .info_type = info_type ;
244
257
info .hdr .len = len ;
245
258
info .fsid = * fsid ;
246
259
if (copy_to_user (buf , & info , sizeof (info )))
@@ -304,8 +317,10 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
304
317
struct fanotify_event_metadata metadata ;
305
318
struct path * path = fanotify_event_path (event );
306
319
struct fanotify_info * info = fanotify_event_info (event );
320
+ unsigned int fid_mode = FAN_GROUP_FLAG (group , FANOTIFY_FID_BITS );
307
321
struct file * f = NULL ;
308
322
int ret , fd = FAN_NOFD ;
323
+ int info_type = 0 ;
309
324
310
325
pr_debug ("%s: group=%p event=%p\n" , __func__ , group , event );
311
326
@@ -346,9 +361,10 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
346
361
347
362
/* Event info records order is: dir fid + name, child fid */
348
363
if (fanotify_event_dir_fh_len (event )) {
364
+ info_type = FAN_EVENT_INFO_TYPE_DFID_NAME ;
349
365
ret = copy_info_to_user (fanotify_event_fsid (event ),
350
366
fanotify_info_dir_fh (info ),
351
- fanotify_info_name (info ),
367
+ info_type , fanotify_info_name (info ),
352
368
info -> name_len , buf , count );
353
369
if (ret < 0 )
354
370
return ret ;
@@ -358,9 +374,33 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
358
374
}
359
375
360
376
if (fanotify_event_object_fh_len (event )) {
377
+ if (fid_mode == FAN_REPORT_FID || info_type ) {
378
+ /*
379
+ * With only group flag FAN_REPORT_FID only type FID is
380
+ * reported. Second info record type is always FID.
381
+ */
382
+ info_type = FAN_EVENT_INFO_TYPE_FID ;
383
+ } else if ((event -> mask & ALL_FSNOTIFY_DIRENT_EVENTS ) ||
384
+ (event -> mask & FAN_ONDIR )) {
385
+ /*
386
+ * With group flag FAN_REPORT_DIR_FID, a single info
387
+ * record has type DFID for directory entry modification
388
+ * event and for event on a directory.
389
+ */
390
+ info_type = FAN_EVENT_INFO_TYPE_DFID ;
391
+ } else {
392
+ /*
393
+ * With group flags FAN_REPORT_DIR_FID|FAN_REPORT_FID,
394
+ * a single info record has type FID for event on a
395
+ * non-directory, when there is no directory to report.
396
+ * For example, on FAN_DELETE_SELF event.
397
+ */
398
+ info_type = FAN_EVENT_INFO_TYPE_FID ;
399
+ }
400
+
361
401
ret = copy_info_to_user (fanotify_event_fsid (event ),
362
402
fanotify_event_object_fh (event ),
363
- NULL , 0 , buf , count );
403
+ info_type , NULL , 0 , buf , count );
364
404
if (ret < 0 )
365
405
return ret ;
366
406
@@ -861,6 +901,8 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
861
901
struct fsnotify_group * group ;
862
902
int f_flags , fd ;
863
903
struct user_struct * user ;
904
+ unsigned int fid_mode = flags & FANOTIFY_FID_BITS ;
905
+ unsigned int class = flags & FANOTIFY_CLASS_BITS ;
864
906
865
907
pr_debug ("%s: flags=%x event_f_flags=%x\n" ,
866
908
__func__ , flags , event_f_flags );
@@ -887,10 +929,19 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
887
929
return - EINVAL ;
888
930
}
889
931
890
- if ((flags & FANOTIFY_FID_BITS ) &&
891
- (flags & FANOTIFY_CLASS_BITS ) != FAN_CLASS_NOTIF )
932
+ if (fid_mode && class != FAN_CLASS_NOTIF )
892
933
return - EINVAL ;
893
934
935
+ /* Reporting either object fid or dir fid */
936
+ switch (fid_mode ) {
937
+ case 0 :
938
+ case FAN_REPORT_FID :
939
+ case FAN_REPORT_DIR_FID :
940
+ break ;
941
+ default :
942
+ return - EINVAL ;
943
+ }
944
+
894
945
user = get_current_user ();
895
946
if (atomic_read (& user -> fanotify_listeners ) > FANOTIFY_DEFAULT_MAX_LISTENERS ) {
896
947
free_uid (user );
@@ -926,7 +977,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
926
977
group -> fanotify_data .f_flags = event_f_flags ;
927
978
init_waitqueue_head (& group -> fanotify_data .access_waitq );
928
979
INIT_LIST_HEAD (& group -> fanotify_data .access_list );
929
- switch (flags & FANOTIFY_CLASS_BITS ) {
980
+ switch (class ) {
930
981
case FAN_CLASS_NOTIF :
931
982
group -> priority = FS_PRIO_0 ;
932
983
break ;
@@ -1236,7 +1287,7 @@ COMPAT_SYSCALL_DEFINE6(fanotify_mark,
1236
1287
*/
1237
1288
static int __init fanotify_user_setup (void )
1238
1289
{
1239
- BUILD_BUG_ON (HWEIGHT32 (FANOTIFY_INIT_FLAGS ) != 8 );
1290
+ BUILD_BUG_ON (HWEIGHT32 (FANOTIFY_INIT_FLAGS ) != 9 );
1240
1291
BUILD_BUG_ON (HWEIGHT32 (FANOTIFY_MARK_FLAGS ) != 9 );
1241
1292
1242
1293
fanotify_mark_cache = KMEM_CACHE (fsnotify_mark ,
0 commit comments