aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDong Jia Shi <bjsdjshi@linux.ibm.com>2018-05-22 22:56:44 -0400
committerCornelia Huck <cohuck@redhat.com>2018-05-29 03:27:42 -0400
commit6238f92132a6da64b731de1a728fa46ffaa21f62 (patch)
tree45465435d773ecf4a24a3f8ad240745da880b6ce
parent5c1cfb1c3948fe93a32dfcd75223dda0f1558bb7 (diff)
vfio: ccw: set ccw->cda to NULL defensively
Let's avoid free on ccw->cda that points to a guest address or an already freed memory area by setting it to NULL if memory allocation didn't happen or failed. Signed-off-by: Dong Jia Shi <bjsdjshi@linux.ibm.com> Message-Id: <20180523025645.8978-4-bjsdjshi@linux.ibm.com> Signed-off-by: Cornelia Huck <cohuck@redhat.com>
-rw-r--r--drivers/s390/cio/vfio_ccw_cp.c31
1 files changed, 20 insertions, 11 deletions
diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c
index b0f20230fc72..dbe7c7ac9ac8 100644
--- a/drivers/s390/cio/vfio_ccw_cp.c
+++ b/drivers/s390/cio/vfio_ccw_cp.c
@@ -502,7 +502,7 @@ static int ccwchain_fetch_direct(struct ccwchain *chain,
502 struct ccw1 *ccw; 502 struct ccw1 *ccw;
503 struct pfn_array_table *pat; 503 struct pfn_array_table *pat;
504 unsigned long *idaws; 504 unsigned long *idaws;
505 int idaw_nr; 505 int ret;
506 506
507 ccw = chain->ch_ccw + idx; 507 ccw = chain->ch_ccw + idx;
508 508
@@ -522,18 +522,19 @@ static int ccwchain_fetch_direct(struct ccwchain *chain,
522 * needed when translating a direct ccw to a idal ccw. 522 * needed when translating a direct ccw to a idal ccw.
523 */ 523 */
524 pat = chain->ch_pat + idx; 524 pat = chain->ch_pat + idx;
525 if (pfn_array_table_init(pat, 1)) 525 ret = pfn_array_table_init(pat, 1);
526 return -ENOMEM; 526 if (ret)
527 idaw_nr = pfn_array_alloc_pin(pat->pat_pa, cp->mdev, 527 goto out_init;
528 ccw->cda, ccw->count); 528
529 if (idaw_nr < 0) 529 ret = pfn_array_alloc_pin(pat->pat_pa, cp->mdev, ccw->cda, ccw->count);
530 return idaw_nr; 530 if (ret < 0)
531 goto out_init;
531 532
532 /* Translate this direct ccw to a idal ccw. */ 533 /* Translate this direct ccw to a idal ccw. */
533 idaws = kcalloc(idaw_nr, sizeof(*idaws), GFP_DMA | GFP_KERNEL); 534 idaws = kcalloc(ret, sizeof(*idaws), GFP_DMA | GFP_KERNEL);
534 if (!idaws) { 535 if (!idaws) {
535 pfn_array_table_unpin_free(pat, cp->mdev); 536 ret = -ENOMEM;
536 return -ENOMEM; 537 goto out_unpin;
537 } 538 }
538 ccw->cda = (__u32) virt_to_phys(idaws); 539 ccw->cda = (__u32) virt_to_phys(idaws);
539 ccw->flags |= CCW_FLAG_IDA; 540 ccw->flags |= CCW_FLAG_IDA;
@@ -541,6 +542,12 @@ static int ccwchain_fetch_direct(struct ccwchain *chain,
541 pfn_array_table_idal_create_words(pat, idaws); 542 pfn_array_table_idal_create_words(pat, idaws);
542 543
543 return 0; 544 return 0;
545
546out_unpin:
547 pfn_array_table_unpin_free(pat, cp->mdev);
548out_init:
549 ccw->cda = 0;
550 return ret;
544} 551}
545 552
546static int ccwchain_fetch_idal(struct ccwchain *chain, 553static int ccwchain_fetch_idal(struct ccwchain *chain,
@@ -570,7 +577,7 @@ static int ccwchain_fetch_idal(struct ccwchain *chain,
570 pat = chain->ch_pat + idx; 577 pat = chain->ch_pat + idx;
571 ret = pfn_array_table_init(pat, idaw_nr); 578 ret = pfn_array_table_init(pat, idaw_nr);
572 if (ret) 579 if (ret)
573 return ret; 580 goto out_init;
574 581
575 /* Translate idal ccw to use new allocated idaws. */ 582 /* Translate idal ccw to use new allocated idaws. */
576 idaws = kzalloc(idaw_len, GFP_DMA | GFP_KERNEL); 583 idaws = kzalloc(idaw_len, GFP_DMA | GFP_KERNEL);
@@ -602,6 +609,8 @@ out_free_idaws:
602 kfree(idaws); 609 kfree(idaws);
603out_unpin: 610out_unpin:
604 pfn_array_table_unpin_free(pat, cp->mdev); 611 pfn_array_table_unpin_free(pat, cp->mdev);
612out_init:
613 ccw->cda = 0;
605 return ret; 614 return ret;
606} 615}
607 616