mainline inclusion from mainline-v7.2-rc1 commit a078484921052d0badd827fcc2770b5cfc1d4120 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/16108 CVE: CVE-2026-53388 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- fuse_try_move_folio() unlocks the request on entry but does not re-lock it on the success path. This means fuse_chan_abort() can end the request and free the fuse_io_args (eg fuse_readpages_end()) while the subsequent copy chain logic after fuse_try_move_folio() accesses the fuse_io_args, leading to use-after-free issues. Fix this by calling lock_request() before replace_page_cache_folio(). This ensures the request is locked on the success path which will prevent the fuse_io_args from being freed while the later copying logic runs, and also ensures that the ap->folios[i]->mapping is never null since ap->folios[i] will always point to the newfolio after replace_page_cache_folio(). Fixes: ce534fb05292 ("fuse: allow splice to move pages") Cc: stable@vger.kernel.org Reported-by: Lei Lu <llfamsec@gmail.com> Signed-off-by: Joanne Koong <joannelkoong@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> Conflicts: fs/fuse/dev.c [Conflicts due to context] Signed-off-by: Lu Chentao <luchentao1@huawei.com> --- fs/fuse/dev.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 0c4487e4b867..1a12515fd8ea 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -1186,10 +1186,14 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep) if (WARN_ON(PageDirty(oldpage) || PageWriteback(oldpage))) goto out_fallback_unlock; if (WARN_ON(PageMlocked(oldpage))) goto out_fallback_unlock; + err = lock_request(cs->req); + if (err) + goto out_fallback_unlock; + err = replace_page_cache_page(oldpage, newpage, GFP_KERNEL); if (err) { unlock_page(newpage); goto out_put_old; } @@ -1203,24 +1207,11 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep) * 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); - err = 0; - spin_lock(&cs->req->waitq.lock); - if (test_bit(FR_ABORTED, &cs->req->flags)) - err = -ENOENT; - else - *pagep = newpage; - spin_unlock(&cs->req->waitq.lock); - - if (err) { - unlock_page(newpage); - put_page(newpage); - goto out_put_old; - } - + *pagep = newpage; unlock_page(oldpage); /* Drop ref for ap->pages[] array */ put_page(oldpage); cs->len = 0; -- 2.52.0