@@ -656,28 +656,35 @@ static int fanotify_find_path(int dfd, const char __user *filename,
656
656
}
657
657
658
658
static __u32 fanotify_mark_remove_from_mask (struct fsnotify_mark * fsn_mark ,
659
- __u32 mask ,
660
- unsigned int flags ,
661
- int * destroy )
659
+ __u32 mask , unsigned int flags ,
660
+ __u32 umask , int * destroy )
662
661
{
663
662
__u32 oldmask = 0 ;
664
663
664
+ /* umask bits cannot be removed by user */
665
+ mask &= ~umask ;
665
666
spin_lock (& fsn_mark -> lock );
666
667
if (!(flags & FAN_MARK_IGNORED_MASK )) {
667
668
oldmask = fsn_mark -> mask ;
668
669
fsn_mark -> mask &= ~mask ;
669
670
} else {
670
671
fsn_mark -> ignored_mask &= ~mask ;
671
672
}
672
- * destroy = !(fsn_mark -> mask | fsn_mark -> ignored_mask );
673
+ /*
674
+ * We need to keep the mark around even if remaining mask cannot
675
+ * result in any events (e.g. mask == FAN_ONDIR) to support incremenal
676
+ * changes to the mask.
677
+ * Destroy mark when only umask bits remain.
678
+ */
679
+ * destroy = !((fsn_mark -> mask | fsn_mark -> ignored_mask ) & ~umask );
673
680
spin_unlock (& fsn_mark -> lock );
674
681
675
682
return mask & oldmask ;
676
683
}
677
684
678
685
static int fanotify_remove_mark (struct fsnotify_group * group ,
679
686
fsnotify_connp_t * connp , __u32 mask ,
680
- unsigned int flags )
687
+ unsigned int flags , __u32 umask )
681
688
{
682
689
struct fsnotify_mark * fsn_mark = NULL ;
683
690
__u32 removed ;
@@ -691,7 +698,7 @@ static int fanotify_remove_mark(struct fsnotify_group *group,
691
698
}
692
699
693
700
removed = fanotify_mark_remove_from_mask (fsn_mark , mask , flags ,
694
- & destroy_mark );
701
+ umask , & destroy_mark );
695
702
if (removed & fsnotify_conn_mask (fsn_mark -> connector ))
696
703
fsnotify_recalc_mask (fsn_mark -> connector );
697
704
if (destroy_mark )
@@ -707,25 +714,26 @@ static int fanotify_remove_mark(struct fsnotify_group *group,
707
714
708
715
static int fanotify_remove_vfsmount_mark (struct fsnotify_group * group ,
709
716
struct vfsmount * mnt , __u32 mask ,
710
- unsigned int flags )
717
+ unsigned int flags , __u32 umask )
711
718
{
712
719
return fanotify_remove_mark (group , & real_mount (mnt )-> mnt_fsnotify_marks ,
713
- mask , flags );
720
+ mask , flags , umask );
714
721
}
715
722
716
723
static int fanotify_remove_sb_mark (struct fsnotify_group * group ,
717
- struct super_block * sb , __u32 mask ,
718
- unsigned int flags )
724
+ struct super_block * sb , __u32 mask ,
725
+ unsigned int flags , __u32 umask )
719
726
{
720
- return fanotify_remove_mark (group , & sb -> s_fsnotify_marks , mask , flags );
727
+ return fanotify_remove_mark (group , & sb -> s_fsnotify_marks , mask ,
728
+ flags , umask );
721
729
}
722
730
723
731
static int fanotify_remove_inode_mark (struct fsnotify_group * group ,
724
732
struct inode * inode , __u32 mask ,
725
- unsigned int flags )
733
+ unsigned int flags , __u32 umask )
726
734
{
727
735
return fanotify_remove_mark (group , & inode -> i_fsnotify_marks , mask ,
728
- flags );
736
+ flags , umask );
729
737
}
730
738
731
739
static __u32 fanotify_mark_add_to_mask (struct fsnotify_mark * fsn_mark ,
@@ -1175,13 +1183,13 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
1175
1183
case FAN_MARK_REMOVE :
1176
1184
if (mark_type == FAN_MARK_MOUNT )
1177
1185
ret = fanotify_remove_vfsmount_mark (group , mnt , mask ,
1178
- flags );
1186
+ flags , 0 );
1179
1187
else if (mark_type == FAN_MARK_FILESYSTEM )
1180
1188
ret = fanotify_remove_sb_mark (group , mnt -> mnt_sb , mask ,
1181
- flags );
1189
+ flags , 0 );
1182
1190
else
1183
1191
ret = fanotify_remove_inode_mark (group , inode , mask ,
1184
- flags );
1192
+ flags , 0 );
1185
1193
break ;
1186
1194
default :
1187
1195
ret = - EINVAL ;
0 commit comments