Skip to content

Commit d78092e

Browse files
author
Miklos Szeredi
committed
fuse: fix page dereference after free
After unlock_request() pages from the ap->pages[] array may be put (e.g. by aborting the connection) and the pages can be freed. Prevent use after free by grabbing a reference to the page before calling unlock_request(). The original patch was created by Pradeep P V K. Reported-by: Pradeep P V K <ppvk@codeaurora.org> Cc: <stable@vger.kernel.org> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
1 parent 9a752d1 commit d78092e

1 file changed

Lines changed: 18 additions & 10 deletions

File tree

fs/fuse/dev.c

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -785,15 +785,16 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
785785
struct page *newpage;
786786
struct pipe_buffer *buf = cs->pipebufs;
787787

788+
get_page(oldpage);
788789
err = unlock_request(cs->req);
789790
if (err)
790-
return err;
791+
goto out_put_old;
791792

792793
fuse_copy_finish(cs);
793794

794795
err = pipe_buf_confirm(cs->pipe, buf);
795796
if (err)
796-
return err;
797+
goto out_put_old;
797798

798799
BUG_ON(!cs->nr_segs);
799800
cs->currbuf = buf;
@@ -833,7 +834,7 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
833834
err = replace_page_cache_page(oldpage, newpage, GFP_KERNEL);
834835
if (err) {
835836
unlock_page(newpage);
836-
return err;
837+
goto out_put_old;
837838
}
838839

839840
get_page(newpage);
@@ -852,14 +853,19 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
852853
if (err) {
853854
unlock_page(newpage);
854855
put_page(newpage);
855-
return err;
856+
goto out_put_old;
856857
}
857858

858859
unlock_page(oldpage);
860+
/* Drop ref for ap->pages[] array */
859861
put_page(oldpage);
860862
cs->len = 0;
861863

862-
return 0;
864+
err = 0;
865+
out_put_old:
866+
/* Drop ref obtained in this function */
867+
put_page(oldpage);
868+
return err;
863869

864870
out_fallback_unlock:
865871
unlock_page(newpage);
@@ -868,10 +874,10 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
868874
cs->offset = buf->offset;
869875

870876
err = lock_request(cs->req);
871-
if (err)
872-
return err;
877+
if (!err)
878+
err = 1;
873879

874-
return 1;
880+
goto out_put_old;
875881
}
876882

877883
static int fuse_ref_page(struct fuse_copy_state *cs, struct page *page,
@@ -883,14 +889,16 @@ static int fuse_ref_page(struct fuse_copy_state *cs, struct page *page,
883889
if (cs->nr_segs >= cs->pipe->max_usage)
884890
return -EIO;
885891

892+
get_page(page);
886893
err = unlock_request(cs->req);
887-
if (err)
894+
if (err) {
895+
put_page(page);
888896
return err;
897+
}
889898

890899
fuse_copy_finish(cs);
891900

892901
buf = cs->pipebufs;
893-
get_page(page);
894902
buf->page = page;
895903
buf->offset = offset;
896904
buf->len = count;

0 commit comments

Comments
 (0)