From a21fd3549af9e9a60c08315507f74fc5fa604b06 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 21 Mar 2022 09:37:30 +0000 Subject: [PATCH 1/2] fuse: fix pipe buffer lifetime for direct_io Signed-off-by: wufan ----------------------------------------------- mainline inclusion from mainline-v5.17-rc8 commit 0c4bcfdecb1ac0967619ee7ff44871d93c08c909 category: bugfix bugzilla: 186448, https://gitee.com/openeuler/kernel/issues/I4YORE CVE: CVE-2022-1011 -------------------------------- In FOPEN_DIRECT_IO mode, fuse_file_write_iter() calls fuse_direct_write_iter(), which normally calls fuse_direct_io(), which then imports the write buffer with fuse_get_user_pages(), which uses iov_iter_get_pages() to grab references to userspace pages instead of actually copying memory. On the filesystem device side, these pages can then either be read to userspace (via fuse_dev_read()), or splice()d over into a pipe using fuse_dev_splice_read() as pipe buffers with &nosteal_pipe_buf_ops. This is wrong because after fuse_dev_do_read() unlocks the FUSE request, the userspace filesystem can mark the request as completed, causing write() to return. At that point, the userspace filesystem should no longer have access to the pipe buffer. Fix by copying pages coming from the user address space to new pipe buffers. Reported-by: Jann Horn Fixes: c3021629a0d8 ("fuse: support splice() reading from fuse device") Cc: Signed-off-by: Miklos Szeredi Conflicts: fs/fuse/file.c fs/fuse/fuse_i.h Signed-off-by: Zhang Wensheng Reviewed-by: Tao Hou Reviewed-by: Xiu Jianfeng Signed-off-by: Yongqiang Liu --- fs/fuse/dev.c | 12 +++++++++++- fs/fuse/file.c | 6 ++++-- fs/fuse/fuse_i.h | 3 +++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 1ff5a6b21db0..0ff26588335e 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -993,7 +993,17 @@ static int fuse_copy_page(struct fuse_copy_state *cs, struct page **pagep, while (count) { if (cs->write && cs->pipebufs && page) { - return fuse_ref_page(cs, page, offset, count); + /* + * Can't control lifetime of pipe buffers, so always + * copy user pages. + */ + if (cs->req->in.user_pages) { + err = fuse_copy_fill(cs); + if (err) + return err; + } else { + return fuse_ref_page(cs, page, offset, count); + } } else if (!cs->len) { if (cs->move_pages && page && offset == 0 && count == PAGE_SIZE) { diff --git a/fs/fuse/file.c b/fs/fuse/file.c index c1af038920dc..d90d91232dfe 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1320,10 +1320,12 @@ static int fuse_get_user_pages(struct fuse_req *req, struct iov_iter *ii, (PAGE_SIZE - ret) & (PAGE_SIZE - 1); } - if (write) + if (write) { + req->in.user_pages = 1; req->in.argpages = 1; - else + } else { req->out.argpages = 1; + } *nbytesp = nbytes; diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 853d37ec81e0..27f3b6d4f11c 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -174,6 +174,9 @@ struct fuse_in { /** True if the data for the last argument is in req->pages */ unsigned argpages:1; + /** True if direct write */ + unsigned user_pages:1; + /** Number of arguments */ unsigned numargs; -- Gitee From 458d03461829d684754306085b1829ac448eb516 Mon Sep 17 00:00:00 2001 From: Zhang Wensheng Date: Mon, 21 Mar 2022 09:37:31 +0000 Subject: [PATCH 2/2] kabi: fix kabi broken in struct fuse_in Signed-off-by: wufan ----------------------------------------------- mainline inclusion from mainline-v5.17-rc8 commit 0c4bcfdecb1ac0967619ee7ff44871d93c08c909 category: bugfix bugzilla: 186448, https://gitee.com/openeuler/kernel/issues/I4YORE CVE: CVE-2022-1011 -------------------------------- Because create a new user_pages in fuse_in, to fix kabi change. Signed-off-by: Zhang Wensheng Reviewed-by: Tao Hou Reviewed-by: Xiu Jianfeng Signed-off-by: Yongqiang Liu --- fs/fuse/fuse_i.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 27f3b6d4f11c..0981011c10c6 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -174,8 +174,10 @@ struct fuse_in { /** True if the data for the last argument is in req->pages */ unsigned argpages:1; +#ifndef __GENKSYMS__ /** True if direct write */ unsigned user_pages:1; +#endif /** Number of arguments */ unsigned numargs; -- Gitee