summaryrefslogtreecommitdiff
path: root/block/block-backend.c
diff options
context:
space:
mode:
authorDeepa Srinivasan <deepa.srinivasan@oracle.com>2017-12-15 16:59:13 -0800
committerStefan Hajnoczi <stefanha@redhat.com>2018-03-08 15:43:11 +0000
commitc060332c762acbe7899b01edda972da7f9ec9057 (patch)
treef8e61f407d4b17c039f93e8b7a4137ec65c29794 /block/block-backend.c
parent0ab4537f08e09b13788db67efd760592fb7db769 (diff)
downloadqemu-c060332c762acbe7899b01edda972da7f9ec9057.zip
block: Fix qemu crash when using scsi-block
Starting qemu with the following arguments causes qemu to segfault: ... -device lsi,id=lsi0 -drive file=iscsi:<...>,format=raw,if=none,node-name= iscsi1 -device scsi-block,bus=lsi0.0,id=<...>,drive=iscsi1 This patch fixes blk_aio_ioctl() so it does not pass stack addresses to blk_aio_ioctl_entry() which may be invoked after blk_aio_ioctl() returns. More details about the bug follow. blk_aio_ioctl() invokes blk_aio_prwv() with blk_aio_ioctl_entry as the coroutine parameter. blk_aio_prwv() ultimately calls aio_co_enter(). When blk_aio_ioctl() is executed from within a coroutine context (e.g. iscsi_bh_cb()), aio_co_enter() adds the coroutine (blk_aio_ioctl_entry) to the current coroutine's wakeup queue. blk_aio_ioctl() then returns. When blk_aio_ioctl_entry() executes later, it accesses an invalid pointer: .... BlkRwCo *rwco = &acb->rwco; rwco->ret = blk_co_ioctl(rwco->blk, rwco->offset, rwco->qiov->iov[0].iov_base); <--- qiov is invalid here ... In the case when blk_aio_ioctl() is called from a non-coroutine context, blk_aio_ioctl_entry() executes immediately. But if bdrv_co_ioctl() calls qemu_coroutine_yield(), blk_aio_ioctl() will return. When the coroutine execution is complete, control returns to blk_aio_ioctl_entry() after the call to blk_co_ioctl(). There is no invalid reference after this point, but the function is still holding on to invalid pointers. The fix is to change blk_aio_prwv() to accept a void pointer for the IO buffer rather than a QEMUIOVector. blk_aio_prwv() passes this through in BlkRwCo and the coroutine function casts it to QEMUIOVector or uses the void pointer directly. Signed-off-by: Deepa Srinivasan <deepa.srinivasan@oracle.com> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Reviewed-by: Mark Kanda <mark.kanda@oracle.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'block/block-backend.c')
-rw-r--r--block/block-backend.c51
1 files changed, 25 insertions, 26 deletions
diff --git a/block/block-backend.c b/block/block-backend.c
index b3c790e2bd..f2e0a855ff 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -1150,7 +1150,7 @@ int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset,
typedef struct BlkRwCo {
BlockBackend *blk;
int64_t offset;
- QEMUIOVector *qiov;
+ void *iobuf;
int ret;
BdrvRequestFlags flags;
} BlkRwCo;
@@ -1158,17 +1158,19 @@ typedef struct BlkRwCo {
static void blk_read_entry(void *opaque)
{
BlkRwCo *rwco = opaque;
+ QEMUIOVector *qiov = rwco->iobuf;
- rwco->ret = blk_co_preadv(rwco->blk, rwco->offset, rwco->qiov->size,
- rwco->qiov, rwco->flags);
+ rwco->ret = blk_co_preadv(rwco->blk, rwco->offset, qiov->size,
+ qiov, rwco->flags);
}
static void blk_write_entry(void *opaque)
{
BlkRwCo *rwco = opaque;
+ QEMUIOVector *qiov = rwco->iobuf;
- rwco->ret = blk_co_pwritev(rwco->blk, rwco->offset, rwco->qiov->size,
- rwco->qiov, rwco->flags);
+ rwco->ret = blk_co_pwritev(rwco->blk, rwco->offset, qiov->size,
+ qiov, rwco->flags);
}
static int blk_prw(BlockBackend *blk, int64_t offset, uint8_t *buf,
@@ -1188,7 +1190,7 @@ static int blk_prw(BlockBackend *blk, int64_t offset, uint8_t *buf,
rwco = (BlkRwCo) {
.blk = blk,
.offset = offset,
- .qiov = &qiov,
+ .iobuf = &qiov,
.flags = flags,
.ret = NOT_DONE,
};
@@ -1296,7 +1298,7 @@ static void blk_aio_complete_bh(void *opaque)
}
static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, int bytes,
- QEMUIOVector *qiov, CoroutineEntry co_entry,
+ void *iobuf, CoroutineEntry co_entry,
BdrvRequestFlags flags,
BlockCompletionFunc *cb, void *opaque)
{
@@ -1308,7 +1310,7 @@ static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, int bytes,
acb->rwco = (BlkRwCo) {
.blk = blk,
.offset = offset,
- .qiov = qiov,
+ .iobuf = iobuf,
.flags = flags,
.ret = NOT_DONE,
};
@@ -1331,10 +1333,11 @@ static void blk_aio_read_entry(void *opaque)
{
BlkAioEmAIOCB *acb = opaque;
BlkRwCo *rwco = &acb->rwco;
+ QEMUIOVector *qiov = rwco->iobuf;
- assert(rwco->qiov->size == acb->bytes);
+ assert(qiov->size == acb->bytes);
rwco->ret = blk_co_preadv(rwco->blk, rwco->offset, acb->bytes,
- rwco->qiov, rwco->flags);
+ qiov, rwco->flags);
blk_aio_complete(acb);
}
@@ -1342,10 +1345,11 @@ static void blk_aio_write_entry(void *opaque)
{
BlkAioEmAIOCB *acb = opaque;
BlkRwCo *rwco = &acb->rwco;
+ QEMUIOVector *qiov = rwco->iobuf;
- assert(!rwco->qiov || rwco->qiov->size == acb->bytes);
+ assert(!qiov || qiov->size == acb->bytes);
rwco->ret = blk_co_pwritev(rwco->blk, rwco->offset, acb->bytes,
- rwco->qiov, rwco->flags);
+ qiov, rwco->flags);
blk_aio_complete(acb);
}
@@ -1474,8 +1478,10 @@ int blk_co_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
static void blk_ioctl_entry(void *opaque)
{
BlkRwCo *rwco = opaque;
+ QEMUIOVector *qiov = rwco->iobuf;
+
rwco->ret = blk_co_ioctl(rwco->blk, rwco->offset,
- rwco->qiov->iov[0].iov_base);
+ qiov->iov[0].iov_base);
}
int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
@@ -1488,24 +1494,15 @@ static void blk_aio_ioctl_entry(void *opaque)
BlkAioEmAIOCB *acb = opaque;
BlkRwCo *rwco = &acb->rwco;
- rwco->ret = blk_co_ioctl(rwco->blk, rwco->offset,
- rwco->qiov->iov[0].iov_base);
+ rwco->ret = blk_co_ioctl(rwco->blk, rwco->offset, rwco->iobuf);
+
blk_aio_complete(acb);
}
BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf,
BlockCompletionFunc *cb, void *opaque)
{
- QEMUIOVector qiov;
- struct iovec iov;
-
- iov = (struct iovec) {
- .iov_base = buf,
- .iov_len = 0,
- };
- qemu_iovec_init_external(&qiov, &iov, 1);
-
- return blk_aio_prwv(blk, req, 0, &qiov, blk_aio_ioctl_entry, 0, cb, opaque);
+ return blk_aio_prwv(blk, req, 0, buf, blk_aio_ioctl_entry, 0, cb, opaque);
}
int blk_co_pdiscard(BlockBackend *blk, int64_t offset, int bytes)
@@ -1949,7 +1946,9 @@ int blk_truncate(BlockBackend *blk, int64_t offset, PreallocMode prealloc,
static void blk_pdiscard_entry(void *opaque)
{
BlkRwCo *rwco = opaque;
- rwco->ret = blk_co_pdiscard(rwco->blk, rwco->offset, rwco->qiov->size);
+ QEMUIOVector *qiov = rwco->iobuf;
+
+ rwco->ret = blk_co_pdiscard(rwco->blk, rwco->offset, qiov->size);
}
int blk_pdiscard(BlockBackend *blk, int64_t offset, int bytes)