Skip to content

Commit 3982534

Browse files
amir73iljankara
authored andcommitted
fanotify: record old and new parent and name in FAN_RENAME event
In the special case of FAN_RENAME event, we record both the old and new parent and name. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Amir Goldstein <[email protected]> Signed-off-by: Jan Kara <[email protected]>
1 parent 3cf984e commit 3982534

File tree

2 files changed

+40
-4
lines changed

2 files changed

+40
-4
lines changed

fs/notify/fanotify/fanotify.c

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -592,21 +592,28 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *dir,
592592
__kernel_fsid_t *fsid,
593593
const struct qstr *name,
594594
struct inode *child,
595+
struct dentry *moved,
595596
unsigned int *hash,
596597
gfp_t gfp)
597598
{
598599
struct fanotify_name_event *fne;
599600
struct fanotify_info *info;
600601
struct fanotify_fh *dfh, *ffh;
602+
struct inode *dir2 = moved ? d_inode(moved->d_parent) : NULL;
603+
const struct qstr *name2 = moved ? &moved->d_name : NULL;
601604
unsigned int dir_fh_len = fanotify_encode_fh_len(dir);
605+
unsigned int dir2_fh_len = fanotify_encode_fh_len(dir2);
602606
unsigned int child_fh_len = fanotify_encode_fh_len(child);
603607
unsigned long name_len = name ? name->len : 0;
608+
unsigned long name2_len = name2 ? name2->len : 0;
604609
unsigned int len, size;
605610

606611
/* Reserve terminating null byte even for empty name */
607-
size = sizeof(*fne) + name_len + 1;
612+
size = sizeof(*fne) + name_len + name2_len + 2;
608613
if (dir_fh_len)
609614
size += FANOTIFY_FH_HDR_LEN + dir_fh_len;
615+
if (dir2_fh_len)
616+
size += FANOTIFY_FH_HDR_LEN + dir2_fh_len;
610617
if (child_fh_len)
611618
size += FANOTIFY_FH_HDR_LEN + child_fh_len;
612619
fne = kmalloc(size, gfp);
@@ -623,6 +630,11 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *dir,
623630
len = fanotify_encode_fh(dfh, dir, dir_fh_len, hash, 0);
624631
fanotify_info_set_dir_fh(info, len);
625632
}
633+
if (dir2_fh_len) {
634+
dfh = fanotify_info_dir2_fh(info);
635+
len = fanotify_encode_fh(dfh, dir2, dir2_fh_len, hash, 0);
636+
fanotify_info_set_dir2_fh(info, len);
637+
}
626638
if (child_fh_len) {
627639
ffh = fanotify_info_file_fh(info);
628640
len = fanotify_encode_fh(ffh, child, child_fh_len, hash, 0);
@@ -632,11 +644,22 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *dir,
632644
fanotify_info_copy_name(info, name);
633645
*hash ^= full_name_hash((void *)name_len, name->name, name_len);
634646
}
647+
if (name2_len) {
648+
fanotify_info_copy_name2(info, name2);
649+
*hash ^= full_name_hash((void *)name2_len, name2->name,
650+
name2_len);
651+
}
635652

636653
pr_debug("%s: size=%u dir_fh_len=%u child_fh_len=%u name_len=%u name='%.*s'\n",
637654
__func__, size, dir_fh_len, child_fh_len,
638655
info->name_len, info->name_len, fanotify_info_name(info));
639656

657+
if (dir2_fh_len) {
658+
pr_debug("%s: dir2_fh_len=%u name2_len=%u name2='%.*s'\n",
659+
__func__, dir2_fh_len, info->name2_len,
660+
info->name2_len, fanotify_info_name2(info));
661+
}
662+
640663
return &fne->fae;
641664
}
642665

@@ -692,6 +715,7 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
692715
struct inode *dirid = fanotify_dfid_inode(mask, data, data_type, dir);
693716
const struct path *path = fsnotify_data_path(data, data_type);
694717
struct mem_cgroup *old_memcg;
718+
struct dentry *moved = NULL;
695719
struct inode *child = NULL;
696720
bool name_event = false;
697721
unsigned int hash = 0;
@@ -727,6 +751,15 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
727751
} else if ((mask & ALL_FSNOTIFY_DIRENT_EVENTS) || !ondir) {
728752
name_event = true;
729753
}
754+
755+
/*
756+
* In the special case of FAN_RENAME event, we record both
757+
* old and new parent+name.
758+
* 'dirid' and 'file_name' are the old parent+name and
759+
* 'moved' has the new parent+name.
760+
*/
761+
if (mask & FAN_RENAME)
762+
moved = fsnotify_data_dentry(data, data_type);
730763
}
731764

732765
/*
@@ -748,9 +781,9 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
748781
} else if (fanotify_is_error_event(mask)) {
749782
event = fanotify_alloc_error_event(group, fsid, data,
750783
data_type, &hash);
751-
} else if (name_event && (file_name || child)) {
752-
event = fanotify_alloc_name_event(id, fsid, file_name, child,
753-
&hash, gfp);
784+
} else if (name_event && (file_name || moved || child)) {
785+
event = fanotify_alloc_name_event(dirid, fsid, file_name, child,
786+
moved, &hash, gfp);
754787
} else if (fid_mode) {
755788
event = fanotify_alloc_fid_event(id, fsid, &hash, gfp);
756789
} else {
@@ -860,6 +893,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask,
860893
BUILD_BUG_ON(FAN_OPEN_EXEC != FS_OPEN_EXEC);
861894
BUILD_BUG_ON(FAN_OPEN_EXEC_PERM != FS_OPEN_EXEC_PERM);
862895
BUILD_BUG_ON(FAN_FS_ERROR != FS_ERROR);
896+
BUILD_BUG_ON(FAN_RENAME != FS_RENAME);
863897

864898
BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 20);
865899

include/uapi/linux/fanotify.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828

2929
#define FAN_EVENT_ON_CHILD 0x08000000 /* Interested in child events */
3030

31+
#define FAN_RENAME 0x10000000 /* File was renamed */
32+
3133
#define FAN_ONDIR 0x40000000 /* Event occurred against dir */
3234

3335
/* helper events */

0 commit comments

Comments
 (0)