Skip to content

Commit 929943b

Browse files
amir73iljankara
authored andcommitted
fanotify: add support for FAN_REPORT_NAME
Introduce a new fanotify_init() flag FAN_REPORT_NAME. It requires the flag FAN_REPORT_DIR_FID and there is a constant for setting both flags named FAN_REPORT_DFID_NAME. For a group with flag FAN_REPORT_NAME, the parent fid and name are reported for directory entry modification events (create/detete/move) and for events on non-directory objects. Events on directories themselves are reported with their own fid and "." as the name. The parent fid and name are reported with an info record of type FAN_EVENT_INFO_TYPE_DFID_NAME, similar to the way that parent fid is reported with into type FAN_EVENT_INFO_TYPE_DFID, but with an appended null terminated name string. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Amir Goldstein <[email protected]> Signed-off-by: Jan Kara <[email protected]>
1 parent 5128063 commit 929943b

File tree

4 files changed

+58
-11
lines changed

4 files changed

+58
-11
lines changed

fs/notify/fanotify/fanotify.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,9 +522,25 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
522522
unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS);
523523
bool name_event = false;
524524

525-
if ((fid_mode & FAN_REPORT_DIR_FID) && dirid)
525+
if ((fid_mode & FAN_REPORT_DIR_FID) && dirid) {
526526
id = dirid;
527527

528+
/*
529+
* We record file name only in a group with FAN_REPORT_NAME
530+
* and when we have a directory inode to report.
531+
*
532+
* For directory entry modification event, we record the fid of
533+
* the directory and the name of the modified entry.
534+
*
535+
* For event on non-directory that is reported to parent, we
536+
* record the fid of the parent and the name of the child.
537+
*/
538+
if ((fid_mode & FAN_REPORT_NAME) &&
539+
((mask & ALL_FSNOTIFY_DIRENT_EVENTS) ||
540+
!(mask & FAN_ONDIR)))
541+
name_event = true;
542+
}
543+
528544
/*
529545
* For queues with unlimited length lost events are not expected and
530546
* can possibly have security implications. Avoid losing events when

fs/notify/fanotify/fanotify_user.c

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,18 +64,27 @@ static int fanotify_fid_info_len(int fh_len, int name_len)
6464
return roundup(FANOTIFY_INFO_HDR_LEN + info_len, FANOTIFY_EVENT_ALIGN);
6565
}
6666

67-
static int fanotify_event_info_len(struct fanotify_event *event)
67+
static int fanotify_event_info_len(unsigned int fid_mode,
68+
struct fanotify_event *event)
6869
{
6970
struct fanotify_info *info = fanotify_event_info(event);
7071
int dir_fh_len = fanotify_event_dir_fh_len(event);
7172
int fh_len = fanotify_event_object_fh_len(event);
7273
int info_len = 0;
74+
int dot_len = 0;
7375

74-
if (dir_fh_len)
76+
if (dir_fh_len) {
7577
info_len += fanotify_fid_info_len(dir_fh_len, info->name_len);
78+
} else if ((fid_mode & FAN_REPORT_NAME) && (event->mask & FAN_ONDIR)) {
79+
/*
80+
* With group flag FAN_REPORT_NAME, if name was not recorded in
81+
* event on a directory, we will report the name ".".
82+
*/
83+
dot_len = 1;
84+
}
7685

7786
if (fh_len)
78-
info_len += fanotify_fid_info_len(fh_len, 0);
87+
info_len += fanotify_fid_info_len(fh_len, dot_len);
7988

