-----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEq1nRK9aeMoq1VSgcnJ2qBz9kQNkFAl0kWgwACgkQnJ2qBz9k QNkkdggA7bdy6xZRPdumZMxtASGDs1JJ4diNs+apgyc6wUfsT1lCE2ap20EdzfzK drAvlJt1vYEW+6apOzUXJ0qWXMVRzy4XRl+jVMO9GW6BoY4OyJQ86AQZlEv1zZ4n vxeYnlbxA7JyfkWgup0ZSb5EKRSO1eSxZKEZou0wu2jRCRr/E5RyjPQHXaiE5ihc 7ilEtTI3Qg3nnAK30F0Iy0X3lGqgXj+rlJ0TgR8BBEDllct2wV16vvMl/Sy+BXip 5sSWjSy8zntMnkSN8yH/oJN0D+fqmCsnYafwqTpPek8izvEz4xpjshbWTDnPm0HM eiMC1U3ZJoD3Z4/wxRZ91m60VYgJBA== =SVKR -----END PGP SIGNATURE----- Merge tag 'fsnotify_for_v5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs Pull fsnotify updates from Jan Kara: "This contains cleanups of the fsnotify name removal hook and also a patch to disable fanotify permission events for 'proc' filesystem" * tag 'fsnotify_for_v5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs: fsnotify: get rid of fsnotify_nameremove() fsnotify: move fsnotify_nameremove() hook out of d_delete() configfs: call fsnotify_rmdir() hook debugfs: call fsnotify_{unlink,rmdir}() hooks debugfs: simplify __debugfs_remove_file() devpts: call fsnotify_unlink() hook tracefs: call fsnotify_{unlink,rmdir}() hooks rpc_pipefs: call fsnotify_{unlink,rmdir}() hooks btrfs: call fsnotify_rmdir() hook fsnotify: add empty fsnotify_{unlink,rmdir}() hooks fanotify: Disallow permission events for proc filesystem
This commit is contained in:
commit
e6983afd92
|
@ -60,11 +60,6 @@ static int afs_do_silly_rename(struct afs_vnode *dvnode, struct afs_vnode *vnode
|
|||
if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
|
||||
afs_edit_dir_add(dvnode, &new->d_name,
|
||||
&vnode->fid, afs_edit_dir_for_silly_1);
|
||||
|
||||
/* vfs_unlink and the like do not issue this when a file is
|
||||
* sillyrenamed, so do it here.
|
||||
*/
|
||||
fsnotify_nameremove(old, 0);
|
||||
}
|
||||
|
||||
kfree(scb);
|
||||
|
|
|
@ -2928,8 +2928,10 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
|
|||
inode_lock(inode);
|
||||
err = btrfs_delete_subvolume(dir, dentry);
|
||||
inode_unlock(inode);
|
||||
if (!err)
|
||||
if (!err) {
|
||||
fsnotify_rmdir(dir, dentry);
|
||||
d_delete(dentry);
|
||||
}
|
||||
|
||||
out_dput:
|
||||
dput(dentry);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#undef DEBUG
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/fsnotify.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -1788,6 +1789,7 @@ void configfs_unregister_group(struct config_group *group)
|
|||
configfs_detach_group(&group->cg_item);
|
||||
d_inode(dentry)->i_flags |= S_DEAD;
|
||||
dont_mount(dentry);
|
||||
fsnotify_rmdir(d_inode(parent), dentry);
|
||||
d_delete(dentry);
|
||||
inode_unlock(d_inode(parent));
|
||||
|
||||
|
@ -1916,6 +1918,7 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys)
|
|||
configfs_detach_group(&group->cg_item);
|
||||
d_inode(dentry)->i_flags |= S_DEAD;
|
||||
dont_mount(dentry);
|
||||
fsnotify_rmdir(d_inode(root), dentry);
|
||||
inode_unlock(d_inode(dentry));
|
||||
|
||||
d_delete(dentry);
|
||||
|
|
|
@ -2372,7 +2372,6 @@ EXPORT_SYMBOL(d_hash_and_lookup);
|
|||
void d_delete(struct dentry * dentry)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int isdir = d_is_dir(dentry);
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
spin_lock(&dentry->d_lock);
|
||||
|
@ -2387,7 +2386,6 @@ void d_delete(struct dentry * dentry)
|
|||
spin_unlock(&dentry->d_lock);
|
||||
spin_unlock(&inode->i_lock);
|
||||
}
|
||||
fsnotify_nameremove(dentry, isdir);
|
||||
}
|
||||
EXPORT_SYMBOL(d_delete);
|
||||
|
||||
|
|
|
@ -617,13 +617,10 @@ struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(debugfs_create_symlink);
|
||||
|
||||
static void __debugfs_remove_file(struct dentry *dentry, struct dentry *parent)
|
||||
static void __debugfs_file_removed(struct dentry *dentry)
|
||||
{
|
||||
struct debugfs_fsdata *fsd;
|
||||
|
||||
simple_unlink(d_inode(parent), dentry);
|
||||
d_delete(dentry);
|
||||
|
||||
/*
|
||||
* Paired with the closing smp_mb() implied by a successful
|
||||
* cmpxchg() in debugfs_file_get(): either
|
||||
|
@ -644,16 +641,18 @@ static int __debugfs_remove(struct dentry *dentry, struct dentry *parent)
|
|||
|
||||
if (simple_positive(dentry)) {
|
||||
dget(dentry);
|
||||
if (!d_is_reg(dentry)) {
|
||||
if (d_is_dir(dentry))
|
||||
ret = simple_rmdir(d_inode(parent), dentry);
|
||||
else
|
||||
simple_unlink(d_inode(parent), dentry);
|
||||
if (d_is_dir(dentry)) {
|
||||
ret = simple_rmdir(d_inode(parent), dentry);
|
||||
if (!ret)
|
||||
d_delete(dentry);
|
||||
fsnotify_rmdir(d_inode(parent), dentry);
|
||||
} else {
|
||||
__debugfs_remove_file(dentry, parent);
|
||||
simple_unlink(d_inode(parent), dentry);
|
||||
fsnotify_unlink(d_inode(parent), dentry);
|
||||
}
|
||||
if (!ret)
|
||||
d_delete(dentry);
|
||||
if (d_is_reg(dentry))
|
||||
__debugfs_file_removed(dentry);
|
||||
dput(dentry);
|
||||
}
|
||||
return ret;
|
||||
|
|
|
@ -621,6 +621,7 @@ void devpts_pty_kill(struct dentry *dentry)
|
|||
|
||||
dentry->d_fsdata = NULL;
|
||||
drop_nlink(dentry->d_inode);
|
||||
fsnotify_unlink(d_inode(dentry->d_parent), dentry);
|
||||
d_delete(dentry);
|
||||
dput(dentry); /* d_alloc_name() in devpts_pty_new() */
|
||||
}
|
||||
|
|
|
@ -3883,6 +3883,7 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
|
|||
dentry->d_inode->i_flags |= S_DEAD;
|
||||
dont_mount(dentry);
|
||||
detach_mounts(dentry);
|
||||
fsnotify_rmdir(dir, dentry);
|
||||
|
||||
out:
|
||||
inode_unlock(dentry->d_inode);
|
||||
|
@ -3999,6 +4000,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegate
|
|||
if (!error) {
|
||||
dont_mount(dentry);
|
||||
detach_mounts(dentry);
|
||||
fsnotify_unlink(dir, dentry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -396,12 +396,6 @@ nfs_complete_sillyrename(struct rpc_task *task, struct nfs_renamedata *data)
|
|||
nfs_cancel_async_unlink(dentry);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* vfs_unlink and the like do not issue this when a file is
|
||||
* sillyrenamed, so do it here.
|
||||
*/
|
||||
fsnotify_nameremove(dentry, 0);
|
||||
}
|
||||
|
||||
#define SILLYNAME_PREFIX ".nfs"
|
||||
|
|
|
@ -920,6 +920,22 @@ static int fanotify_test_fid(struct path *path, __kernel_fsid_t *fsid)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int fanotify_events_supported(struct path *path, __u64 mask)
|
||||
{
|
||||
/*
|
||||
* Some filesystems such as 'proc' acquire unusual locks when opening
|
||||
* files. For them fanotify permission events have high chances of
|
||||
* deadlocking the system - open done when reporting fanotify event
|
||||
* blocks on this "unusual" lock while another process holding the lock
|
||||
* waits for fanotify permission event to be answered. Just disallow
|
||||
* permission events for such filesystems.
|
||||
*/
|
||||
if (mask & FANOTIFY_PERM_EVENTS &&
|
||||
path->mnt->mnt_sb->s_type->fs_flags & FS_DISALLOW_NOTIFY_PERM)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
|
||||
int dfd, const char __user *pathname)
|
||||
{
|
||||
|
@ -1018,6 +1034,12 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
|
|||
if (ret)
|
||||
goto fput_and_out;
|
||||
|
||||
if (flags & FAN_MARK_ADD) {
|
||||
ret = fanotify_events_supported(&path, mask);
|
||||
if (ret)
|
||||
goto path_put_and_out;
|
||||
}
|
||||
|
||||
if (FAN_GROUP_FLAG(group, FAN_REPORT_FID)) {
|
||||
ret = fanotify_test_fid(&path, &__fsid);
|
||||
if (ret)
|
||||
|
|
|
@ -94,47 +94,6 @@ void fsnotify_sb_delete(struct super_block *sb)
|
|||
fsnotify_clear_marks_by_sb(sb);
|
||||
}
|
||||
|
||||
/*
|
||||
* fsnotify_nameremove - a filename was removed from a directory
|
||||
*
|
||||
* This is mostly called under parent vfs inode lock so name and
|
||||
* dentry->d_parent should be stable. However there are some corner cases where
|
||||
* inode lock is not held. So to be on the safe side and be reselient to future
|
||||
* callers and out of tree users of d_delete(), we do not assume that d_parent
|
||||
* and d_name are stable and we use dget_parent() and
|
||||
* take_dentry_name_snapshot() to grab stable references.
|
||||
*/
|
||||
void fsnotify_nameremove(struct dentry *dentry, int isdir)
|
||||
{
|
||||
struct dentry *parent;
|
||||
struct name_snapshot name;
|
||||
__u32 mask = FS_DELETE;
|
||||
|
||||
/* d_delete() of pseudo inode? (e.g. __ns_get_path() playing tricks) */
|
||||
if (IS_ROOT(dentry))
|
||||
return;
|
||||
|
||||
if (isdir)
|
||||
mask |= FS_ISDIR;
|
||||
|
||||
parent = dget_parent(dentry);
|
||||
/* Avoid unneeded take_dentry_name_snapshot() */
|
||||
if (!(d_inode(parent)->i_fsnotify_mask & FS_DELETE) &&
|
||||
!(dentry->d_sb->s_fsnotify_mask & FS_DELETE))
|
||||
goto out_dput;
|
||||
|
||||
take_dentry_name_snapshot(&name, dentry);
|
||||
|
||||
fsnotify(d_inode(parent), mask, d_inode(dentry), FSNOTIFY_EVENT_INODE,
|
||||
&name.name, 0);
|
||||
|
||||
release_dentry_name_snapshot(&name);
|
||||
|
||||
out_dput:
|
||||
dput(parent);
|
||||
}
|
||||
EXPORT_SYMBOL(fsnotify_nameremove);
|
||||
|
||||
/*
|
||||
* Given an inode, first check if we care what happens to our children. Inotify
|
||||
* and dnotify both tell their parents about events. If we care about any event
|
||||
|
|
|
@ -211,7 +211,7 @@ static struct file_system_type proc_fs_type = {
|
|||
.init_fs_context = proc_init_fs_context,
|
||||
.parameters = &proc_fs_parameters,
|
||||
.kill_sb = proc_kill_sb,
|
||||
.fs_flags = FS_USERNS_MOUNT,
|
||||
.fs_flags = FS_USERNS_MOUNT | FS_DISALLOW_NOTIFY_PERM,
|
||||
};
|
||||
|
||||
void __init proc_root_init(void)
|
||||
|
|
|
@ -505,9 +505,12 @@ static int __tracefs_remove(struct dentry *dentry, struct dentry *parent)
|
|||
switch (dentry->d_inode->i_mode & S_IFMT) {
|
||||
case S_IFDIR:
|
||||
ret = simple_rmdir(parent->d_inode, dentry);
|
||||
if (!ret)
|
||||
fsnotify_rmdir(parent->d_inode, dentry);
|
||||
break;
|
||||
default:
|
||||
simple_unlink(parent->d_inode, dentry);
|
||||
fsnotify_unlink(parent->d_inode, dentry);
|
||||
break;
|
||||
}
|
||||
if (!ret)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
||||
fsnotify_dirent(dir, dentry, FS_DELETE);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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));
|
||||
|
||||
fsnotify_dirent(dir, dentry, FS_DELETE | FS_ISDIR);
|
||||
}
|
||||
|
||||
/*
|
||||
* fsnotify_access - file was read
|
||||
*/
|
||||
|
|
|
@ -357,7 +357,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)
|
||||
|
@ -527,9 +526,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)
|
||||
{}
|
||||
|
||||
|
|
|
@ -598,6 +598,8 @@ static int __rpc_rmdir(struct inode *dir, struct dentry *dentry)
|
|||
|
||||
dget(dentry);
|
||||
ret = simple_rmdir(dir, dentry);
|
||||
if (!ret)
|
||||
fsnotify_rmdir(dir, dentry);
|
||||
d_delete(dentry);
|
||||
dput(dentry);
|
||||
return ret;
|
||||
|
@ -609,6 +611,8 @@ static int __rpc_unlink(struct inode *dir, struct dentry *dentry)
|
|||
|
||||
dget(dentry);
|
||||
ret = simple_unlink(dir, dentry);
|
||||
if (!ret)
|
||||
fsnotify_unlink(dir, dentry);
|
||||
d_delete(dentry);
|
||||
dput(dentry);
|
||||
return ret;
|
||||
|
|
Loading…
Reference in New Issue