]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 31 Jan 2022 10:37:38 +0000 (11:37 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 31 Jan 2022 10:37:38 +0000 (11:37 +0100)
added patches:
block-fix-wrong-offset-in-bio_truncate.patch
fsnotify-invalidate-dcache-before-in_delete-event.patch

queue-5.4/block-fix-wrong-offset-in-bio_truncate.patch [new file with mode: 0644]
queue-5.4/fsnotify-invalidate-dcache-before-in_delete-event.patch [new file with mode: 0644]
queue-5.4/series

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 (file)
index 0000000..ab59abf
--- /dev/null
@@ -0,0 +1,38 @@
+From 3ee859e384d453d6ac68bfd5971f630d9fa46ad3 Mon Sep 17 00:00:00 2001
+From: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
+Date: Sun, 9 Jan 2022 18:36:43 +0900
+Subject: block: Fix wrong offset in bio_truncate()
+
+From: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
+
+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 <hirofumi@mail.parknet.co.jp>
+Reviewed-by: Ming Lei <ming.lei@redhat.com>
+Link: https://lore.kernel.org/r/875yqt1c9g.fsf@mail.parknet.co.jp
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..27ce0a6
--- /dev/null
@@ -0,0 +1,173 @@
+From a37d9a17f099072fe4d3a9048b0321978707a918 Mon Sep 17 00:00:00 2001
+From: Amir Goldstein <amir73il@gmail.com>
+Date: Thu, 20 Jan 2022 23:53:04 +0200
+Subject: fsnotify: invalidate dcache before IN_DELETE event
+
+From: Amir Goldstein <amir73il@gmail.com>
+
+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 <colona@arista.com>
+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 <amir73il@gmail.com>
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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);
+ }
+ /*
index 9038fdcf511a526147d9c02751e6cc39c07ae59b..1ecd29baeef4570a7849586ffeee4c5459f9d013 100644 (file)
@@ -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