Skip to content

Commit af28922

Browse files
joannekoonggregkh
authored andcommitted
fuse: re-lock request before replacing page cache folio
commit a078484 upstream. 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: ce534fb ("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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 29706ac commit af28922

1 file changed

Lines changed: 5 additions & 14 deletions

File tree

fs/fuse/dev.c

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,6 +1037,10 @@ static int fuse_try_move_folio(struct fuse_copy_state *cs, struct folio **foliop
10371037
if (WARN_ON(folio_test_mlocked(oldfolio)))
10381038
goto out_fallback_unlock;
10391039

1040+
err = lock_request(cs->req);
1041+
if (err)
1042+
goto out_fallback_unlock;
1043+
10401044
replace_page_cache_folio(oldfolio, newfolio);
10411045

10421046
folio_get(newfolio);
@@ -1050,20 +1054,7 @@ static int fuse_try_move_folio(struct fuse_copy_state *cs, struct folio **foliop
10501054
*/
10511055
pipe_buf_release(cs->pipe, buf);
10521056

1053-
err = 0;
1054-
spin_lock(&cs->req->waitq.lock);
1055-
if (test_bit(FR_ABORTED, &cs->req->flags))
1056-
err = -ENOENT;
1057-
else
1058-
*foliop = newfolio;
1059-
spin_unlock(&cs->req->waitq.lock);
1060-
1061-
if (err) {
1062-
folio_unlock(newfolio);
1063-
folio_put(newfolio);
1064-
goto out_put_old;
1065-
}
1066-
1057+
*foliop = newfolio;
10671058
folio_unlock(oldfolio);
10681059
/* Drop ref for ap->pages[] array */
10691060
folio_put(oldfolio);

0 commit comments

Comments
 (0)