Many of the use cases for fanotify events only use the event->fd to resolve the path of the event target object. Using O_PATH for this purpose is more efficient and prevents exposing a readable fd of the object if that is not required. To be able to distinguish a user opened O_PATH fd, from fanotify provided O_PATH event->fd, do not explicitly set FMODE_NONOTIFY on open of all O_PATH fds, do not override FMODE_NONOTIFY when setting FMODE_PATH in do_dentry_open() and check explicitly for FMODE_PATH in fsnotify_file() to suppress FAN_CLOSE events on close of O_PATH fds. Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx> --- fs/notify/fanotify/fanotify_user.c | 2 +- fs/open.c | 4 ++-- include/linux/fs.h | 10 ++++++---- include/linux/fsnotify.h | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 9d7b3a610b4a..fd2906a8a15e 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -105,7 +105,7 @@ static void __init fanotify_sysctls_init(void) #define FANOTIFY_INIT_ALL_EVENT_F_BITS ( \ O_ACCMODE | O_APPEND | O_NONBLOCK | \ __O_SYNC | O_DSYNC | O_CLOEXEC | \ - O_LARGEFILE | O_NOATIME ) + O_LARGEFILE | O_NOATIME | O_PATH) extern const struct fsnotify_ops fanotify_fsnotify_ops; diff --git a/fs/open.c b/fs/open.c index 7828234a7caa..4664240f4c5e 100644 --- a/fs/open.c +++ b/fs/open.c @@ -913,8 +913,8 @@ static int do_dentry_open(struct file *f, f->f_sb_err = file_sample_sb_err(f); if (unlikely(f->f_flags & O_PATH)) { - f->f_mode = FMODE_PATH | FMODE_OPENED; - file_set_fsnotify_mode(f, FMODE_NONOTIFY); + f->f_mode = FMODE_PATH | FMODE_OPENED | + FMODE_FSNOTIFY(f->f_mode); f->f_op = &empty_fops; return 0; } diff --git a/include/linux/fs.h b/include/linux/fs.h index aad2fb940a45..098456235cb5 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -210,14 +210,16 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset, #define FMODE_FSNOTIFY_MASK \ (FMODE_NONOTIFY | FMODE_NONOTIFY_PERM) +#define FMODE_FSNOTIFY(mode) \ + (mode & FMODE_FSNOTIFY_MASK) #define FMODE_FSNOTIFY_NONE(mode) \ - ((mode & FMODE_FSNOTIFY_MASK) == FMODE_NONOTIFY) + (FMODE_FSNOTIFY(mode) == FMODE_NONOTIFY) #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS #define FMODE_FSNOTIFY_PERM(mode) \ - ((mode & FMODE_FSNOTIFY_MASK) == 0 || \ - (mode & FMODE_FSNOTIFY_MASK) == (FMODE_NONOTIFY | FMODE_NONOTIFY_PERM)) + (FMODE_FSNOTIFY(mode) == 0 || \ + FMODE_FSNOTIFY(mode) == (FMODE_NONOTIFY | FMODE_NONOTIFY_PERM)) #define FMODE_FSNOTIFY_HSM(mode) \ - ((mode & FMODE_FSNOTIFY_MASK) == 0) + (FMODE_FSNOTIFY(mode) == 0) #else #define FMODE_FSNOTIFY_PERM(mode) 0 #define FMODE_FSNOTIFY_HSM(mode) 0 diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index 454d8e466958..175149167642 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -121,7 +121,7 @@ static inline int fsnotify_file(struct file *file, __u32 mask) * FMODE_PATH fds (involves open & close events) as they are just * handle creation / destruction events and not "real" file events. */ - if (FMODE_FSNOTIFY_NONE(file->f_mode)) + if (FMODE_FSNOTIFY_NONE(file->f_mode) || (file->f_mode & FMODE_PATH)) return 0; return fsnotify_path(&file->f_path, mask); -- 2.34.1