Skip to content

Commit cacfb95

Browse files
amir73iljankara
authored andcommitted
fanotify: record name info for FAN_DIR_MODIFY event
For FAN_DIR_MODIFY event, allocate a variable size event struct to store the dir entry name along side the directory file handle. At this point, name info reporting is not yet implemented, so trying to set FAN_DIR_MODIFY in mark mask will return -EINVAL. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Amir Goldstein <[email protected]> Signed-off-by: Jan Kara <[email protected]>
1 parent 01affd5 commit cacfb95

File tree

3 files changed

+108
-12
lines changed

3 files changed

+108
-12
lines changed

fs/notify/fanotify/fanotify.c

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,23 @@ static bool fanotify_fid_event_equal(struct fanotify_fid_event *ffe1,
5353
fanotify_fh_equal(&ffe1->object_fh, &ffe2->object_fh);
5454
}
5555

56+
static bool fanotify_name_event_equal(struct fanotify_name_event *fne1,
57+
struct fanotify_name_event *fne2)
58+
{
59+
/*
60+
* Do not merge name events without dir fh.
61+
* FAN_DIR_MODIFY does not encode object fh, so it may be empty.
62+
*/
63+
if (!fne1->dir_fh.len)
64+
return false;
65+
66+
if (fne1->name_len != fne2->name_len ||
67+
!fanotify_fh_equal(&fne1->dir_fh, &fne2->dir_fh))
68+
return false;
69+
70+
return !memcmp(fne1->name, fne2->name, fne1->name_len);
71+
}
72+
5673
static bool should_merge(struct fsnotify_event *old_fsn,
5774
struct fsnotify_event *new_fsn)
5875
{
@@ -84,6 +101,9 @@ static bool should_merge(struct fsnotify_event *old_fsn,
84101

85102
return fanotify_fid_event_equal(FANOTIFY_FE(old),
86103
FANOTIFY_FE(new));
104+
case FANOTIFY_EVENT_TYPE_FID_NAME:
105+
return fanotify_name_event_equal(FANOTIFY_NE(old),
106+
FANOTIFY_NE(new));
87107
default:
88108
WARN_ON_ONCE(1);
89109
}
@@ -262,6 +282,9 @@ static void fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode,
262282
void *buf = fh->buf;
263283
int err;
264284

285+
if (!inode)
286+
goto out;
287+
265288
dwords = 0;
266289
err = -ENOENT;
267290
type = exportfs_encode_inode_fh(inode, NULL, &dwords, NULL);
@@ -295,6 +318,7 @@ static void fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode,
295318
type, bytes, err);
296319
kfree(ext_buf);
297320
*fanotify_fh_ext_buf_ptr(fh) = NULL;
321+
out:
298322
/* Report the event without a file identifier on encode error */
299323
fh->type = FILEID_INVALID;
300324
fh->len = 0;
@@ -320,10 +344,12 @@ static struct inode *fanotify_fid_inode(struct inode *to_tell, u32 event_mask,
320344
struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
321345
struct inode *inode, u32 mask,
322346
const void *data, int data_type,
347+
const struct qstr *file_name,
323348
__kernel_fsid_t *fsid)
324349
{
325350
struct fanotify_event *event = NULL;
326351
struct fanotify_fid_event *ffe = NULL;
352+
struct fanotify_name_event *fne = NULL;
327353
gfp_t gfp = GFP_KERNEL_ACCOUNT;
328354
struct inode *id = fanotify_fid_inode(inode, mask, data, data_type);
329355
const struct path *path = fsnotify_data_path(data, data_type);
@@ -356,6 +382,23 @@ struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
356382
goto init;
357383
}
358384

385+
/*
386+
* For FAN_DIR_MODIFY event, we report the fid of the directory and
387+
* the name of the modified entry.
388+
* Allocate an fanotify_name_event struct and copy the name.
389+
*/
390+
if (mask & FAN_DIR_MODIFY && !(WARN_ON_ONCE(!file_name))) {
391+
fne = kmalloc(sizeof(*fne) + file_name->len + 1, gfp);
392+
if (!fne)
393+
goto out;
394+
395+
event = &fne->fae;
396+
event->type = FANOTIFY_EVENT_TYPE_FID_NAME;
397+
fne->name_len = file_name->len;
398+
strcpy(fne->name, file_name->name);
399+
goto init;
400+
}
401+
359402
if (FAN_GROUP_FLAG(group, FAN_REPORT_FID)) {
360403
ffe = kmem_cache_alloc(fanotify_fid_event_cachep, gfp);
361404
if (!ffe)
@@ -374,7 +417,7 @@ struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
374417
event->type = FANOTIFY_EVENT_TYPE_PATH;
375418
}
376419

