file->f_flags & O_APPEND is checked twice
-> do_splice_direct or do_splice: return EINVAL if O_APPEND enabled
   -> generic_write_checks: seek to end in case of O_APPEND
This is obviously whong and result in unpredictable behaviour if raced with
fcntl. It is reasonable to recheck append flag after kiocb was constructed (
f_flags becomes stable), for that reason we should use special analog of
vfs_write_iter()

Signed-off-by: Dmitry Monakhov <[email protected]>
---
 fs/splice.c |   23 ++++++++++++++++++++++-
 1 files changed, 22 insertions(+), 1 deletions(-)

diff --git a/fs/splice.c b/fs/splice.c
index 41cbb16..7ac43db 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -922,6 +922,27 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, 
struct file *out,
 
        return ret;
 }
+ssize_t splice_iter_write(struct file *file, struct iov_iter *iter, loff_t 
*ppos)
+{
+       struct kiocb kiocb;
+       ssize_t ret;
+
+       if (!file->f_op->write_iter)
+               return -EINVAL;
+
+       init_sync_kiocb(&kiocb, file);
+       if (is_append_kiocb(&kiocb))
+               return -EINVAL;
+
+       kiocb.ki_pos = *ppos;
+       iter->type |= WRITE;
+       ret = file->f_op->write_iter(&kiocb, iter);
+       BUG_ON(ret == -EIOCBQUEUED);
+       if (ret > 0)
+               *ppos = kiocb.ki_pos;
+       return ret;
+}
+
 
 /**
  * iter_file_splice_write - splice data from a pipe to a file
@@ -1005,7 +1026,7 @@ iter_file_splice_write(struct pipe_inode_info *pipe, 
struct file *out,
 
                iov_iter_bvec(&from, ITER_BVEC | WRITE, array, n,
                              sd.total_len - left);
-               ret = vfs_iter_write(out, &from, &sd.pos);
+               ret = splice_iter_write(out, &from, &sd.pos);
                if (ret <= 0)
                        break;
 
-- 
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to