@@ -76,23 +76,35 @@ static bool fanotify_info_equal(struct fanotify_info *info1,
7676 struct fanotify_info * info2 )
7777{
7878 if (info1 -> dir_fh_totlen != info2 -> dir_fh_totlen ||
79+ info1 -> dir2_fh_totlen != info2 -> dir2_fh_totlen ||
7980 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 )
8183 return false;
8284
8385 if (info1 -> dir_fh_totlen &&
8486 !fanotify_fh_equal (fanotify_info_dir_fh (info1 ),
8587 fanotify_info_dir_fh (info2 )))
8688 return false;
8789
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+
8895 if (info1 -> file_fh_totlen &&
8996 !fanotify_fh_equal (fanotify_info_file_fh (info1 ),
9097 fanotify_info_file_fh (info2 )))
9198 return false;
9299
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 );
96108}
97109
98110static bool fanotify_name_event_equal (struct fanotify_name_event * fne1 ,
@@ -141,6 +153,13 @@ static bool fanotify_should_merge(struct fanotify_event *old,
141153 if ((old -> mask & FS_ISDIR ) != (new -> mask & FS_ISDIR ))
142154 return false;
143155
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+
144163 switch (old -> type ) {
145164 case FANOTIFY_EVENT_TYPE_PATH :
146165 return fanotify_path_equal (fanotify_event_path (old ),
@@ -272,8 +291,9 @@ static int fanotify_get_response(struct fsnotify_group *group,
272291 */
273292static u32 fanotify_group_event_mask (struct fsnotify_group * group ,
274293 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 )
277297{
278298 __u32 marks_mask = 0 , marks_ignored_mask = 0 ;
279299 __u32 test_mask , user_mask = FANOTIFY_OUTGOING_EVENTS |
@@ -299,7 +319,7 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group,
299319 return 0 ;
300320 }
301321
302- fsnotify_foreach_obj_type (type ) {
322+ fsnotify_foreach_iter_type (type ) {
303323 if (!fsnotify_iter_should_report_type (iter_info , type ))
304324 continue ;
305325 mark = iter_info -> marks [type ];
@@ -318,11 +338,14 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group,
318338 * If the event is on a child and this mark is on a parent not
319339 * watching children, don't send it!
320340 */
321- if (type == FSNOTIFY_OBJ_TYPE_PARENT &&
341+ if (type == FSNOTIFY_ITER_TYPE_PARENT &&
322342 !(mark -> mask & FS_EVENT_ON_CHILD ))
323343 continue ;
324344
325345 marks_mask |= mark -> mask ;
346+
347+ /* Record the mark types of this group that matched the event */
348+ * match_mask |= 1U << type ;
326349 }
327350
328351 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,
411434 * be zero in that case if encoding fh len failed.
412435 */
413436 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 )
415438 goto out_err ;
416439
417440 /* 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,
458481}
459482
460483/*
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+ *
464508 * 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.
467512 */
468513static 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 )
470516{
471- if (event_mask & ALL_FSNOTIFY_DIRENT_EVENTS )
517+ if ((event_mask & ALL_FSNOTIFY_DIRENT_EVENTS ) &&
518+ !(fid_mode & FAN_REPORT_TARGET_FID ))
472519 return dir ;
473520
474521 return fsnotify_data_inode (data , data_type );
@@ -552,25 +599,34 @@ static struct fanotify_event *fanotify_alloc_fid_event(struct inode *id,
552599 return & ffe -> fae ;
553600}
554601
555- static struct fanotify_event * fanotify_alloc_name_event (struct inode * id ,
602+ static struct fanotify_event * fanotify_alloc_name_event (struct inode * dir ,
556603 __kernel_fsid_t * fsid ,
557604 const struct qstr * name ,
558605 struct inode * child ,
606+ struct dentry * moved ,
559607 unsigned int * hash ,
560608 gfp_t gfp )
561609{
562610 struct fanotify_name_event * fne ;
563611 struct fanotify_info * info ;
564612 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 );
566617 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 ;
570628 if (child_fh_len )
571629 size += FANOTIFY_FH_HDR_LEN + child_fh_len ;
572- if (name )
573- size += name -> len + 1 ;
574630 fne = kmalloc (size , gfp );
575631 if (!fne )
576632 return NULL ;
@@ -580,24 +636,41 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *id,
580636 * hash ^= fanotify_hash_fsid (fsid );
581637 info = & fne -> info ;
582638 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+ }
585649 if (child_fh_len ) {
586650 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 );
589653 }
590- if (name ) {
591- long salt = name -> len ;
592-
654+ if (name_len ) {
593655 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 );
595662 }
596663
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 ,
599666 info -> name_len , info -> name_len , fanotify_info_name (info ));
600667
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+
601674 return & fne -> fae ;
602675}
603676
@@ -639,19 +712,21 @@ static struct fanotify_event *fanotify_alloc_error_event(
639712 return & fee -> fae ;
640713}
641714
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 )
647720{
648721 struct fanotify_event * event = NULL ;
649722 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 );
651726 struct inode * dirid = fanotify_dfid_inode (mask , data , data_type , dir );
652727 const struct path * path = fsnotify_data_path (data , data_type );
653- unsigned int fid_mode = FAN_GROUP_FLAG (group , FANOTIFY_FID_BITS );
654728 struct mem_cgroup * old_memcg ;
729+ struct dentry * moved = NULL ;
655730 struct inode * child = NULL ;
656731 bool name_event = false;
657732 unsigned int hash = 0 ;
@@ -660,11 +735,10 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
660735
661736 if ((fid_mode & FAN_REPORT_DIR_FID ) && dirid ) {
662737 /*
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
665739 * in addition to reporting the parent fid and maybe child name.
666740 */
667- if ((fid_mode & FAN_REPORT_FID ) && id != dirid && ! ondir )
741+ if (fanotify_report_child_fid (fid_mode , mask ) && id != dirid )
668742 child = id ;
669743
670744 id = dirid ;
@@ -688,6 +762,38 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
688762 } else if ((mask & ALL_FSNOTIFY_DIRENT_EVENTS ) || !ondir ) {
689763 name_event = true;
690764 }
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+ }
691797 }
692798
693799 /*
@@ -709,9 +815,9 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
709815 } else if (fanotify_is_error_event (mask )) {
710816 event = fanotify_alloc_error_event (group , fsid , data ,
711817 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 );
715821 } else if (fid_mode ) {
716822 event = fanotify_alloc_fid_event (id , fsid , & hash , gfp );
717823 } else {
@@ -746,7 +852,7 @@ static __kernel_fsid_t fanotify_get_fsid(struct fsnotify_iter_info *iter_info)
746852 int type ;
747853 __kernel_fsid_t fsid = {};
748854
749- fsnotify_foreach_obj_type (type ) {
855+ fsnotify_foreach_iter_type (type ) {
750856 struct fsnotify_mark_connector * conn ;
751857
752858 if (!fsnotify_iter_should_report_type (iter_info , type ))
@@ -800,6 +906,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask,
800906 struct fanotify_event * event ;
801907 struct fsnotify_event * fsn_event ;
802908 __kernel_fsid_t fsid = {};
909+ u32 match_mask = 0 ;
803910
804911 BUILD_BUG_ON (FAN_ACCESS != FS_ACCESS );
805912 BUILD_BUG_ON (FAN_MODIFY != FS_MODIFY );
@@ -821,15 +928,17 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask,
821928 BUILD_BUG_ON (FAN_OPEN_EXEC != FS_OPEN_EXEC );
822929 BUILD_BUG_ON (FAN_OPEN_EXEC_PERM != FS_OPEN_EXEC_PERM );
823930 BUILD_BUG_ON (FAN_FS_ERROR != FS_ERROR );
931+ BUILD_BUG_ON (FAN_RENAME != FS_RENAME );
824932
825- BUILD_BUG_ON (HWEIGHT32 (ALL_FANOTIFY_EVENT_BITS ) != 20 );
933+ BUILD_BUG_ON (HWEIGHT32 (ALL_FANOTIFY_EVENT_BITS ) != 21 );
826934
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 );
829937 if (!mask )
830938 return 0 ;
831939
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 );
833942
834943 if (fanotify_is_perm_event (mask )) {
835944 /*
@@ -848,7 +957,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask,
848957 }
849958
850959 event = fanotify_alloc_event (group , mask , data , data_type , dir ,
851- file_name , & fsid );
960+ file_name , & fsid , match_mask );
852961 ret = - ENOMEM ;
853962 if (unlikely (!event )) {
854963 /*
0 commit comments