Skip to content

Commit be2fd15

Browse files
author
Trond Myklebust
committed
NFS: Fix a use after free in nfs_direct_join_group()
Be more careful when tearing down the subrequests of an O_DIRECT write as part of a retransmission. Reported-by: Chris Mason <clm@fb.com> Fixes: ed5d588 ("NFS: Try to join page groups before an O_DIRECT retransmission") Cc: stable@vger.kernel.org Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
1 parent 1cbc11a commit be2fd15

File tree

1 file changed

+16
-10
lines changed

1 file changed

+16
-10
lines changed

fs/nfs/direct.c

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -472,20 +472,26 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter,
472472
return result;
473473
}
474474

475-
static void
476-
nfs_direct_join_group(struct list_head *list, struct inode *inode)
475+
static void nfs_direct_join_group(struct list_head *list, struct inode *inode)
477476
{
478-
struct nfs_page *req, *next;
477+
struct nfs_page *req, *subreq;
479478

480479
list_for_each_entry(req, list, wb_list) {
481-
if (req->wb_head != req || req->wb_this_page == req)
480+
if (req->wb_head != req)
482481
continue;
483-
for (next = req->wb_this_page;
484-
next != req->wb_head;
485-
next = next->wb_this_page) {
486-
nfs_list_remove_request(next);
487-
nfs_release_request(next);
488-
}
482+
subreq = req->wb_this_page;
483+
if (subreq == req)
484+
continue;
485+
do {
486+
/*
487+
* Remove subrequests from this list before freeing
488+
* them in the call to nfs_join_page_group().
489+
*/
490+
if (!list_empty(&subreq->wb_list)) {
491+
nfs_list_remove_request(subreq);
492+
nfs_release_request(subreq);
493+
}
494+
} while ((subreq = subreq->wb_this_page) != req);
489495
nfs_join_page_group(req, inode);
490496
}
491497
}

0 commit comments

Comments
 (0)