summaryrefslogtreecommitdiffstats
path: root/fs/fuse
diff options
context:
space:
mode:
authorMatthew Wilcox <willy@infradead.org>2019-04-05 14:02:10 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-05-04 09:20:11 +0200
commit0311ff82b70fa12e80d188635bff24029ec06ae1 (patch)
treef8434ac298b7ab6be99e9851df019b9d2436ba43 /fs/fuse
parentd972ebbf42ba6712460308ae57c222a0706f2af3 (diff)
downloadlinux-stable-0311ff82b70fa12e80d188635bff24029ec06ae1.tar.gz
linux-stable-0311ff82b70fa12e80d188635bff24029ec06ae1.tar.bz2
linux-stable-0311ff82b70fa12e80d188635bff24029ec06ae1.zip
fs: prevent page refcount overflow in pipe_buf_get
commit 15fab63e1e57be9fdb5eec1bbc5916e9825e9acb upstream. Change pipe_buf_get() to return a bool indicating whether it succeeded in raising the refcount of the page (if the thing in the pipe is a page). This removes another mechanism for overflowing the page refcount. All callers converted to handle a failure. Reported-by: Jann Horn <jannh@google.com> Signed-off-by: Matthew Wilcox <willy@infradead.org> Cc: stable@kernel.org Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/fuse')
-rw-r--r--fs/fuse/dev.c12
1 files changed, 6 insertions, 6 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index baaed4d05b22..249de20f752a 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1989,10 +1989,8 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
rem += pipe->bufs[(pipe->curbuf + idx) & (pipe->buffers - 1)].len;
ret = -EINVAL;
- if (rem < len) {
- pipe_unlock(pipe);
- goto out;
- }
+ if (rem < len)
+ goto out_free;
rem = len;
while (rem) {
@@ -2010,7 +2008,9 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
pipe->curbuf = (pipe->curbuf + 1) & (pipe->buffers - 1);
pipe->nrbufs--;
} else {
- pipe_buf_get(pipe, ibuf);
+ if (!pipe_buf_get(pipe, ibuf))
+ goto out_free;
+
*obuf = *ibuf;
obuf->flags &= ~PIPE_BUF_FLAG_GIFT;
obuf->len = rem;
@@ -2033,11 +2033,11 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
ret = fuse_dev_do_write(fud, &cs, len);
pipe_lock(pipe);
+out_free:
for (idx = 0; idx < nbuf; idx++)
pipe_buf_release(pipe, &bufs[idx]);
pipe_unlock(pipe);
-out:
kvfree(bufs);
return ret;
}