forked from mirrors/linux
		
	fanotify: introduce group flag FAN_REPORT_TARGET_FID
FAN_REPORT_FID is ambiguous in that it reports the fid of the child for some events and the fid of the parent for create/delete/move events. The new FAN_REPORT_TARGET_FID flag is an implicit request to report the fid of the target object of the operation (a.k.a the child inode) also in create/delete/move events in addition to the fid of the parent and the name of the child. To reduce the test matrix for uninteresting use cases, the new FAN_REPORT_TARGET_FID flag requires both FAN_REPORT_NAME and FAN_REPORT_FID. The convenience macro FAN_REPORT_DFID_NAME_TARGET combines FAN_REPORT_TARGET_FID with all the required flags. Link: https://lore.kernel.org/r/20211129201537.1932819-4-amir73il@gmail.com Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Jan Kara <jack@suse.cz>
This commit is contained in:
		
							parent
							
								
									1c9007d62b
								
							
						
					
					
						commit
						d61fd650e9
					
				
					 4 changed files with 51 additions and 14 deletions
				
			
		|  | @ -458,17 +458,41 @@ static int fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode, | |||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * The inode to use as identifier when reporting fid depends on the event. | ||||
|  * Report the modified directory inode on dirent modification events. | ||||
|  * Report the "victim" inode otherwise. | ||||
|  * FAN_REPORT_FID is ambiguous in that it reports the fid of the child for | ||||
|  * some events and the fid of the parent for create/delete/move events. | ||||
|  * | ||||
|  * With the FAN_REPORT_TARGET_FID flag, the fid of the child is reported | ||||
|  * also in create/delete/move events in addition to the fid of the parent | ||||
|  * and the name of the child. | ||||
|  */ | ||||
| static inline bool fanotify_report_child_fid(unsigned int fid_mode, u32 mask) | ||||
| { | ||||
| 	if (mask & ALL_FSNOTIFY_DIRENT_EVENTS) | ||||
| 		return (fid_mode & FAN_REPORT_TARGET_FID); | ||||
| 
 | ||||
| 	return (fid_mode & FAN_REPORT_FID) && !(mask & FAN_ONDIR); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * The inode to use as identifier when reporting fid depends on the event | ||||
|  * and the group flags. | ||||
|  * | ||||
|  * With the group flag FAN_REPORT_TARGET_FID, always report the child fid. | ||||
|  * | ||||
|  * Without the group flag FAN_REPORT_TARGET_FID, report the modified directory | ||||
|  * fid on dirent events and the child fid otherwise. | ||||
|  * | ||||
|  * For example: | ||||
|  * FS_ATTRIB reports the child inode even if reported on a watched parent. | ||||
|  * FS_CREATE reports the modified dir inode and not the created inode. | ||||
|  * FS_ATTRIB reports the child fid even if reported on a watched parent. | ||||
|  * FS_CREATE reports the modified dir fid without FAN_REPORT_TARGET_FID. | ||||
|  *       and reports the created child fid with FAN_REPORT_TARGET_FID. | ||||
|  */ | ||||
| static struct inode *fanotify_fid_inode(u32 event_mask, const void *data, | ||||
| 					int data_type, struct inode *dir) | ||||
| 					int data_type, struct inode *dir, | ||||
| 					unsigned int fid_mode) | ||||
| { | ||||
| 	if (event_mask & ALL_FSNOTIFY_DIRENT_EVENTS) | ||||
| 	if ((event_mask & ALL_FSNOTIFY_DIRENT_EVENTS) && | ||||
| 	    !(fid_mode & FAN_REPORT_TARGET_FID)) | ||||
| 		return dir; | ||||
| 
 | ||||
| 	return fsnotify_data_inode(data, data_type); | ||||
|  | @ -647,10 +671,11 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, | |||
| { | ||||
| 	struct fanotify_event *event = NULL; | ||||
| 	gfp_t gfp = GFP_KERNEL_ACCOUNT; | ||||
| 	struct inode *id = fanotify_fid_inode(mask, data, data_type, dir); | ||||
| 	unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS); | ||||
| 	struct inode *id = fanotify_fid_inode(mask, data, data_type, dir, | ||||
| 					      fid_mode); | ||||
| 	struct inode *dirid = fanotify_dfid_inode(mask, data, data_type, dir); | ||||
| 	const struct path *path = fsnotify_data_path(data, data_type); | ||||
| 	unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS); | ||||
| 	struct mem_cgroup *old_memcg; | ||||
| 	struct inode *child = NULL; | ||||
| 	bool name_event = false; | ||||
|  | @ -660,11 +685,10 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, | |||
| 
 | ||||
