aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2017-09-08 21:28:11 -0400
committerTrond Myklebust <trond.myklebust@primarydata.com>2017-09-08 22:07:52 -0400
commit196639ebbe63a037fe9a80669140bd292d8bcd80 (patch)
tree96e44b7ef1fbfb23c69076f96c4987e397f9333e
parente973b1a5999e57da677ab50da5f5479fdc0f0c31 (diff)
NFS: Fix 2 use after free issues in the I/O code
The writeback code wants to send a commit after processing the pages, which is why we want to delay releasing the struct path until after that's done. Also, the layout code expects that we do not free the inode before we've put the layout segments in pnfs_writehdr_free() and pnfs_readhdr_free() Fixes: 919e3bd9a875 ("NFS: Ensure we commit after writeback is complete") Fixes: 4714fb51fd03 ("nfs: remove pgio_header refcount, related cleanup") Cc: stable@vger.kernel.org Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
-rw-r--r--fs/nfs/internal.h1
-rw-r--r--fs/nfs/pagelist.c26
-rw-r--r--fs/nfs/pnfs.c2
3 files changed, 12 insertions, 17 deletions
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index dc456416d2be..68cc22083639 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -251,7 +251,6 @@ int nfs_iocounter_wait(struct nfs_lock_context *l_ctx);
251extern const struct nfs_pageio_ops nfs_pgio_rw_ops; 251extern const struct nfs_pageio_ops nfs_pgio_rw_ops;
252struct nfs_pgio_header *nfs_pgio_header_alloc(const struct nfs_rw_ops *); 252struct nfs_pgio_header *nfs_pgio_header_alloc(const struct nfs_rw_ops *);
253void nfs_pgio_header_free(struct nfs_pgio_header *); 253void nfs_pgio_header_free(struct nfs_pgio_header *);
254void nfs_pgio_data_destroy(struct nfs_pgio_header *);
255int nfs_generic_pgio(struct nfs_pageio_descriptor *, struct nfs_pgio_header *); 254int nfs_generic_pgio(struct nfs_pageio_descriptor *, struct nfs_pgio_header *);
256int nfs_initiate_pgio(struct rpc_clnt *clnt, struct nfs_pgio_header *hdr, 255int nfs_initiate_pgio(struct rpc_clnt *clnt, struct nfs_pgio_header *hdr,
257 struct rpc_cred *cred, const struct nfs_rpc_ops *rpc_ops, 256 struct rpc_cred *cred, const struct nfs_rpc_ops *rpc_ops,
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index 23cf4a82d94c..bec120ec1967 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -501,16 +501,6 @@ struct nfs_pgio_header *nfs_pgio_header_alloc(const struct nfs_rw_ops *ops)
501} 501}
502EXPORT_SYMBOL_GPL(nfs_pgio_header_alloc); 502EXPORT_SYMBOL_GPL(nfs_pgio_header_alloc);
503 503
504/*
505 * nfs_pgio_header_free - Free a read or write header
506 * @hdr: The header to free
507 */
508void nfs_pgio_header_free(struct nfs_pgio_header *hdr)
509{
510 hdr->rw_ops->rw_free_header(hdr);
511}
512EXPORT_SYMBOL_GPL(nfs_pgio_header_free);
513
514/** 504/**
515 * nfs_pgio_data_destroy - make @hdr suitable for reuse 505 * nfs_pgio_data_destroy - make @hdr suitable for reuse
516 * 506 *
@@ -519,14 +509,24 @@ EXPORT_SYMBOL_GPL(nfs_pgio_header_free);
519 * 509 *
520 * @hdr: A header that has had nfs_generic_pgio called 510 * @hdr: A header that has had nfs_generic_pgio called
521 */ 511 */
522void nfs_pgio_data_destroy(struct nfs_pgio_header *hdr) 512static void nfs_pgio_data_destroy(struct nfs_pgio_header *hdr)
523{ 513{
524 if (hdr->args.context) 514 if (hdr->args.context)
525 put_nfs_open_context(hdr->args.context); 515 put_nfs_open_context(hdr->args.context);
526 if (hdr->page_array.pagevec != hdr->page_array.page_array) 516 if (hdr->page_array.pagevec != hdr->page_array.page_array)
527 kfree(hdr->page_array.pagevec); 517 kfree(hdr->page_array.pagevec);
528} 518}
529EXPORT_SYMBOL_GPL(nfs_pgio_data_destroy); 519
520/*
521 * nfs_pgio_header_free - Free a read or write header
522 * @hdr: The header to free
523 */
524void nfs_pgio_header_free(struct nfs_pgio_header *hdr)
525{
526 nfs_pgio_data_destroy(hdr);
527 hdr->rw_ops->rw_free_header(hdr);
528}
529EXPORT_SYMBOL_GPL(nfs_pgio_header_free);
530 530
531/** 531/**
532 * nfs_pgio_rpcsetup - Set up arguments for a pageio call 532 * nfs_pgio_rpcsetup - Set up arguments for a pageio call
@@ -640,7 +640,6 @@ EXPORT_SYMBOL_GPL(nfs_initiate_pgio);
640static void nfs_pgio_error(struct nfs_pgio_header *hdr) 640static void nfs_pgio_error(struct nfs_pgio_header *hdr)
641{ 641{
642 set_bit(NFS_IOHDR_REDO, &hdr->flags); 642 set_bit(NFS_IOHDR_REDO, &hdr->flags);
643 nfs_pgio_data_destroy(hdr);
644 hdr->completion_ops->completion(hdr); 643 hdr->completion_ops->completion(hdr);
645} 644}
646 645
@@ -651,7 +650,6 @@ static void nfs_pgio_error(struct nfs_pgio_header *hdr)
651static void nfs_pgio_release(void *calldata) 650static void nfs_pgio_release(void *calldata)
652{ 651{
653 struct nfs_pgio_header *hdr = calldata; 652 struct nfs_pgio_header *hdr = calldata;
654 nfs_pgio_data_destroy(hdr);
655 hdr->completion_ops->completion(hdr); 653 hdr->completion_ops->completion(hdr);
656} 654}
657 655
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 3125a9d7b237..7879ed8ceb76 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -2233,7 +2233,6 @@ pnfs_write_through_mds(struct nfs_pageio_descriptor *desc,
2233 nfs_pageio_reset_write_mds(desc); 2233 nfs_pageio_reset_write_mds(desc);
2234 mirror->pg_recoalesce = 1; 2234 mirror->pg_recoalesce = 1;
2235 } 2235 }
2236 nfs_pgio_data_destroy(hdr);
2237 hdr->release(hdr); 2236 hdr->release(hdr);
2238} 2237}
2239 2238
@@ -2357,7 +2356,6 @@ pnfs_read_through_mds(struct nfs_pageio_descriptor *desc,
2357 nfs_pageio_reset_read_mds(desc); 2356 nfs_pageio_reset_read_mds(desc);
2358 mirror->pg_recoalesce = 1; 2357 mirror->pg_recoalesce = 1;
2359 } 2358 }
2360 nfs_pgio_data_destroy(hdr);
2361 hdr->release(hdr); 2359 hdr->release(hdr);
2362} 2360}
2363 2361