From: Greg Kroah-Hartman Date: Fri, 3 Dec 2021 10:32:41 +0000 (+0100) Subject: 5.10-stable patches X-Git-Tag: v4.4.294~58 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6c2198f9990ed03efe9ec8ea5f49f28c976719c9;p=thirdparty%2Fkernel%2Fstable-queue.git 5.10-stable patches added patches: ovl-fix-deadlock-in-splice-write.patch ovl-simplify-file-splice.patch --- 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 index 00000000000..1c27eb080db --- /dev/null +++ b/queue-5.10/ovl-fix-deadlock-in-splice-write.patch @@ -0,0 +1,105 @@ +From 9b91b6b019fda817eb52f728eb9c79b3579760bc Mon Sep 17 00:00:00 2001 +From: Miklos Szeredi +Date: Wed, 28 Jul 2021 10:38:43 +0200 +Subject: ovl: fix deadlock in splice write + +From: Miklos Szeredi + +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 +Cc: Stan Hu +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..d1953dd2bf2 --- /dev/null +++ b/queue-5.10/ovl-simplify-file-splice.patch @@ -0,0 +1,89 @@ +From 82a763e61e2b601309d696d4fa514c77d64ee1be Mon Sep 17 00:00:00 2001 +From: Miklos Szeredi +Date: Mon, 14 Dec 2020 15:26:14 +0100 +Subject: ovl: simplify file splice + +From: Miklos Szeredi + +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 +Cc: Stan Hu +Signed-off-by: Greg Kroah-Hartman +--- + 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, diff --git a/queue-5.10/series b/queue-5.10/series index d7633f3f64f..7c42bc2cad2 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -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