| 	if ((fid_mode & FAN_REPORT_DIR_FID) && dirid) { | ||||
| 		/*
 | ||||
| 		 * With both flags FAN_REPORT_DIR_FID and FAN_REPORT_FID, we | ||||
| 		 * report the child fid for events reported on a non-dir child | ||||
| 		 * For certain events and group flags, report the child fid | ||||
| 		 * in addition to reporting the parent fid and maybe child name. | ||||
| 		 */ | ||||
| 		if ((fid_mode & FAN_REPORT_FID) && id != dirid && !ondir) | ||||
| 		if (fanotify_report_child_fid(fid_mode, mask) && id != dirid) | ||||
| 			child = id; | ||||
| 
 | ||||
| 		id = dirid; | ||||
|  |  | |||
|  | @ -1275,6 +1275,15 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) | |||
| 	if ((fid_mode & FAN_REPORT_NAME) && !(fid_mode & FAN_REPORT_DIR_FID)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * FAN_REPORT_TARGET_FID requires FAN_REPORT_NAME and FAN_REPORT_FID | ||||
| 	 * and is used as an indication to report both dir and child fid on all | ||||
| 	 * dirent events. | ||||
| 	 */ | ||||
| 	if ((fid_mode & FAN_REPORT_TARGET_FID) && | ||||
| 	    (!(fid_mode & FAN_REPORT_NAME) || !(fid_mode & FAN_REPORT_FID))) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	f_flags = O_RDWR | FMODE_NONOTIFY; | ||||
| 	if (flags & FAN_CLOEXEC) | ||||
| 		f_flags |= O_CLOEXEC; | ||||
|  | @ -1667,7 +1676,7 @@ static int __init fanotify_user_setup(void) | |||
| 				     FANOTIFY_DEFAULT_MAX_USER_MARKS); | ||||
| 
 | ||||
| 	BUILD_BUG_ON(FANOTIFY_INIT_FLAGS & FANOTIFY_INTERNAL_GROUP_FLAGS); | ||||
| 	BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 11); | ||||
| 	BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 12); | ||||
| 	BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 9); | ||||
| 
 | ||||
| 	fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, | ||||
|  |  | |||
|  | @ -25,7 +25,7 @@ extern struct ctl_table fanotify_table[]; /* for sysctl */ | |||
| 
 | ||||
| #define FANOTIFY_CLASS_BITS	(FAN_CLASS_NOTIF | FANOTIFY_PERM_CLASSES) | ||||
| 
 | ||||
| #define FANOTIFY_FID_BITS	(FAN_REPORT_FID | FAN_REPORT_DFID_NAME) | ||||
| #define FANOTIFY_FID_BITS	(FAN_REPORT_DFID_NAME_TARGET) | ||||
| 
 | ||||
| #define FANOTIFY_INFO_MODES	(FANOTIFY_FID_BITS | FAN_REPORT_PIDFD) | ||||
| 
 | ||||
|  |  | |||
|  | @ -57,9 +57,13 @@ | |||
| #define FAN_REPORT_FID		0x00000200	/* Report unique file id */ | ||||
| #define FAN_REPORT_DIR_FID	0x00000400	/* Report unique directory id */ | ||||
| #define FAN_REPORT_NAME		0x00000800	/* Report events with name */ | ||||
| #define FAN_REPORT_TARGET_FID	0x00001000	/* Report dirent target id  */ | ||||
| 
 | ||||
| /* Convenience macro - FAN_REPORT_NAME requires FAN_REPORT_DIR_FID */ | ||||
| #define FAN_REPORT_DFID_NAME	(FAN_REPORT_DIR_FID | FAN_REPORT_NAME) | ||||
| /* Convenience macro - FAN_REPORT_TARGET_FID requires all other FID flags */ | ||||
| #define FAN_REPORT_DFID_NAME_TARGET (FAN_REPORT_DFID_NAME | \ | ||||
| 				     FAN_REPORT_FID | FAN_REPORT_TARGET_FID) | ||||
| 
 | ||||
| /* Deprecated - do not use this in programs and do not add new flags here! */ | ||||
| #define FAN_ALL_INIT_FLAGS	(FAN_CLOEXEC | FAN_NONBLOCK | \ | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Amir Goldstein
						Amir Goldstein