]> git.proxmox.com Git - mirror_ubuntu-focal-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)
committerStefan Bader <stefan.bader@canonical.com>
Tue, 5 May 2020 10:32:22 +0000 (12:32 +0200)
BugLink: https://bugs.launchpad.net/bugs/1873481
commit dc9dc2febb17f72e9878eb540ad3996f7984239a upstream.

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: c917cfaf9bbe ("NFS: Fix up NFS I/O subrequest creation")
Cc: stable@vger.kernel.org
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Kelsey Skunberg <kelsey.skunberg@canonical.com>
fs/nfs/pagelist.c

index 20b3717cd7ca83b8bb9efad78c9099b0d7a144a2..8b7c525dbbf7c8f853660f1868c4d20ee0a7888a 100644 (file)
@@ -1177,38 +1177,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;