Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752088AbbDLRJE (ORCPT ); Sun, 12 Apr 2015 13:09:04 -0400 Received: from mailhub.sw.ru ([195.214.232.25]:7678 "EHLO relay.sw.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751680AbbDLRIl (ORCPT ); Sun, 12 Apr 2015 13:08:41 -0400 From: Dmitry Monakhov To: linux-kernel@vger.kernel.org, viro@zeniv.linux.org.uk Cc: linux-fsdevel@vger.kernel.org, Dmitry Monakhov Subject: [PATCH 2/2] splice: fix race beween splice_write vs fcntl Date: Sun, 12 Apr 2015 21:08:22 +0400 Message-Id: <1428858502-5371-3-git-send-email-dmonakhov@openvz.org> X-Mailer: git-send-email 1.9.3 In-Reply-To: <1428858502-5371-1-git-send-email-dmonakhov@openvz.org> References: <1428858502-5371-1-git-send-email-dmonakhov@openvz.org> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 1906 Lines: 62 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 (where ->ki_flags is stable), for that reason we should use special analog of vfs_write_iter() which asserts non-append behaviour. Signed-off-by: Dmitry Monakhov --- fs/splice.c | 23 ++++++++++++++++++++++- 1 files changed, 22 insertions(+), 1 deletions(-) diff --git a/fs/splice.c b/fs/splice.c index 41cbb16..d49615d 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 (kiocb.ki_flags & IOCB_APPEND) + 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 majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/