Received: by 2002:a05:6a10:1a4d:0:0:0:0 with SMTP id nk13csp867564pxb; Tue, 1 Feb 2022 12:04:44 -0800 (PST) X-Google-Smtp-Source: ABdhPJwaXq5gmvxtuptC/GVjVFpFLk4uHduu9cKudUxoaBT4xKuijEoMk6RkGk4gG0Psp7I7V4nD X-Received: by 2002:a17:902:ed44:: with SMTP id y4mr27949384plb.152.1643745884189; Tue, 01 Feb 2022 12:04:44 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1643745884; cv=none; d=google.com; s=arc-20160816; b=DBclIuHvTlQuNwAO9wVIHHFTxy2ViO4IrMpm0W5jYo07I4On/XBiuNHkEFZRS0qHrw jg6khbgf88LHWFLzskXJvoJOZJz5jXYfd5n+/uh99phPeqtr/tpGEo0Bba2sebz23S+l N/ZZw+ms6avNcaXmZGz0ad4AAFo1xrhH2YujpSXggwM5hhYyYZeyTeNYwYpBnP752Kp8 5JiO0FdgdoLDmveGN1tns/O2uHamRi65VKan4wcW7m2w8ygTTdjyfq0ViT4MhEw+070a AIDleQSlYYKWreiLEuxP8jnO2zYPHhWL0HYpRjm4wVwI/Es8MKLEAEJBmW3N0nbEaDyo Nb/w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=oN6XVigybkTR5puyqQf3oJ6uIgvYs0vr6oC/xwyEVdg=; b=agZOaoDmUvyW92+PaebNOQDjLCAQqmAEXzbORWZIWj4fX1ryWgJvY5VNRzoP01zicR iDhVVNMCWlgu/6OJHRqsT1Lzo6tfZSlPym8mQ3J7M/QO0qqG7Gz/jvf4BPygIr7SSZaJ 30dOMYSx7yAj7J68vvaBbza1R0erWkEM4w0rGEefWC5bImKbMwxEPYRlMEjhszIaX/P6 fVTvI/oZqXxfSw0jLjQd9PmexvcQLyezHvAnwwXQWkFOjRg+tfOLF3Lph9NE99aNQ7s8 Ilr8CaHggapJqzpFWZlghAPxsEcS4iBlbUWWOtPd4r57yJYggYkDs7EK0NbXoWaeYDKx mOPw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=lFiMa59K; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id q6si18485744plx.134.2022.02.01.12.04.32; Tue, 01 Feb 2022 12:04:44 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=lFiMa59K; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231809AbiAaLQr (ORCPT + 99 others); Mon, 31 Jan 2022 06:16:47 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44856 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1377130AbiAaLJn (ORCPT ); Mon, 31 Jan 2022 06:09:43 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 25FF6C0604C5; Mon, 31 Jan 2022 03:06:23 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id C3DD5B82A65; Mon, 31 Jan 2022 11:06:22 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 16B7FC340EE; Mon, 31 Jan 2022 11:06:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1643627181; bh=xpJRa1/Hqa4J8TOwr9A3cijO2CHMQKV430HfQznfbS0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=lFiMa59K9cxN/pzfLs6G1UMLaDL04NRpdofAdrj6sH5rjIu+twCTQ7s+u02C3ZooX d0Eiar52KAg86LHIHX+yFnH+D376HIk+yWMYbnK6T6yWz8RGN/ws6mKrop5QGkEo43 qb8I8nMed92rTGUPTSA1I8LwUNig8fC5Yhw1nF7U= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Ivan Delalande , Amir Goldstein , Jan Kara Subject: [PATCH 5.10 099/100] fsnotify: invalidate dcache before IN_DELETE event Date: Mon, 31 Jan 2022 11:57:00 +0100 Message-Id: <20220131105223.775234099@linuxfoundation.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220131105220.424085452@linuxfoundation.org> References: <20220131105220.424085452@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Amir Goldstein commit a37d9a17f099072fe4d3a9048b0321978707a918 upstream. 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, create a new hook fsnotify_delete() that takes the unlinked inode as an argument and use a helper d_delete_notify() to pin the inode, so we can pass it to fsnotify_delete() after d_delete(). 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()). A follow up patch will fix the fsnotify_unlink/rmdir() calls in pseudo filesystem that do not need to call d_delete(). Link: https://lore.kernel.org/r/20220120215305.282577-1-amir73il@gmail.com Reported-by: Ivan Delalande Link: https://lore.kernel.org/linux-fsdevel/YeNyzoDM5hP5LtGW@visor/ Fixes: 49246466a989 ("fsnotify: move fsnotify_nameremove() hook out of d_delete()") Cc: stable@vger.kernel.org # v5.3+ Signed-off-by: Amir Goldstein Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/ioctl.c | 6 +---- fs/namei.c | 10 ++++----- include/linux/fsnotify.h | 48 +++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 49 insertions(+), 15 deletions(-) --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -3103,10 +3103,8 @@ static noinline int btrfs_ioctl_snap_des inode_lock(inode); err = btrfs_delete_subvolume(dir, dentry); inode_unlock(inode); - if (!err) { - fsnotify_rmdir(dir, dentry); - d_delete(dentry); - } + if (!err) + d_delete_notify(dir, dentry); out_dput: dput(dentry); --- a/fs/namei.c +++ b/fs/namei.c @@ -3709,13 +3709,12 @@ int vfs_rmdir(struct inode *dir, struct dentry->d_inode->i_flags |= S_DEAD; dont_mount(dentry); detach_mounts(dentry); - fsnotify_rmdir(dir, dentry); out: inode_unlock(dentry->d_inode); dput(dentry); if (!error) - d_delete(dentry); + d_delete_notify(dir, dentry); return error; } EXPORT_SYMBOL(vfs_rmdir); @@ -3825,7 +3824,6 @@ int vfs_unlink(struct inode *dir, struct if (!error) { dont_mount(dentry); detach_mounts(dentry); - fsnotify_unlink(dir, dentry); } } } @@ -3833,9 +3831,11 @@ out: inode_unlock(target); /* We don't d_delete() NFS sillyrenamed files--they still exist. */ - if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) { + if (!error && dentry->d_flags & DCACHE_NFSFS_RENAMED) { + fsnotify_unlink(dir, dentry); + } else if (!error) { fsnotify_link_count(target); - d_delete(dentry); + d_delete_notify(dir, dentry); } return error; --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -204,16 +204,52 @@ static inline void fsnotify_link(struct } /* + * fsnotify_delete - @dentry was unlinked and unhashed + * + * Caller must make sure that dentry->d_name is stable. + * + * Note: unlike fsnotify_unlink(), we have to pass also the unlinked inode + * as this may be called after d_delete() and old_dentry may be negative. + */ +static inline void fsnotify_delete(struct inode *dir, struct inode *inode, + struct dentry *dentry) +{ + __u32 mask = FS_DELETE; + + if (S_ISDIR(inode->i_mode)) + mask |= FS_ISDIR; + + fsnotify_name(dir, mask, inode, &dentry->d_name, 0); +} + +/** + * d_delete_notify - delete a dentry and call fsnotify_delete() + * @dentry: The dentry to delete + * + * This helper is used to guaranty that the unlinked inode cannot be found + * by lookup of this name after fsnotify_delete() event has been delivered. + */ +static inline void d_delete_notify(struct inode *dir, struct dentry *dentry) +{ + struct inode *inode = d_inode(dentry); + + ihold(inode); + d_delete(dentry); + fsnotify_delete(dir, inode, dentry); + iput(inode); +} + +/* * 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)); + if (WARN_ON_ONCE(d_is_negative(dentry))) + return; - fsnotify_dirent(dir, dentry, FS_DELETE); + fsnotify_delete(dir, d_inode(dentry), dentry); } /* @@ -233,10 +269,10 @@ static inline void fsnotify_mkdir(struct */ 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)); + if (WARN_ON_ONCE(d_is_negative(dentry))) + return; - fsnotify_dirent(dir, dentry, FS_DELETE | FS_ISDIR); + fsnotify_delete(dir, d_inode(dentry), dentry); } /*