[SCSI] virtio_scsi: fix TMF use-after-free

Fix a use-after-free in the TMF path, where cmd may have been already
freed by virtscsi_complete_free when wait_for_completion restarts
executing virtscsi_tmf.  Technically a race, but in practice the command
will always be freed long before the completion waiter is awoken.

The fix is to make callers specifying a completion responsible for
freeing the command in all cases.

Signed-off-by: Hu Tao <hutao@cn.fujitsu.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
Paolo Bonzini 2012-05-04 12:32:04 +02:00 committed by James Bottomley
parent 3c8d9a957d
commit e4594bb505

View File

@ -175,7 +175,8 @@ static void virtscsi_complete_free(void *buf)
if (cmd->comp)
complete_all(cmd->comp);
mempool_free(cmd, virtscsi_cmd_pool);
else
mempool_free(cmd, virtscsi_cmd_pool);
}
static void virtscsi_ctrl_done(struct virtqueue *vq)
@ -311,21 +312,22 @@ out:
static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd)
{
DECLARE_COMPLETION_ONSTACK(comp);
int ret;
int ret = FAILED;
cmd->comp = &comp;
ret = virtscsi_kick_cmd(vscsi, vscsi->ctrl_vq, cmd,
sizeof cmd->req.tmf, sizeof cmd->resp.tmf,
GFP_NOIO);
if (ret < 0)
return FAILED;
if (virtscsi_kick_cmd(vscsi, vscsi->ctrl_vq, cmd,
sizeof cmd->req.tmf, sizeof cmd->resp.tmf,
GFP_NOIO) < 0)
goto out;
wait_for_completion(&comp);
if (cmd->resp.tmf.response != VIRTIO_SCSI_S_OK &&
cmd->resp.tmf.response != VIRTIO_SCSI_S_FUNCTION_SUCCEEDED)
return FAILED;
if (cmd->resp.tmf.response == VIRTIO_SCSI_S_OK ||
cmd->resp.tmf.response == VIRTIO_SCSI_S_FUNCTION_SUCCEEDED)
ret = SUCCESS;
return SUCCESS;
out:
mempool_free(cmd, virtscsi_cmd_pool);
return ret;
}
static int virtscsi_device_reset(struct scsi_cmnd *sc)