]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 3 Dec 2021 10:32:41 +0000 (11:32 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 3 Dec 2021 10:32:41 +0000 (11:32 +0100)
added patches:
ovl-fix-deadlock-in-splice-write.patch
ovl-simplify-file-splice.patch

queue-5.10/ovl-fix-deadlock-in-splice-write.patch [new file with mode: 0644]
queue-5.10/ovl-simplify-file-splice.patch [new file with mode: 0644]
queue-5.10/series

diff --git a/queue-5.10/ovl-fix-deadlock-in-splice-write.patch b/queue-5.10/ovl-fix-deadlock-in-splice-write.patch
new file mode 100644 (file)
index 0000000..1c27eb0
--- /dev/null
@@ -0,0 +1,105 @@
+From 9b91b6b019fda817eb52f728eb9c79b3579760bc Mon Sep 17 00:00:00 2001
+From: Miklos Szeredi <mszeredi@redhat.com>
+Date: Wed, 28 Jul 2021 10:38:43 +0200
+Subject: ovl: fix deadlock in splice write
+
+From: Miklos Szeredi <mszeredi@redhat.com>
+
+commit 9b91b6b019fda817eb52f728eb9c79b3579760bc upstream.
+
+There's possibility of an ABBA deadlock in case of a splice write to an
+overlayfs file and a concurrent splice write to a corresponding real file.
+
+The call chain for splice to an overlay file:
+
+ -> do_splice                     [takes sb_writers on overlay file]
+   -> do_splice_from
+     -> iter_file_splice_write    [takes pipe->mutex]
+       -> vfs_iter_write
+         ...
+         -> ovl_write_iter        [takes sb_writers on real file]
+
+And the call chain for splice to a real file:
+
+ -> do_splice                     [takes sb_writers on real file]
+   -> do_splice_from
+     -> iter_file_splice_write    [takes pipe->mutex]
+
+Syzbot successfully bisected this to commit 82a763e61e2b ("ovl: simplify
+file splice").
+
+Fix by reverting the write part of the above commit and by adding missing
+bits from ovl_write_iter() into ovl_splice_write().
+
+Fixes: 82a763e61e2b ("ovl: simplify file splice")
+Reported-and-tested-by: syzbot+579885d1a9a833336209@syzkaller.appspotmail.com
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Cc: Stan Hu <stanhu@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/overlayfs/file.c |   47 ++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 46 insertions(+), 1 deletion(-)
+
+--- a/fs/overlayfs/file.c
++++ b/fs/overlayfs/file.c
+@@ -422,6 +422,51 @@ out_unlock:
+       return ret;
+ }
++/*
++ * Calling iter_file_splice_write() directly from overlay's f_op may deadlock
++ * due to lock order inversion between pipe->mutex in iter_file_splice_write()
++ * and file_start_write(real.file) in ovl_write_iter().
++ *
++ * So do everything ovl_write_iter() does and call iter_file_splice_write() on
++ * the real file.
++ */
++static ssize_t ovl_splice_write(struct pipe_inode_info *pipe, struct file *out,
++                              loff_t *ppos, size_t len, unsigned int flags)
++{
++      struct fd real;
++      const struct cred *old_cred;
++      struct inode *inode = file_inode(out);
++      struct inode *realinode = ovl_inode_real(inode);
++      ssize_t ret;
++
++      inode_lock(inode);
++      /* Update mode */
++      ovl_copyattr(realinode, inode);
++      ret = file_remove_privs(out);
++      if (ret)
++              goto out_unlock;
++
++      ret = ovl_real_fdget(out, &real);
++      if (ret)
++              goto out_unlock;
++
++      old_cred = ovl_override_creds(inode->i_sb);
++      file_start_write(real.file);
++
++      ret = iter_file_splice_write(pipe, real.file, ppos, len, flags);
++
++      file_end_write(real.file);
++      /* Update size */
++      ovl_copyattr(realinode, inode);
++      revert_creds(old_cred);
++      fdput(real);
++
++out_unlock:
++      inode_unlock(inode);
++
++      return ret;
++}
++
+ static int ovl_fsync(struct file *file, loff_t start, loff_t end, int datasync)
+ {
+       struct fd real;
+@@ -731,7 +776,7 @@ const struct file_operations ovl_file_op
+       .compat_ioctl   = ovl_compat_ioctl,
+ #endif
+       .splice_read    = generic_file_splice_read,
+-      .splice_write   = iter_file_splice_write,
++      .splice_write   = ovl_splice_write,
+       .copy_file_range        = ovl_copy_file_range,
+       .remap_file_range       = ovl_remap_file_range,
diff --git a/queue-5.10/ovl-simplify-file-splice.patch b/queue-5.10/ovl-simplify-file-splice.patch
new file mode 100644 (file)
index 0000000..d1953dd
--- /dev/null
@@ -0,0 +1,89 @@
+From 82a763e61e2b601309d696d4fa514c77d64ee1be Mon Sep 17 00:00:00 2001
+From: Miklos Szeredi <mszeredi@redhat.com>
+Date: Mon, 14 Dec 2020 15:26:14 +0100
+Subject: ovl: simplify file splice
+
+From: Miklos Szeredi <mszeredi@redhat.com>
+
+commit 82a763e61e2b601309d696d4fa514c77d64ee1be upstream.
+
+generic_file_splice_read() and iter_file_splice_write() will call back into
+f_op->iter_read() and f_op->iter_write() respectively.  These already do
+the real file lookup and cred override.  So the code in ovl_splice_read()
+and ovl_splice_write() is redundant.
+
+In addition the ovl_file_accessed() call in ovl_splice_write() is
+incorrect, though probably harmless.
+
+Fix by calling generic_file_splice_read() and iter_file_splice_write()
+directly.
+
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Cc: Stan Hu <stanhu@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/overlayfs/file.c |   46 ++--------------------------------------------
+ 1 file changed, 2 insertions(+), 44 deletions(-)
+
+--- a/fs/overlayfs/file.c
++++ b/fs/overlayfs/file.c
+@@ -422,48 +422,6 @@ out_unlock:
+       return ret;
+ }
+-static ssize_t ovl_splice_read(struct file *in, loff_t *ppos,
+-                       struct pipe_inode_info *pipe, size_t len,
+-                       unsigned int flags)
+-{
+-      ssize_t ret;
+-      struct fd real;
+-      const struct cred *old_cred;
+-
+-      ret = ovl_real_fdget(in, &real);
+-      if (ret)
+-              return ret;
+-
+-      old_cred = ovl_override_creds(file_inode(in)->i_sb);
+-      ret = generic_file_splice_read(real.file, ppos, pipe, len, flags);
+-      revert_creds(old_cred);
+-
+-      ovl_file_accessed(in);
+-      fdput(real);
+-      return ret;
+-}
+-
+-static ssize_t
+-ovl_splice_write(struct pipe_inode_info *pipe, struct file *out,
+-                        loff_t *ppos, size_t len, unsigned int flags)
+-{
+-      struct fd real;
+-      const struct cred *old_cred;
+-      ssize_t ret;
+-
+-      ret = ovl_real_fdget(out, &real);
+-      if (ret)
+-              return ret;
+-
+-      old_cred = ovl_override_creds(file_inode(out)->i_sb);
+-      ret = iter_file_splice_write(pipe, real.file, ppos, len, flags);
+-      revert_creds(old_cred);
+-
+-      ovl_file_accessed(out);
+-      fdput(real);
+-      return ret;
+-}
+-
+ static int ovl_fsync(struct file *file, loff_t start, loff_t end, int datasync)
+ {
+       struct fd real;
+@@ -772,8 +730,8 @@ const struct file_operations ovl_file_op
+ #ifdef CONFIG_COMPAT
+       .compat_ioctl   = ovl_compat_ioctl,
+ #endif
+-      .splice_read    = ovl_splice_read,
+-      .splice_write   = ovl_splice_write,
++      .splice_read    = generic_file_splice_read,
++      .splice_write   = iter_file_splice_write,
+       .copy_file_range        = ovl_copy_file_range,
+       .remap_file_range       = ovl_remap_file_range,
index d7633f3f64f5845d3261202e49b84ca8c2c2f13b..7c42bc2cad2da1ce4aa100f9557d76134d4c474d 100644 (file)
@@ -1,2 +1,4 @@
 nfsv42-fix-pagecache-invalidation-after-copy-clone.patch
 can-j1939-j1939_tp_cmd_recv-check-the-dst-address-of-tp.cm_bam.patch
+ovl-simplify-file-splice.patch
+ovl-fix-deadlock-in-splice-write.patch