From: Greg Kroah-Hartman Date: Mon, 31 Jan 2022 10:37:38 +0000 (+0100) Subject: 5.4-stable patches X-Git-Tag: v5.4.176~11 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8da3c33b8af07c9db10ba3e8e41ddb1ca20386a3;p=thirdparty%2Fkernel%2Fstable-queue.git 5.4-stable patches added patches: block-fix-wrong-offset-in-bio_truncate.patch fsnotify-invalidate-dcache-before-in_delete-event.patch --- diff --git a/queue-5.4/block-fix-wrong-offset-in-bio_truncate.patch b/queue-5.4/block-fix-wrong-offset-in-bio_truncate.patch new file mode 100644 index 00000000000..ab59abfa444 --- /dev/null +++ b/queue-5.4/block-fix-wrong-offset-in-bio_truncate.patch @@ -0,0 +1,38 @@ +From 3ee859e384d453d6ac68bfd5971f630d9fa46ad3 Mon Sep 17 00:00:00 2001 +From: OGAWA Hirofumi +Date: Sun, 9 Jan 2022 18:36:43 +0900 +Subject: block: Fix wrong offset in bio_truncate() + +From: OGAWA Hirofumi + +commit 3ee859e384d453d6ac68bfd5971f630d9fa46ad3 upstream. + +bio_truncate() clears the buffer outside of last block of bdev, however +current bio_truncate() is using the wrong offset of page. So it can +return the uninitialized data. + +This happened when both of truncated/corrupted FS and userspace (via +bdev) are trying to read the last of bdev. + +Reported-by: syzbot+ac94ae5f68b84197f41c@syzkaller.appspotmail.com +Signed-off-by: OGAWA Hirofumi +Reviewed-by: Ming Lei +Link: https://lore.kernel.org/r/875yqt1c9g.fsf@mail.parknet.co.jp +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman +--- + block/bio.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/block/bio.c ++++ b/block/bio.c +@@ -569,7 +569,8 @@ void bio_truncate(struct bio *bio, unsig + offset = new_size - done; + else + offset = 0; +- zero_user(bv.bv_page, offset, bv.bv_len - offset); ++ zero_user(bv.bv_page, bv.bv_offset + offset, ++ bv.bv_len - offset); + truncated = true; + } + done += bv.bv_len; diff --git a/queue-5.4/fsnotify-invalidate-dcache-before-in_delete-event.patch b/queue-5.4/fsnotify-invalidate-dcache-before-in_delete-event.patch new file mode 100644 index 00000000000..27ce0a61127 --- /dev/null +++ b/queue-5.4/fsnotify-invalidate-dcache-before-in_delete-event.patch @@ -0,0 +1,173 @@ +From a37d9a17f099072fe4d3a9048b0321978707a918 Mon Sep 17 00:00:00 2001 +From: Amir Goldstein +Date: Thu, 20 Jan 2022 23:53:04 +0200 +Subject: fsnotify: invalidate dcache before IN_DELETE event + +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 +@@ -3027,10 +3027,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 +@@ -3878,13 +3878,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); +@@ -3995,7 +3994,6 @@ int vfs_unlink(struct inode *dir, struct + if (!error) { + dont_mount(dentry); + detach_mounts(dentry); +- fsnotify_unlink(dir, dentry); + } + } + } +@@ -4003,9 +4001,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 +@@ -189,16 +189,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(dir, mask, inode, FSNOTIFY_EVENT_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); + } + + /* +@@ -218,10 +254,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); + } + + /* diff --git a/queue-5.4/series b/queue-5.4/series index 9038fdcf511..1ecd29baeef 100644 --- a/queue-5.4/series +++ b/queue-5.4/series @@ -60,3 +60,5 @@ ipv4-raw-lock-the-socket-in-raw_bind.patch ipv4-tcp-send-zero-ipid-in-synack-messages.patch ipv4-remove-sparse-error-in-ip_neigh_gw4.patch dt-bindings-can-tcan4x5x-fix-mram-cfg-rx-fifo-config.patch +fsnotify-invalidate-dcache-before-in_delete-event.patch +block-fix-wrong-offset-in-bio_truncate.patch