Re: WARNING: lock held when returning to user space in ovl_write_iter

From: Miklos Szeredi
Date: Thu Mar 12 2020 - 11:30:39 EST


#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
63623fd4
---
fs/overlayfs/file.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)

--- a/fs/overlayfs/file.c
+++ b/fs/overlayfs/file.c
@@ -243,7 +243,11 @@ static void ovl_aio_cleanup_handler(stru

if (iocb->ki_flags & IOCB_WRITE) {
struct inode *inode = file_inode(orig_iocb->ki_filp);
+ struct inode *real_inode = ovl_inode_real(inode);

+ WARN_ON(real_inode != file_inode(iocb->ki_filp));
+ /* See aio_complete_rw() */
+ __sb_writers_acquired(real_inode->i_sb, SB_FREEZE_WRITE);
file_end_write(iocb->ki_filp);
ovl_copyattr(ovl_inode_real(inode), inode);
}
@@ -311,6 +315,7 @@ static ssize_t ovl_write_iter(struct kio
{
struct file *file = iocb->ki_filp;
struct inode *inode = file_inode(file);
+ struct inode *real_inode = ovl_inode_real(inode);
struct fd real;
const struct cred *old_cred;
ssize_t ret;
@@ -320,7 +325,7 @@ static ssize_t ovl_write_iter(struct kio

inode_lock(inode);
/* Update mode */
- ovl_copyattr(ovl_inode_real(inode), inode);
+ ovl_copyattr(real_inode, inode);
ret = file_remove_privs(file);
if (ret)
goto out_unlock;
@@ -346,6 +351,9 @@ static ssize_t ovl_write_iter(struct kio
goto out;

file_start_write(real.file);
+ WARN_ON(real_inode != file_inode(real.file));
+ /* See aio_write() */
+ __sb_writers_release(real_inode->i_sb, SB_FREEZE_WRITE);
aio_req->fd = real;
real.flags = 0;
aio_req->orig_iocb = iocb;