From 0b3b094ac9a7bb1fcf5d694f3ec981e6864a63d3 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 15 May 2019 16:28:34 +0200 Subject: fanotify: Disallow permission events for proc filesystem Proc filesystem has special locking rules for various files. Thus fanotify which opens files on event delivery can easily deadlock against another process that waits for fanotify permission event to be handled. Since permission events on /proc have doubtful value anyway, just disallow them. Link: https://lore.kernel.org/linux-fsdevel/20190320131642.GE9485@quack2.suse.cz/ Reviewed-by: Amir Goldstein Signed-off-by: Jan Kara --- include/linux/fs.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index f7fdfe93e25d..c7136c98b5ba 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2184,6 +2184,7 @@ struct file_system_type { #define FS_BINARY_MOUNTDATA 2 #define FS_HAS_SUBTYPE 4 #define FS_USERNS_MOUNT 8 /* Can be mounted by userns root */ +#define FS_DISALLOW_NOTIFY_PERM 16 /* Disable fanotify permission events */ #define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move() during rename() internally. */ int (*init_fs_context)(struct fs_context *); const struct fs_parameter_description *parameters; -- cgit v1.2.3 From 116b9731ad7614032a390bb9ad8998a14d6dc752 Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Sun, 26 May 2019 17:34:02 +0300 Subject: fsnotify: add empty fsnotify_{unlink,rmdir}() hooks We would like to move fsnotify_nameremove() calls from d_delete() into a higher layer where the hook makes more sense and so we can consider every d_delete() call site individually. Start by creating empty hook fsnotify_{unlink,rmdir}() and place them in the proper VFS call sites. After all d_delete() call sites will be converted to use the new hook, the new hook will generate the delete events and fsnotify_nameremove() hook will be removed. Signed-off-by: Amir Goldstein Signed-off-by: Jan Kara --- include/linux/fsnotify.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'include/linux') diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index 94972e8eb6d1..7f23eddefcd0 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -188,6 +188,19 @@ static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct fsnotify(dir, FS_CREATE, inode, FSNOTIFY_EVENT_INODE, &new_dentry->d_name, 0); } +/* + * fsnotify_unlink - 'name' was unlinked + * + * Caller must make sure that dentry->d_name is stable. + */ +static inline void fsnotify_unlink(struct inode *dir, struct dentry *dentry) +{ + /* Expected to be called before d_delete() */ + WARN_ON_ONCE(d_is_negative(dentry)); + + /* TODO: call fsnotify_dirent() */ +} + /* * fsnotify_mkdir - directory 'name' was created */ @@ -198,6 +211,19 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry) fsnotify_dirent(inode, dentry, FS_CREATE | FS_ISDIR); } +/* + * fsnotify_rmdir - directory 'name' was removed + * + * Caller must make sure that dentry->d_name is stable. + */ +static inline void fsnotify_rmdir(struct inode *dir, struct dentry *dentry) +{ + /* Expected to be called before d_delete() */ + WARN_ON_ONCE(d_is_negative(dentry)); + + /* TODO: call fsnotify_dirent() */ +} + /* * fsnotify_access - file was read */ -- cgit v1.2.3 From 49246466a98996e78b68a0041807dbd2628c53fe Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Sun, 26 May 2019 17:34:10 +0300 Subject: fsnotify: move fsnotify_nameremove() hook out of d_delete() d_delete() was piggy backed for the fsnotify_nameremove() hook when in fact not all callers of d_delete() care about fsnotify events. For all callers of d_delete() that may be interested in fsnotify events, we made sure to call one of fsnotify_{unlink,rmdir}() hooks before calling d_delete(). Now we can move the fsnotify_nameremove() call from d_delete() to the fsnotify_{unlink,rmdir}() hooks. Two explicit calls to fsnotify_nameremove() from nfs/afs sillyrename are also removed. This will cause a change of behavior - nfs/afs will NOT generate an fsnotify delete event when renaming over a positive dentry. This change is desirable, because it is consistent with the behavior of all other filesystems. Signed-off-by: Amir Goldstein Signed-off-by: Jan Kara --- include/linux/fsnotify.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index 7f23eddefcd0..0145073c2b42 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -199,6 +199,7 @@ static inline void fsnotify_unlink(struct inode *dir, struct dentry *dentry) WARN_ON_ONCE(d_is_negative(dentry)); /* TODO: call fsnotify_dirent() */ + fsnotify_nameremove(dentry, 0); } /* @@ -222,6 +223,7 @@ static inline void fsnotify_rmdir(struct inode *dir, struct dentry *dentry) WARN_ON_ONCE(d_is_negative(dentry)); /* TODO: call fsnotify_dirent() */ + fsnotify_nameremove(dentry, 1); } /* -- cgit v1.2.3 From 7377f5bec13332bc470856f337935be6cabbcf24 Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Sun, 26 May 2019 17:34:11 +0300 Subject: fsnotify: get rid of fsnotify_nameremove() For all callers of fsnotify_{unlink,rmdir}(), we made sure that d_parent and d_name are stable. Therefore, fsnotify_{unlink,rmdir}() do not need the safety measures in fsnotify_nameremove() to stabilize parent and name. We can now simplify those hooks and get rid of fsnotify_nameremove(). Signed-off-by: Amir Goldstein Signed-off-by: Jan Kara --- include/linux/fsnotify.h | 6 ++---- include/linux/fsnotify_backend.h | 4 ---- 2 files changed, 2 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index 0145073c2b42..a2d5d175d3c1 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -198,8 +198,7 @@ static inline void fsnotify_unlink(struct inode *dir, struct dentry *dentry) /* Expected to be called before d_delete() */ WARN_ON_ONCE(d_is_negative(dentry)); - /* TODO: call fsnotify_dirent() */ - fsnotify_nameremove(dentry, 0); + fsnotify_dirent(dir, dentry, FS_DELETE); } /* @@ -222,8 +221,7 @@ static inline void fsnotify_rmdir(struct inode *dir, struct dentry *dentry) /* Expected to be called before d_delete() */ WARN_ON_ONCE(d_is_negative(dentry)); - /* TODO: call fsnotify_dirent() */ - fsnotify_nameremove(dentry, 1); + fsnotify_dirent(dir, dentry, FS_DELETE | FS_ISDIR); } /* diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index a9f9dcc1e515..c28f6ed1f59b 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -355,7 +355,6 @@ extern int __fsnotify_parent(const struct path *path, struct dentry *dentry, __u extern void __fsnotify_inode_delete(struct inode *inode); extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt); extern void fsnotify_sb_delete(struct super_block *sb); -extern void fsnotify_nameremove(struct dentry *dentry, int isdir); extern u32 fsnotify_get_cookie(void); static inline int fsnotify_inode_watches_children(struct inode *inode) @@ -525,9 +524,6 @@ static inline void __fsnotify_vfsmount_delete(struct vfsmount *mnt) static inline void fsnotify_sb_delete(struct super_block *sb) {} -static inline void fsnotify_nameremove(struct dentry *dentry, int isdir) -{} - static inline void fsnotify_update_flags(struct dentry *dentry) {} -- cgit v1.2.3