diff options
author | Jann Horn <jannh@google.com> | 2019-01-23 15:19:17 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2019-03-23 20:09:59 +0100 |
commit | 2af926fd52fc287a92fc782ce074f349d86966aa (patch) | |
tree | 0d57a0d79c7b30cc3602b66b21ee8b9879e2ee42 /fs/splice.c | |
parent | 1c2123ff43122bb9e0578198391ee3cf752049d6 (diff) | |
download | linux-stable-2af926fd52fc287a92fc782ce074f349d86966aa.tar.gz linux-stable-2af926fd52fc287a92fc782ce074f349d86966aa.tar.bz2 linux-stable-2af926fd52fc287a92fc782ce074f349d86966aa.zip |
splice: don't merge into linked buffers
commit a0ce2f0aa6ad97c3d4927bf2ca54bcebdf062d55 upstream.
Before this patch, it was possible for two pipes to affect each other after
data had been transferred between them with tee():
============
$ cat tee_test.c
int main(void) {
int pipe_a[2];
if (pipe(pipe_a)) err(1, "pipe");
int pipe_b[2];
if (pipe(pipe_b)) err(1, "pipe");
if (write(pipe_a[1], "abcd", 4) != 4) err(1, "write");
if (tee(pipe_a[0], pipe_b[1], 2, 0) != 2) err(1, "tee");
if (write(pipe_b[1], "xx", 2) != 2) err(1, "write");
char buf[5];
if (read(pipe_a[0], buf, 4) != 4) err(1, "read");
buf[4] = 0;
printf("got back: '%s'\n", buf);
}
$ gcc -o tee_test tee_test.c
$ ./tee_test
got back: 'abxx'
$
============
As suggested by Al Viro, fix it by creating a separate type for
non-mergeable pipe buffers, then changing the types of buffers in
splice_pipe_to_pipe() and link_pipe().
Cc: <stable@vger.kernel.org>
Fixes: 7c77f0b3f920 ("splice: implement pipe to pipe splicing")
Fixes: 70524490ee2e ("[PATCH] splice: add support for sys_tee()")
Suggested-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/splice.c')
-rw-r--r-- | fs/splice.c | 4 |
1 files changed, 4 insertions, 0 deletions
diff --git a/fs/splice.c b/fs/splice.c index b3daa971f597..29e92b506394 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -1593,6 +1593,8 @@ retry: */ obuf->flags &= ~PIPE_BUF_FLAG_GIFT; + pipe_buf_mark_unmergeable(obuf); + obuf->len = len; opipe->nrbufs++; ibuf->offset += obuf->len; @@ -1667,6 +1669,8 @@ static int link_pipe(struct pipe_inode_info *ipipe, */ obuf->flags &= ~PIPE_BUF_FLAG_GIFT; + pipe_buf_mark_unmergeable(obuf); + if (obuf->len > len) obuf->len = len; |