From: Greg Kroah-Hartman Date: Wed, 30 Mar 2022 16:40:02 +0000 (+0200) Subject: 4.14-stable patches X-Git-Tag: v4.14.275~56 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=22c5ab23c41d6be4f0c57421ca72fdbc59b06831;p=thirdparty%2Fkernel%2Fstable-queue.git 4.14-stable patches added patches: fuse-fix-pipe-buffer-lifetime-for-direct_io.patch --- diff --git a/queue-4.14/fuse-fix-pipe-buffer-lifetime-for-direct_io.patch b/queue-4.14/fuse-fix-pipe-buffer-lifetime-for-direct_io.patch new file mode 100644 index 00000000000..33ef9d9ab61 --- /dev/null +++ b/queue-4.14/fuse-fix-pipe-buffer-lifetime-for-direct_io.patch @@ -0,0 +1,81 @@ +From 0c4bcfdecb1ac0967619ee7ff44871d93c08c909 Mon Sep 17 00:00:00 2001 +From: Miklos Szeredi +Date: Mon, 7 Mar 2022 16:30:44 +0100 +Subject: fuse: fix pipe buffer lifetime for direct_io + +From: Miklos Szeredi + +commit 0c4bcfdecb1ac0967619ee7ff44871d93c08c909 upstream. + +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 +Signed-off-by: Zach O'Keefe +Signed-off-by: Greg Kroah-Hartman +--- + fs/fuse/dev.c | 12 +++++++++++- + fs/fuse/file.c | 1 + + fs/fuse/fuse_i.h | 2 ++ + 3 files changed, 14 insertions(+), 1 deletion(-) + +--- a/fs/fuse/dev.c ++++ b/fs/fuse/dev.c +@@ -991,7 +991,17 @@ static int fuse_copy_page(struct fuse_co + + 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->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) { +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -1325,6 +1325,7 @@ static int fuse_get_user_pages(struct fu + (PAGE_SIZE - ret) & (PAGE_SIZE - 1); + } + ++ req->user_pages = true; + if (write) + req->in.argpages = 1; + else +--- a/fs/fuse/fuse_i.h ++++ b/fs/fuse/fuse_i.h +@@ -312,6 +312,8 @@ struct fuse_req { + /** refcount */ + refcount_t count; + ++ bool user_pages; ++ + /** Unique ID for the interrupt request */ + u64 intr_unique; + diff --git a/queue-4.14/series b/queue-4.14/series index 9a7065bc1c8..943579393aa 100644 --- a/queue-4.14/series +++ b/queue-4.14/series @@ -7,3 +7,4 @@ ethernet-sun-free-the-coherent-when-failing-in-probi.patch spi-fix-invalid-sgs-value.patch spi-fix-erroneous-sgs-value-with-min_t.patch af_key-add-__gfp_zero-flag-for-compose_sadb_supporte.patch +fuse-fix-pipe-buffer-lifetime-for-direct_io.patch