Re: [PATCH 5.15 056/917] fuse: fix page stealing

Miklos Szeredi
2021-11-23T19:22:49Z

[-- Attachment #1: Type: text/plain, Size: 2000 bytes --]

On Tue, Nov 23, 2021 at 7:29 PM Justin Forbes <jmforbes@linuxtx.org> wrote:
>
> On Mon, Nov 15, 2021 at 7:04 PM Greg Kroah-Hartman
> <gregkh@linuxfoundation.org> wrote:
> >
> > From: Miklos Szeredi <mszeredi@redhat.com>
> >
> > commit 712a951025c0667ff00b25afc360f74e639dfabe upstream.
> >
> > It is possible to trigger a crash by splicing anon pipe bufs to the fuse
> > device.
> >
> > The reason for this is that anon_pipe_buf_release() will reuse buf->page if
> > the refcount is 1, but that page might have already been stolen and its
> > flags modified (e.g. PG_lru added).
> >
> > This happens in the unlikely case of fuse_dev_splice_write() getting around
> > to calling pipe_buf_release() after a page has been stolen, added to the
> > page cache and removed from the page cache.
> >
> > Fix by calling pipe_buf_release() right after the page was inserted into
> > the page cache. In this case the page has an elevated refcount so any
> > release function will know that the page isn't reusable.
> >
> > Reported-by: Frank Dinoff <fdinoff@google.com>
> > Link: https://lore.kernel.org/r/CAAmZXrsGg2xsP1CK+cbuEMumtrqdvD-NKnWzhNcvn71RV3c1yw@mail.gmail.com/
> > Fixes: dd3bb14f44a6 ("fuse: support splice() writing to fuse device")
> > Cc: <stable@vger.kernel.org> # v2.6.35
> > Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
> > Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>
> It appears this patch causes a rather serious regression in flatpacks
> using portals to access files. Reverting this patch restores expected
> behavior. I have asked users in the Fedora bug to test with 5.16-rc2
> to see if we are just missing a dependent patch in stable, or if this
> is broken there as well, but no response yet.:
>
> https://bugzilla.redhat.com/show_bug.cgi?id=2025285
> https://github.com/flatpak/flatpak/issues/4595

Hi,

Thanks for the report. Can someone with the reproducer try the attached patch?

I think the race there is unlikely but possible.

Thanks,
Miklos

[-- Attachment #2: fuse-refcount-fix.patch --]
[-- Type: text/x-patch, Size: 566 bytes --]

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 79f7eda49e06..959d2b7f9e9d 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -847,14 +847,14 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)

replace_page_cache_page(oldpage, newpage);

+ get_page(newpage);
+
/*
* Release while we have extra ref on stolen page. Otherwise
* anon_pipe_buf_release() might think the page can be reused.
*/
pipe_buf_release(cs->pipe, buf);

- get_page(newpage);
-
if (!(buf->flags & PIPE_BUF_FLAG_LRU))
lru_cache_add(newpage);