8089
return info_len;
8190
}
@@ -91,15 +100,16 @@ static struct fanotify_event *get_one_event(struct fsnotify_group *group,
91100
{
92101
size_t event_size = FAN_EVENT_METADATA_LEN;
93102
struct fanotify_event *event = NULL;
103+
unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS);
94104

95105
pr_debug("%s: group=%p count=%zd\n", __func__, group, count);
96106

97107
spin_lock(&group->notification_lock);
98108
if (fsnotify_notify_queue_is_empty(group))
99109
goto out;
100110

101-
if (FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS)) {
102-
event_size += fanotify_event_info_len(
111+
if (fid_mode) {
112+
event_size += fanotify_event_info_len(fid_mode,
103113
FANOTIFY_E(fsnotify_peek_first_event(group)));
104114
}
105115

@@ -325,7 +335,7 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
325335
pr_debug("%s: group=%p event=%p\n", __func__, group, event);
326336

327337
metadata.event_len = FAN_EVENT_METADATA_LEN +
328-
fanotify_event_info_len(event);
338+
fanotify_event_info_len(fid_mode, event);
329339
metadata.metadata_len = FAN_EVENT_METADATA_LEN;
330340
metadata.vers = FANOTIFY_METADATA_VERSION;
331341
metadata.reserved = 0;
@@ -374,12 +384,25 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
374384
}
375385

376386
if (fanotify_event_object_fh_len(event)) {
387+
const char *dot = NULL;
388+
int dot_len = 0;
389+
377390
if (fid_mode == FAN_REPORT_FID || info_type) {
378391
/*
379392
* With only group flag FAN_REPORT_FID only type FID is
380393
* reported. Second info record type is always FID.
381394
*/
382395
info_type = FAN_EVENT_INFO_TYPE_FID;
396+
} else if ((fid_mode & FAN_REPORT_NAME) &&
397+
(event->mask & FAN_ONDIR)) {
398+
/*
399+
* With group flag FAN_REPORT_NAME, if name was not
400+
* recorded in an event on a directory, report the
401+
* name "." with info type DFID_NAME.
402+
*/
403+
info_type = FAN_EVENT_INFO_TYPE_DFID_NAME;
404+
dot = ".";
405+
dot_len = 1;
383406
} else if ((event->mask & ALL_FSNOTIFY_DIRENT_EVENTS) ||
384407
(event->mask & FAN_ONDIR)) {
385408
/*
@@ -400,7 +423,7 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
400423

401424
ret = copy_info_to_user(fanotify_event_fsid(event),
402425
fanotify_event_object_fh(event),
403-
info_type, NULL, 0, buf, count);
426+
info_type, dot, dot_len, buf, count);
404427
if (ret < 0)
405428
return ret;
406429

@@ -932,11 +955,15 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
932955
if (fid_mode && class != FAN_CLASS_NOTIF)
933956
return -EINVAL;
934957

935-
/* Reporting either object fid or dir fid */
958+
/*
959+
* Reporting either object fid or dir fid.
960+
* Child name is reported with parent fid so requires dir fid.
961+
*/
936962
switch (fid_mode) {
937963
case 0:
938964
case FAN_REPORT_FID:
939965
case FAN_REPORT_DIR_FID:
966+
case FAN_REPORT_DFID_NAME:
940967
break;
941968
default:
942969
return -EINVAL;
@@ -1294,7 +1321,7 @@ COMPAT_SYSCALL_DEFINE6(fanotify_mark,
12941321
*/
12951322
static int __init fanotify_user_setup(void)
12961323
{
1297-
BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 9);
1324+
BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 10);
12981325
BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 9);
12991326

13001327
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
@@ -18,7 +18,7 @@
1818
#define FANOTIFY_CLASS_BITS (FAN_CLASS_NOTIF | FAN_CLASS_CONTENT | \
1919
FAN_CLASS_PRE_CONTENT)
2020

21-
#define FANOTIFY_FID_BITS (FAN_REPORT_FID | FAN_REPORT_DIR_FID)
21+
#define FANOTIFY_FID_BITS (FAN_REPORT_FID | FAN_REPORT_DFID_NAME)
2222

2323
#define FANOTIFY_INIT_FLAGS (FANOTIFY_CLASS_BITS | FANOTIFY_FID_BITS | \
2424
FAN_REPORT_TID | \

include/uapi/linux/fanotify.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@
5454
#define FAN_REPORT_TID 0x00000100 /* event->pid is thread id */
5555
#define FAN_REPORT_FID 0x00000200 /* Report unique file id */
5656
#define FAN_REPORT_DIR_FID 0x00000400 /* Report unique directory id */
57+
#define FAN_REPORT_NAME 0x00000800 /* Report events with name */
58+
59+
/* Convenience macro - FAN_REPORT_NAME requires FAN_REPORT_DIR_FID */
60+
#define FAN_REPORT_DFID_NAME (FAN_REPORT_DIR_FID | FAN_REPORT_NAME)
5761

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

0 commit comments

Comments
 (0)