@@ -76,23 +76,35 @@ static bool fanotify_info_equal(struct fanotify_info *info1,
76
76
struct fanotify_info * info2 )
77
77
{
78
78
if (info1 -> dir_fh_totlen != info2 -> dir_fh_totlen ||
79
+ info1 -> dir2_fh_totlen != info2 -> dir2_fh_totlen ||
79
80
info1 -> file_fh_totlen != info2 -> file_fh_totlen ||
80
- info1 -> name_len != info2 -> name_len )
81
+ info1 -> name_len != info2 -> name_len ||
82
+ info1 -> name2_len != info2 -> name2_len )
81
83
return false;
82
84
83
85
if (info1 -> dir_fh_totlen &&
84
86
!fanotify_fh_equal (fanotify_info_dir_fh (info1 ),
85
87
fanotify_info_dir_fh (info2 )))
86
88
return false;
87
89
90
+ if (info1 -> dir2_fh_totlen &&
91
+ !fanotify_fh_equal (fanotify_info_dir2_fh (info1 ),
92
+ fanotify_info_dir2_fh (info2 )))
93
+ return false;
94
+
88
95
if (info1 -> file_fh_totlen &&
89
96
!fanotify_fh_equal (fanotify_info_file_fh (info1 ),
90
97
fanotify_info_file_fh (info2 )))
91
98
return false;
92
99
93
- return !info1 -> name_len ||
94
- !memcmp (fanotify_info_name (info1 ), fanotify_info_name (info2 ),
95
- info1 -> name_len );
100
+ if (info1 -> name_len &&
101
+ memcmp (fanotify_info_name (info1 ), fanotify_info_name (info2 ),
102
+ info1 -> name_len ))
103
+ return false;
104
+
105
+ return !info1 -> name2_len ||
106
+ !memcmp (fanotify_info_name2 (info1 ), fanotify_info_name2 (info2 ),
107
+ info1 -> name2_len );
96
108
}
97
109
98
110
static bool fanotify_name_event_equal (struct fanotify_name_event * fne1 ,
@@ -141,6 +153,13 @@ static bool fanotify_should_merge(struct fanotify_event *old,
141
153
if ((old -> mask & FS_ISDIR ) != (new -> mask & FS_ISDIR ))
142
154
return false;
143
155
156
+ /*
157
+ * FAN_RENAME event is reported with special info record types,
158
+ * so we cannot merge it with other events.
159
+ */
160
+ if ((old -> mask & FAN_RENAME ) != (new -> mask & FAN_RENAME ))
161
+ return false;
162
+
144
163
switch (old -> type ) {
145
164
case FANOTIFY_EVENT_TYPE_PATH :
146
165
return fanotify_path_equal (fanotify_event_path (old ),
@@ -272,8 +291,9 @@ static int fanotify_get_response(struct fsnotify_group *group,
272
291
*/
273
292
static u32 fanotify_group_event_mask (struct fsnotify_group * group ,
274
293
struct fsnotify_iter_info * iter_info ,
275
- u32 event_mask , const void * data ,
276
- int data_type , struct inode * dir )
294
+ u32 * match_mask , u32 event_mask ,
295
+ const void * data , int data_type ,
296
+ struct inode * dir )
277
297
{
278
298
__u32 marks_mask = 0 , marks_ignored_mask = 0 ;
279
299
__u32 test_mask , user_mask = FANOTIFY_OUTGOING_EVENTS |
@@ -299,7 +319,7 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group,
299
319
return 0 ;
300
320
}
301
321
302
- fsnotify_foreach_obj_type (type ) {
322
+ fsnotify_foreach_iter_type (type ) {
303
323
if (!fsnotify_iter_should_report_type (iter_info , type ))
304
324
continue ;
305
325
mark = iter_info -> marks [type ];
@@ -318,11 +338,14 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group,
318
338
* If the event is on a child and this mark is on a parent not
319
339
* watching children, don't send it!
320
340
*/
321
- if (type == FSNOTIFY_OBJ_TYPE_PARENT &&
341
+ if (type == FSNOTIFY_ITER_TYPE_PARENT &&
322
342
!(mark -> mask & FS_EVENT_ON_CHILD ))
323
343
continue ;
324
344
325
345
marks_mask |= mark -> mask ;
346
+
347
+ /* Record the mark types of this group that matched the event */
348
+ * match_mask |= 1U << type ;
326
349
}
327
350
328
351
test_mask = event_mask & marks_mask & ~marks_ignored_mask ;
@@ -411,7 +434,7 @@ static int fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode,
411
434
* be zero in that case if encoding fh len failed.
412
435
*/
413
436
err = - ENOENT ;
414
- if (fh_len < 4 || WARN_ON_ONCE (fh_len % 4 ))
437
+ if (fh_len < 4 || WARN_ON_ONCE (fh_len % 4 ) || fh_len > MAX_HANDLE_SZ )
415
438
goto out_err ;
416
439
417
440
/* No external buffer in a variable size allocated fh */
@@ -458,17 +481,41 @@ static int fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode,
458
481
}
459
482
460
483
/*
461
- * The inode to use as identifier when reporting fid depends on the event.
462
- * Report the modified directory inode on dirent modification events.
463
- * Report the "victim" inode otherwise.
484
+ * FAN_REPORT_FID is ambiguous in that it reports the fid of the child for
485
+ * some events and the fid of the parent for create/delete/move events.
486
+ *
487
+ * With the FAN_REPORT_TARGET_FID flag, the fid of the child is reported
488
+ * also in create/delete/move events in addition to the fid of the parent
489
+ * and the name of the child.
490
+ */
491
+ static inline bool fanotify_report_child_fid (unsigned int fid_mode , u32 mask )
492
+ {
493
+ if (mask & ALL_FSNOTIFY_DIRENT_EVENTS )
494
+ return (fid_mode & FAN_REPORT_TARGET_FID );
495
+
496
+ return (fid_mode & FAN_REPORT_FID ) && !(mask & FAN_ONDIR );
497
+ }
498
+
499
+ /*
500
+ * The inode to use as identifier when reporting fid depends on the event
501
+ * and the group flags.
502
+ *
503
+ * With the group flag FAN_REPORT_TARGET_FID, always report the child fid.
504
+ *
505
+ * Without the group flag FAN_REPORT_TARGET_FID, report the modified directory
506
+ * fid on dirent events and the child fid otherwise.
507
+ *
464
508
* For example:
465
- * FS_ATTRIB reports the child inode even if reported on a watched parent.
466
- * FS_CREATE reports the modified dir inode and not the created inode.
509
+ * FS_ATTRIB reports the child fid even if reported on a watched parent.
510
+ * FS_CREATE reports the modified dir fid without FAN_REPORT_TARGET_FID.
511
+ * and reports the created child fid with FAN_REPORT_TARGET_FID.
467
512
*/
468
513
static struct inode * fanotify_fid_inode (u32 event_mask , const void * data ,
469
- int data_type , struct inode * dir )
514
+ int data_type , struct inode * dir ,
515
+ unsigned int fid_mode )
470
516
{
471
- if (event_mask & ALL_FSNOTIFY_DIRENT_EVENTS )
517
+ if ((event_mask & ALL_FSNOTIFY_DIRENT_EVENTS ) &&
518
+ !(fid_mode & FAN_REPORT_TARGET_FID ))
472
519
return dir ;
473
520
474
521
return fsnotify_data_inode (data , data_type );
@@ -552,25 +599,34 @@ static struct fanotify_event *fanotify_alloc_fid_event(struct inode *id,
552
599
return & ffe -> fae ;
553
600
}
554
601
555
- static struct fanotify_event * fanotify_alloc_name_event (struct inode * id ,
602
+ static struct fanotify_event * fanotify_alloc_name_event (struct inode * dir ,
556
603
__kernel_fsid_t * fsid ,
557
604
const struct qstr * name ,
558
605
struct inode * child ,
606
+ struct dentry * moved ,
559
607
unsigned int * hash ,
560
608
gfp_t gfp )
561
609
{
562
610
struct fanotify_name_event * fne ;
563
611
struct fanotify_info * info ;
564
612
struct fanotify_fh * dfh , * ffh ;
565
- unsigned int dir_fh_len = fanotify_encode_fh_len (id );
613
+ struct inode * dir2 = moved ? d_inode (moved -> d_parent ) : NULL ;
614
+ const struct qstr * name2 = moved ? & moved -> d_name : NULL ;
615
+ unsigned int dir_fh_len = fanotify_encode_fh_len (dir );
616
+ unsigned int dir2_fh_len = fanotify_encode_fh_len (dir2 );
566
617
unsigned int child_fh_len = fanotify_encode_fh_len (child );
567
- unsigned int size ;
568
-
569
- size = sizeof (* fne ) + FANOTIFY_FH_HDR_LEN + dir_fh_len ;
618
+ unsigned long name_len = name ? name -> len : 0 ;
619
+ unsigned long name2_len = name2 ? name2 -> len : 0 ;
620
+ unsigned int len , size ;
621
+
622
+ /* Reserve terminating null byte even for empty name */
623
+ size = sizeof (* fne ) + name_len + name2_len + 2 ;
624
+ if (dir_fh_len )
625
+ size += FANOTIFY_FH_HDR_LEN + dir_fh_len ;
626
+ if (dir2_fh_len )
627
+ size += FANOTIFY_FH_HDR_LEN + dir2_fh_len ;
570
628
if (child_fh_len )
571
629
size += FANOTIFY_FH_HDR_LEN + child_fh_len ;
572
- if (name )
573
- size += name -> len + 1 ;
574
630
fne = kmalloc (size , gfp );
575
631
if (!fne )
576
632
return NULL ;
@@ -580,24 +636,41 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *id,
580
636
* hash ^= fanotify_hash_fsid (fsid );
581
637
info = & fne -> info ;
582
638
fanotify_info_init (info );
583
- dfh = fanotify_info_dir_fh (info );
584
- info -> dir_fh_totlen = fanotify_encode_fh (dfh , id , dir_fh_len , hash , 0 );
639
+ if (dir_fh_len ) {
640
+ dfh = fanotify_info_dir_fh (info );
641
+ len = fanotify_encode_fh (dfh , dir , dir_fh_len , hash , 0 );
642
+ fanotify_info_set_dir_fh (info , len );
643
+ }
644
+ if (dir2_fh_len ) {
645
+ dfh = fanotify_info_dir2_fh (info );
646
+ len = fanotify_encode_fh (dfh , dir2 , dir2_fh_len , hash , 0 );
647
+ fanotify_info_set_dir2_fh (info , len );
648
+ }
585
649
if (child_fh_len ) {
586
650
ffh = fanotify_info_file_fh (info );
587
- info -> file_fh_totlen = fanotify_encode_fh (ffh , child ,
588
- child_fh_len , hash , 0 );
651
+ len = fanotify_encode_fh (ffh , child , child_fh_len , hash , 0 );
652
+ fanotify_info_set_file_fh ( info , len );
589
653
}
590
- if (name ) {
591
- long salt = name -> len ;
592
-
654
+ if (name_len ) {
593
655
fanotify_info_copy_name (info , name );
594
- * hash ^= full_name_hash ((void * )salt , name -> name , name -> len );
656
+ * hash ^= full_name_hash ((void * )name_len , name -> name , name_len );
657
+ }
658
+ if (name2_len ) {
659
+ fanotify_info_copy_name2 (info , name2 );
660
+ * hash ^= full_name_hash ((void * )name2_len , name2 -> name ,
661
+ name2_len );
595
662
}
596
663
597
- pr_debug ("%s: ino=%lu size=%u dir_fh_len=%u child_fh_len=%u name_len=%u name='%.*s'\n" ,
598
- __func__ , id -> i_ino , size , dir_fh_len , child_fh_len ,
664
+ pr_debug ("%s: size=%u dir_fh_len=%u child_fh_len=%u name_len=%u name='%.*s'\n" ,
665
+ __func__ , size , dir_fh_len , child_fh_len ,
599
666
info -> name_len , info -> name_len , fanotify_info_name (info ));
600
667
668
+ if (dir2_fh_len ) {
669
+ pr_debug ("%s: dir2_fh_len=%u name2_len=%u name2='%.*s'\n" ,
670
+ __func__ , dir2_fh_len , info -> name2_len ,
671
+ info -> name2_len , fanotify_info_name2 (info ));
672
+ }
673
+
601
674
return & fne -> fae ;
602
675
}
603
676
@@ -639,19 +712,21 @@ static struct fanotify_event *fanotify_alloc_error_event(
639
712
return & fee -> fae ;
640
713
}
641
714
642
- static struct fanotify_event * fanotify_alloc_event (struct fsnotify_group * group ,
643
- u32 mask , const void * data ,
644
- int data_type , struct inode * dir ,
645
- const struct qstr * file_name ,
646
- __kernel_fsid_t * fsid )
715
+ static struct fanotify_event * fanotify_alloc_event (
716
+ struct fsnotify_group * group ,
717
+ u32 mask , const void * data , int data_type ,
718
+ struct inode * dir , const struct qstr * file_name ,
719
+ __kernel_fsid_t * fsid , u32 match_mask )
647
720
{
648
721
struct fanotify_event * event = NULL ;
649
722
gfp_t gfp = GFP_KERNEL_ACCOUNT ;
650
- struct inode * id = fanotify_fid_inode (mask , data , data_type , dir );
723
+ unsigned int fid_mode = FAN_GROUP_FLAG (group , FANOTIFY_FID_BITS );
724
+ struct inode * id = fanotify_fid_inode (mask , data , data_type , dir ,
725
+ fid_mode );
651
726
struct inode * dirid = fanotify_dfid_inode (mask , data , data_type , dir );
652
727
const struct path * path = fsnotify_data_path (data , data_type );
653
- unsigned int fid_mode = FAN_GROUP_FLAG (group , FANOTIFY_FID_BITS );
654
728
struct mem_cgroup * old_memcg ;
729
+ struct dentry * moved = NULL ;
655
730
struct inode * child = NULL ;
656
731
bool name_event = false;
657
732
unsigned int hash = 0 ;
@@ -660,11 +735,10 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
660
735
661
736
if ((fid_mode & FAN_REPORT_DIR_FID ) && dirid ) {
662
737
/*
663
- * With both flags FAN_REPORT_DIR_FID and FAN_REPORT_FID, we
664
- * report the child fid for events reported on a non-dir child
738
+ * For certain events and group flags, report the child fid
665
739
* in addition to reporting the parent fid and maybe child name.
666
740
*/
667
- if ((fid_mode & FAN_REPORT_FID ) && id != dirid && ! ondir )
741
+ if (fanotify_report_child_fid (fid_mode , mask ) && id != dirid )
668
742
child = id ;
669
743
670
744
id = dirid ;
@@ -688,6 +762,38 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
688
762
} else if ((mask & ALL_FSNOTIFY_DIRENT_EVENTS ) || !ondir ) {
689
763
name_event = true;
690
764
}
765
+
766
+ /*
767
+ * In the special case of FAN_RENAME event, use the match_mask
768
+ * to determine if we need to report only the old parent+name,
769
+ * only the new parent+name or both.
770
+ * 'dirid' and 'file_name' are the old parent+name and
771
+ * 'moved' has the new parent+name.
772
+ */
773
+ if (mask & FAN_RENAME ) {
774
+ bool report_old , report_new ;
775
+
776
+ if (WARN_ON_ONCE (!match_mask ))
777
+ return NULL ;
778
+
779
+ /* Report both old and new parent+name if sb watching */
780
+ report_old = report_new =
781
+ match_mask & (1U << FSNOTIFY_ITER_TYPE_SB );
782
+ report_old |=
783
+ match_mask & (1U << FSNOTIFY_ITER_TYPE_INODE );
784
+ report_new |=
785
+ match_mask & (1U << FSNOTIFY_ITER_TYPE_INODE2 );
786
+
787
+ if (!report_old ) {
788
+ /* Do not report old parent+name */
789
+ dirid = NULL ;
790
+ file_name = NULL ;
791
+ }
792
+ if (report_new ) {
793
+ /* Report new parent+name */
794
+ moved = fsnotify_data_dentry (data , data_type );
795
+ }
796
+ }
691
797
}
692
798
693
799
/*
@@ -709,9 +815,9 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
709
815
} else if (fanotify_is_error_event (mask )) {
710
816
event = fanotify_alloc_error_event (group , fsid , data ,
711
817
data_type , & hash );
712
- } else if (name_event && (file_name || child )) {
713
- event = fanotify_alloc_name_event (id , fsid , file_name , child ,
714
- & hash , gfp );
818
+ } else if (name_event && (file_name || moved || child )) {
819
+ event = fanotify_alloc_name_event (dirid , fsid , file_name , child ,
820
+ moved , & hash , gfp );
715
821
} else if (fid_mode ) {
716
822
event = fanotify_alloc_fid_event (id , fsid , & hash , gfp );
717
823
} else {
@@ -746,7 +852,7 @@ static __kernel_fsid_t fanotify_get_fsid(struct fsnotify_iter_info *iter_info)
746
852
int type ;
747
853
__kernel_fsid_t fsid = {};
748
854
749
- fsnotify_foreach_obj_type (type ) {
855
+ fsnotify_foreach_iter_type (type ) {
750
856
struct fsnotify_mark_connector * conn ;
751
857
752
858
if (!fsnotify_iter_should_report_type (iter_info , type ))
@@ -800,6 +906,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask,
800
906
struct fanotify_event * event ;
801
907
struct fsnotify_event * fsn_event ;
802
908
__kernel_fsid_t fsid = {};
909
+ u32 match_mask = 0 ;
803
910
804
911
BUILD_BUG_ON (FAN_ACCESS != FS_ACCESS );
805
912
BUILD_BUG_ON (FAN_MODIFY != FS_MODIFY );
@@ -821,15 +928,17 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask,
821
928
BUILD_BUG_ON (FAN_OPEN_EXEC != FS_OPEN_EXEC );
822
929
BUILD_BUG_ON (FAN_OPEN_EXEC_PERM != FS_OPEN_EXEC_PERM );
823
930
BUILD_BUG_ON (FAN_FS_ERROR != FS_ERROR );
931
+ BUILD_BUG_ON (FAN_RENAME != FS_RENAME );
824
932
825
- BUILD_BUG_ON (HWEIGHT32 (ALL_FANOTIFY_EVENT_BITS ) != 20 );
933
+ BUILD_BUG_ON (HWEIGHT32 (ALL_FANOTIFY_EVENT_BITS ) != 21 );
826
934
827
- mask = fanotify_group_event_mask (group , iter_info , mask , data ,
828
- data_type , dir );
935
+ mask = fanotify_group_event_mask (group , iter_info , & match_mask ,
936
+ mask , data , data_type , dir );
829
937
if (!mask )
830
938
return 0 ;
831
939
832
- pr_debug ("%s: group=%p mask=%x\n" , __func__ , group , mask );
940
+ pr_debug ("%s: group=%p mask=%x report_mask=%x\n" , __func__ ,
941
+ group , mask , match_mask );
833
942
834
943
if (fanotify_is_perm_event (mask )) {
835
944
/*
@@ -848,7 +957,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask,
848
957
}
849
958
850
959
event = fanotify_alloc_event (group , mask , data , data_type , dir ,
851
- file_name , & fsid );
960
+ file_name , & fsid , match_mask );
852
961
ret = - ENOMEM ;
853
962
if (unlikely (!event )) {
854
963
/*
0 commit comments