]> git.baikalelectronics.ru Git - kernel.git/commitdiff
NFS: Fix use-after-free issues in nfs_pageio_add_request()
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Sun, 29 Mar 2020 23:55:05 +0000 (19:55 -0400)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Wed, 1 Apr 2020 17:37:56 +0000 (13:37 -0400)
We need to ensure that we create the mirror requests before calling
nfs_pageio_add_request_mirror() on the request we are adding.
Otherwise, we can end up with a use-after-free if the call to
nfs_pageio_add_request_mirror() triggers I/O.

Fixes: 4d98e6984499 ("NFS: Fix up NFS I/O subrequest creation")
Cc: stable@vger.kernel.org
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
fs/nfs/pagelist.c

index 0e3f0f241d833cd4fab12c62bc917bb271623b6a..99eb839c577861ed3c7cc5e83827520a313f17fb 100644 (file)
@@ -1191,38 +1191,38 @@ int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
        if (desc->pg_error < 0)
                goto out_failed;
 
-       for (midx = 0; midx < desc->pg_mirror_count; midx++) {
-               if (midx) {
-                       nfs_page_group_lock(req);
-
-                       /* find the last request */
-                       for (lastreq = req->wb_head;
-                            lastreq->wb_this_page != req->wb_head;
-                            lastreq = lastreq->wb_this_page)
-                               ;
-
-                       dupreq = nfs_create_subreq(req, lastreq,
-                                       pgbase, offset, bytes);
-
-                       nfs_page_group_unlock(req);
-                       if (IS_ERR(dupreq)) {
-                               desc->pg_error = PTR_ERR(dupreq);
-                               goto out_failed;
-                       }
-               } else
-                       dupreq = req;
+       /* Create the mirror instances first, and fire them off */
+       for (midx = 1; midx < desc->pg_mirror_count; midx++) {
+               nfs_page_group_lock(req);
+
+               /* find the last request */
+               for (lastreq = req->wb_head;
+                    lastreq->wb_this_page != req->wb_head;
+                    lastreq = lastreq->wb_this_page)
+                       ;
+
+               dupreq = nfs_create_subreq(req, lastreq,
+                               pgbase, offset, bytes);
+
+               nfs_page_group_unlock(req);
+               if (IS_ERR(dupreq)) {
+                       desc->pg_error = PTR_ERR(dupreq);
+                       goto out_failed;
+               }
 
-               if (nfs_pgio_has_mirroring(desc))
-                       desc->pg_mirror_idx = midx;
+               desc->pg_mirror_idx = midx;
                if (!nfs_pageio_add_request_mirror(desc, dupreq))
                        goto out_cleanup_subreq;
        }
 
+       desc->pg_mirror_idx = 0;
+       if (!nfs_pageio_add_request_mirror(desc, req))
+               goto out_failed;
+
        return 1;
 
 out_cleanup_subreq:
-       if (req != dupreq)
-               nfs_pageio_cleanup_request(desc, dupreq);
+       nfs_pageio_cleanup_request(desc, dupreq);
 out_failed:
        nfs_pageio_error_cleanup(desc);
        return 0;