377-
init: __maybe_unused
420+
init:
378421
/*
379422
* Use the victim inode instead of the watching inode as the id for
380423
* event queue, so event reported on parent is merged with event
@@ -387,13 +430,16 @@ init: __maybe_unused
387430
else
388431
event->pid = get_pid(task_tgid(current));
389432

390-
if (fanotify_event_object_fh(event)) {
391-
ffe->object_fh.len = 0;
392-
if (fsid)
393-
ffe->fsid = *fsid;
394-
if (id)
395-
fanotify_encode_fh(&ffe->object_fh, id, gfp);
396-
} else if (fanotify_event_has_path(event)) {
433+
if (fsid && fanotify_event_fsid(event))
434+
*fanotify_event_fsid(event) = *fsid;
435+
436+
if (fanotify_event_object_fh(event))
437+
fanotify_encode_fh(fanotify_event_object_fh(event), id, gfp);
438+
439+
if (fanotify_event_dir_fh(event))
440+
fanotify_encode_fh(fanotify_event_dir_fh(event), id, gfp);
441+
442+
if (fanotify_event_has_path(event)) {
397443
struct path *p = fanotify_event_path(event);
398444

399445
if (path) {
@@ -501,7 +547,7 @@ static int fanotify_handle_event(struct fsnotify_group *group,
501547
}
502548

503549
event = fanotify_alloc_event(group, inode, mask, data, data_type,
504-
&fsid);
550+
file_name, &fsid);
505551
ret = -ENOMEM;
506552
if (unlikely(!event)) {
507553
/*
@@ -563,6 +609,15 @@ static void fanotify_free_fid_event(struct fanotify_event *event)
563609
kmem_cache_free(fanotify_fid_event_cachep, ffe);
564610
}
565611

612+
static void fanotify_free_name_event(struct fanotify_event *event)
613+
{
614+
struct fanotify_name_event *fne = FANOTIFY_NE(event);
615+
616+
if (fanotify_fh_has_ext_buf(&fne->dir_fh))
617+
kfree(fanotify_fh_ext_buf(&fne->dir_fh));
618+
kfree(fne);
619+
}
620+
566621
static void fanotify_free_event(struct fsnotify_event *fsn_event)
567622
{
568623
struct fanotify_event *event;
@@ -579,6 +634,9 @@ static void fanotify_free_event(struct fsnotify_event *fsn_event)
579634
case FANOTIFY_EVENT_TYPE_FID:
580635
fanotify_free_fid_event(event);
581636
break;
637+
case FANOTIFY_EVENT_TYPE_FID_NAME:
638+
fanotify_free_name_event(event);
639+
break;
582640
default:
583641
WARN_ON_ONCE(1);
584642
}

fs/notify/fanotify/fanotify.h

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ static inline void *fanotify_fh_buf(struct fanotify_fh *fh)
5959
* be freed and which concrete struct it may be cast to.
6060
*/
6161
enum fanotify_event_type {
62-
FANOTIFY_EVENT_TYPE_FID,
62+
FANOTIFY_EVENT_TYPE_FID, /* fixed length */
63+
FANOTIFY_EVENT_TYPE_FID_NAME, /* variable length */
6364
FANOTIFY_EVENT_TYPE_PATH,
6465
FANOTIFY_EVENT_TYPE_PATH_PERM,
6566
};
@@ -83,10 +84,26 @@ FANOTIFY_FE(struct fanotify_event *event)
8384
return container_of(event, struct fanotify_fid_event, fae);
8485
}
8586

87+
struct fanotify_name_event {
88+
struct fanotify_event fae;
89+
__kernel_fsid_t fsid;
90+
struct fanotify_fh dir_fh;
91+
u8 name_len;
92+
char name[0];
93+
};
94+
95+
static inline struct fanotify_name_event *
96+
FANOTIFY_NE(struct fanotify_event *event)
97+
{
98+
return container_of(event, struct fanotify_name_event, fae);
99+
}
100+
86101
static inline __kernel_fsid_t *fanotify_event_fsid(struct fanotify_event *event)
87102
{
88103
if (event->type == FANOTIFY_EVENT_TYPE_FID)
89104
return &FANOTIFY_FE(event)->fsid;
105+
else if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME)
106+
return &FANOTIFY_NE(event)->fsid;
90107
else
91108
return NULL;
92109
}
@@ -100,13 +117,33 @@ static inline struct fanotify_fh *fanotify_event_object_fh(
100117
return NULL;
101118
}
102119

120+
static inline struct fanotify_fh *fanotify_event_dir_fh(
121+
struct fanotify_event *event)
122+
{
123+
if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME)
124+
return &FANOTIFY_NE(event)->dir_fh;
125+
else
126+
return NULL;
127+
}
128+
103129
static inline int fanotify_event_object_fh_len(struct fanotify_event *event)
104130
{
105131
struct fanotify_fh *fh = fanotify_event_object_fh(event);
106132

107133
return fh ? fh->len : 0;
108134
}
109135

136+
static inline bool fanotify_event_has_name(struct fanotify_event *event)
137+
{
138+
return event->type == FANOTIFY_EVENT_TYPE_FID_NAME;
139+
}
140+
141+
static inline int fanotify_event_name_len(struct fanotify_event *event)
142+
{
143+
return fanotify_event_has_name(event) ?
144+
FANOTIFY_NE(event)->name_len : 0;
145+
}
146+
110147
struct fanotify_path_event {
111148
struct fanotify_event fae;
112149
struct path path;
@@ -169,4 +206,5 @@ static inline struct path *fanotify_event_path(struct fanotify_event *event)
169206
struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
170207
struct inode *inode, u32 mask,
171208
const void *data, int data_type,
209+
const struct qstr *file_name,
172210
__kernel_fsid_t *fsid);

fs/notify/fanotify/fanotify_user.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ static int copy_fid_to_user(__kernel_fsid_t *fsid, struct fanotify_fh *fh,
210210
struct fanotify_event_info_fid info = { };
211211
struct file_handle handle = { };
212212
unsigned char bounce[FANOTIFY_INLINE_FH_LEN], *fh_buf;
213-
size_t fh_len = fh->len;
213+
size_t fh_len = fh ? fh->len : 0;
214214
size_t len = fanotify_fid_info_len(fh_len);
215215

216216
if (!len)
@@ -828,7 +828,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
828828
group->memcg = get_mem_cgroup_from_mm(current->mm);
829829

830830
oevent = fanotify_alloc_event(group, NULL, FS_Q_OVERFLOW, NULL,
831-
FSNOTIFY_EVENT_NONE, NULL);
831+
FSNOTIFY_EVENT_NONE, NULL, NULL);
832832
if (unlikely(!oevent)) {
833833
fd = -ENOMEM;
834834
goto out_destroy_group;

0 commit comments

Comments
 (0)