On Tue, Jan 18, 2022 at 2:00 PM Amir Goldstein <amir73il@xxxxxxxxx> wrote: > > Apparently, there are some applications that use IN_DELETE event as an > invalidation mechanism and expect that if they try to open a file with > the name reported with the delete event, that it should not contain the > content of the deleted file. > > Commit 49246466a989 ("fsnotify: move fsnotify_nameremove() hook out of > d_delete()") moved the fsnotify delete hook before d_delete() so fsnotify > will have access to a positive dentry. > > This allowed a race where opening the deleted file via cached dentry > is now possible after receiving the IN_DELETE event. > > To fix the regression, we use two different techniques: > 1) For call sites that call d_delete() with elevated refcount, convert > the call to d_drop() and move the fsnotify hook after d_drop(). > 2) For the vfs helpers that may turn dentry to negative on d_delete(), > use a helper d_delete_notify() to pin the inode, so we can pass it > to an fsnotify hook after d_delete(). > > Create a new hook fsnotify_delete() that allows to pass a negative > dentry and takes the unlinked inode as an argument. > > Add a missing fsnotify_unlink() hook in nfsdfs that was found during > the call sites audit. > > Note that the call sites in simple_recursive_removal() follow > d_invalidate(), so they require no change. > > Backporting hint: this regression is from v5.3. Although patch will > apply with only trivial conflicts to v5.4 and v5.10, it won't build, > because fsnotify_delete() implementation is different in each of those > versions (see fsnotify_link()). > > Reported-by: Ivan Delalande <colona@xxxxxxxxxx> > Link: https://lore.kernel.org/linux-fsdevel/YeNyzoDM5hP5LtGW@visor/ > Fixes: 49246466a989 ("fsnotify: move fsnotify_nameremove() hook out of d_delete()") > Cc: stable@xxxxxxxxxxxxxxx # v5.3+ > Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx> > --- > > Jan, > > This turned into an audit of fsnotify_unlink/rmdir() call sites, so > besides fixing the regression, I also added one missing hook and replaced > most of the d_delete() calls with d_drop() to simplify things. > > I will follow up with backports for v5.4 and v5.10 and will send the > repro to LTP guys. > > Thanks, > Amir. > > fs/btrfs/ioctl.c | 5 ++--- > fs/configfs/dir.c | 6 +++--- > fs/devpts/inode.c | 2 +- > fs/namei.c | 27 ++++++++++++++++++++++----- > fs/nfsd/nfsctl.c | 5 +++-- > include/linux/fsnotify.h | 20 ++++++++++++++++++++ > net/sunrpc/rpc_pipe.c | 4 ++-- > 7 files changed, 53 insertions(+), 16 deletions(-) > > diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c > index edfecfe62b4b..121e8f439996 100644 > --- a/fs/btrfs/ioctl.c > +++ b/fs/btrfs/ioctl.c > @@ -3060,10 +3060,9 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, > btrfs_inode_lock(inode, 0); > err = btrfs_delete_subvolume(dir, dentry); > btrfs_inode_unlock(inode, 0); > - if (!err) { > + d_drop(dentry); > + if (!err) > fsnotify_rmdir(dir, dentry); > - d_delete(dentry); > - } > oops that an unintentional logic change. Was supposed to be: if (!err) { + d_drop(dentry); fsnotify_rmdir(dir, dentry); - d_delete(dentry); } Anyway, fix is pushed to fsnotify-fixes branch. Thanks, Amir.