diff options
author | Dong Jia Shi <bjsdjshi@linux.ibm.com> | 2018-05-22 22:56:44 -0400 |
---|---|---|
committer | Cornelia Huck <cohuck@redhat.com> | 2018-05-29 03:27:42 -0400 |
commit | 6238f92132a6da64b731de1a728fa46ffaa21f62 (patch) | |
tree | 45465435d773ecf4a24a3f8ad240745da880b6ce | |
parent | 5c1cfb1c3948fe93a32dfcd75223dda0f1558bb7 (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.c | 31 |
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 | |||
546 | out_unpin: | ||
547 | pfn_array_table_unpin_free(pat, cp->mdev); | ||
548 | out_init: | ||
549 | ccw->cda = 0; | ||
550 | return ret; | ||
544 | } | 551 | } |
545 | 552 | ||
546 | static int ccwchain_fetch_idal(struct ccwchain *chain, | 553 | static 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); |
603 | out_unpin: | 610 | out_unpin: |
604 | pfn_array_table_unpin_free(pat, cp->mdev); | 611 | pfn_array_table_unpin_free(pat, cp->mdev); |
612 | out_init: | ||
613 | ccw->cda = 0; | ||
605 | return ret; | 614 | return ret; |
606 | } | 615 | } |
607 | 616 | ||