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>
This commit is contained in:
parent
5c1cfb1c39
commit
6238f92132
@ -502,7 +502,7 @@ static int ccwchain_fetch_direct(struct ccwchain *chain,
|
|||||||
struct ccw1 *ccw;
|
struct ccw1 *ccw;
|
||||||
struct pfn_array_table *pat;
|
struct pfn_array_table *pat;
|
||||||
unsigned long *idaws;
|
unsigned long *idaws;
|
||||||
int idaw_nr;
|
int ret;
|
||||||
|
|
||||||
ccw = chain->ch_ccw + idx;
|
ccw = chain->ch_ccw + idx;
|
||||||
|
|
||||||
@ -522,18 +522,19 @@ static int ccwchain_fetch_direct(struct ccwchain *chain,
|
|||||||
* needed when translating a direct ccw to a idal ccw.
|
* needed when translating a direct ccw to a idal ccw.
|
||||||
*/
|
*/
|
||||||
pat = chain->ch_pat + idx;
|
pat = chain->ch_pat + idx;
|
||||||
if (pfn_array_table_init(pat, 1))
|
ret = pfn_array_table_init(pat, 1);
|
||||||
return -ENOMEM;
|
if (ret)
|
||||||
idaw_nr = pfn_array_alloc_pin(pat->pat_pa, cp->mdev,
|
goto out_init;
|
||||||
ccw->cda, ccw->count);
|
|
||||||
if (idaw_nr < 0)
|
ret = pfn_array_alloc_pin(pat->pat_pa, cp->mdev, ccw->cda, ccw->count);
|
||||||
return idaw_nr;
|
if (ret < 0)
|
||||||
|
goto out_init;
|
||||||
|
|
||||||
/* Translate this direct ccw to a idal ccw. */
|
/* Translate this direct ccw to a idal ccw. */
|
||||||
idaws = kcalloc(idaw_nr, sizeof(*idaws), GFP_DMA | GFP_KERNEL);
|
idaws = kcalloc(ret, sizeof(*idaws), GFP_DMA | GFP_KERNEL);
|
||||||
if (!idaws) {
|
if (!idaws) {
|
||||||
pfn_array_table_unpin_free(pat, cp->mdev);
|
ret = -ENOMEM;
|
||||||
return -ENOMEM;
|
goto out_unpin;
|
||||||
}
|
}
|
||||||
ccw->cda = (__u32) virt_to_phys(idaws);
|
ccw->cda = (__u32) virt_to_phys(idaws);
|
||||||
ccw->flags |= CCW_FLAG_IDA;
|
ccw->flags |= CCW_FLAG_IDA;
|
||||||
@ -541,6 +542,12 @@ static int ccwchain_fetch_direct(struct ccwchain *chain,
|
|||||||
pfn_array_table_idal_create_words(pat, idaws);
|
pfn_array_table_idal_create_words(pat, idaws);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
out_unpin:
|
||||||
|
pfn_array_table_unpin_free(pat, cp->mdev);
|
||||||
|
out_init:
|
||||||
|
ccw->cda = 0;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ccwchain_fetch_idal(struct ccwchain *chain,
|
static int ccwchain_fetch_idal(struct ccwchain *chain,
|
||||||
@ -570,7 +577,7 @@ static int ccwchain_fetch_idal(struct ccwchain *chain,
|
|||||||
pat = chain->ch_pat + idx;
|
pat = chain->ch_pat + idx;
|
||||||
ret = pfn_array_table_init(pat, idaw_nr);
|
ret = pfn_array_table_init(pat, idaw_nr);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto out_init;
|
||||||
|
|
||||||
/* Translate idal ccw to use new allocated idaws. */
|
/* Translate idal ccw to use new allocated idaws. */
|
||||||
idaws = kzalloc(idaw_len, GFP_DMA | GFP_KERNEL);
|
idaws = kzalloc(idaw_len, GFP_DMA | GFP_KERNEL);
|
||||||
@ -602,6 +609,8 @@ out_free_idaws:
|
|||||||
kfree(idaws);
|
kfree(idaws);
|
||||||
out_unpin:
|
out_unpin:
|
||||||
pfn_array_table_unpin_free(pat, cp->mdev);
|
pfn_array_table_unpin_free(pat, cp->mdev);
|
||||||
|
out_init:
|
||||||
|
ccw->cda = 0;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user