Skip to content

Commit d61fd65

Browse files
amir73iljankara
authored andcommitted
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/[email protected] Signed-off-by: Amir Goldstein <[email protected]> Signed-off-by: Jan Kara <[email protected]>
1 parent 1c9007d commit d61fd65

File tree

4 files changed

+51
-14
lines changed

4 files changed

+51
-14
lines changed

fs/notify/fanotify/fanotify.c

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -458,17 +458,41 @@ static int fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode,
458458
}
459459

460460
/*
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.
461+
* FAN_REPORT_FID is ambiguous in that it reports the fid of the child for
462+
* some events and the fid of the parent for create/delete/move events.
463+
*
464+
* With the FAN_REPORT_TARGET_FID flag, the fid of the child is reported
465+
* also in create/delete/move events in addition to the fid of the parent
466+
* and the name of the child.
467+
*/
468+
static inline bool fanotify_report_child_fid(unsigned int fid_mode, u32 mask)
469+
{
470+
if (mask & ALL_FSNOTIFY_DIRENT_EVENTS)
471+
return (fid_mode & FAN_REPORT_TARGET_FID);
472+
473+
return (fid_mode & FAN_REPORT_FID) && !(mask & FAN_ONDIR);
474+
}
475+
476+
/*
477+
* The inode to use as identifier when reporting fid depends on the event
478+
* and the group flags.
479+
*
480+
* With the group flag FAN_REPORT_TARGET_FID, always report the child fid.
481+
*
482+
* Without the group flag FAN_REPORT_TARGET_FID, report the modified directory
483+
* fid on dirent events and the child fid otherwise.
484+
*
464485
* 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.
486+
* FS_ATTRIB reports the child fid even if reported on a watched parent.
487+
* FS_CREATE reports the modified dir fid without FAN_REPORT_TARGET_FID.
488+
* and reports the created child fid with FAN_REPORT_TARGET_FID.
467489
*/
468490
static struct inode *fanotify_fid_inode(u32 event_mask, const void *data,
469-
int data_type, struct inode *dir)
491+
int data_type, struct inode *dir,
492+
unsigned int fid_mode)
470493
{
471-
if (event_mask & ALL_FSNOTIFY_DIRENT_EVENTS)
494+
if ((event_mask & ALL_FSNOTIFY_DIRENT_EVENTS) &&
495+
!(fid_mode & FAN_REPORT_TARGET_FID))
472496
return dir;
473497

474498
return fsnotify_data_inode(data, data_type);
@@ -647,10 +671,11 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
647671
{
648672
struct fanotify_event *event = NULL;
649673
gfp_t gfp = GFP_KERNEL_ACCOUNT;
650-
struct inode *id = fanotify_fid_inode(mask, data, data_type, dir);
674+
unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS);
675+
struct inode *id = fanotify_fid_inode(mask, data, data_type, dir,
676+
fid_mode);
651677
struct inode *dirid = fanotify_dfid_inode(mask, data, data_type, dir);
652678
const struct path *path = fsnotify_data_path(data, data_type);
653-
unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS);
654679
struct mem_cgroup *old_memcg;
655680
struct inode *child = NULL;
656681
bool name_event = false;
@@ -660,11 +685,10 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
660685

661686
if ((fid_mode & FAN_REPORT_DIR_FID) && dirid) {
662687
/*
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
688+
* For certain events and group flags, report the child fid
665689
* in addition to reporting the parent fid and maybe child name.
666690
*/
667-
if ((fid_mode & FAN_REPORT_FID) && id != dirid && !ondir)
691+
if (fanotify_report_child_fid(fid_mode, mask) && id != dirid)
668692
child = id;
669693

670694
id = dirid;

fs/notify/fanotify/fanotify_user.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1275,6 +1275,15 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
12751275
if ((fid_mode & FAN_REPORT_NAME) && !(fid_mode & FAN_REPORT_DIR_FID))
12761276
return -EINVAL;
12771277

1278+
/*
1279+
* FAN_REPORT_TARGET_FID requires FAN_REPORT_NAME and FAN_REPORT_FID
1280+
* and is used as an indication to report both dir and child fid on all
1281+
* dirent events.
1282+
*/
1283+
if ((fid_mode & FAN_REPORT_TARGET_FID) &&
1284+
(!(fid_mode & FAN_REPORT_NAME) || !(fid_mode & FAN_REPORT_FID)))
1285+
return -EINVAL;
1286+
12781287
f_flags = O_RDWR | FMODE_NONOTIFY;
12791288
if (flags & FAN_CLOEXEC)
12801289
f_flags |= O_CLOEXEC;
@@ -1667,7 +1676,7 @@ static int __init fanotify_user_setup(void)
16671676
FANOTIFY_DEFAULT_MAX_USER_MARKS);
16681677

16691678
BUILD_BUG_ON(FANOTIFY_INIT_FLAGS & FANOTIFY_INTERNAL_GROUP_FLAGS);
1670-
BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 11);
1679+
BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 12);
16711680
BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 9);
16721681

16731682
fanotify_mark_cache = KMEM_CACHE(fsnotify_mark,

include/linux/fanotify.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ extern struct ctl_table fanotify_table[]; /* for sysctl */
2525

2626
#define FANOTIFY_CLASS_BITS (FAN_CLASS_NOTIF | FANOTIFY_PERM_CLASSES)
2727

28-
#define FANOTIFY_FID_BITS (FAN_REPORT_FID | FAN_REPORT_DFID_NAME)
28+
#define FANOTIFY_FID_BITS (FAN_REPORT_DFID_NAME_TARGET)
2929

3030
#define FANOTIFY_INFO_MODES (FANOTIFY_FID_BITS | FAN_REPORT_PIDFD)
3131

include/uapi/linux/fanotify.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,13 @@
5757
#define FAN_REPORT_FID 0x00000200 /* Report unique file id */
5858
#define FAN_REPORT_DIR_FID 0x00000400 /* Report unique directory id */
5959
#define FAN_REPORT_NAME 0x00000800 /* Report events with name */
60+
#define FAN_REPORT_TARGET_FID 0x00001000 /* Report dirent target id */
6061

6162
/* Convenience macro - FAN_REPORT_NAME requires FAN_REPORT_DIR_FID */
6263
#define FAN_REPORT_DFID_NAME (FAN_REPORT_DIR_FID | FAN_REPORT_NAME)
64+
/* Convenience macro - FAN_REPORT_TARGET_FID requires all other FID flags */
65+
#define FAN_REPORT_DFID_NAME_TARGET (FAN_REPORT_DFID_NAME | \
66+
FAN_REPORT_FID | FAN_REPORT_TARGET_FID)
6367

6468
/* Deprecated - do not use this in programs and do not add new flags here! */
6569
#define FAN_ALL_INIT_FLAGS (FAN_CLOEXEC | FAN_NONBLOCK | \

0 commit comments

Comments
 (0)