Commit e4594bb5 authored by Paolo Bonzini's avatar Paolo Bonzini Committed by James Bottomley

[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: default avatarHu Tao <hutao@cn.fujitsu.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 3c8d9a95
...@@ -175,7 +175,8 @@ static void virtscsi_complete_free(void *buf) ...@@ -175,7 +175,8 @@ static void virtscsi_complete_free(void *buf)
if (cmd->comp) if (cmd->comp)
complete_all(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) static void virtscsi_ctrl_done(struct virtqueue *vq)
...@@ -311,21 +312,22 @@ static int virtscsi_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc) ...@@ -311,21 +312,22 @@ static int virtscsi_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc)
static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd) static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd)
{ {
DECLARE_COMPLETION_ONSTACK(comp); DECLARE_COMPLETION_ONSTACK(comp);
int ret; int ret = FAILED;
cmd->comp = &comp; cmd->comp = &comp;
ret = virtscsi_kick_cmd(vscsi, vscsi->ctrl_vq, cmd, if (virtscsi_kick_cmd(vscsi, vscsi->ctrl_vq, cmd,
sizeof cmd->req.tmf, sizeof cmd->resp.tmf, sizeof cmd->req.tmf, sizeof cmd->resp.tmf,
GFP_NOIO); GFP_NOIO) < 0)
if (ret < 0) goto out;
return FAILED;
wait_for_completion(&comp); wait_for_completion(&comp);
if (cmd->resp.tmf.response != VIRTIO_SCSI_S_OK && if (cmd->resp.tmf.response == VIRTIO_SCSI_S_OK ||
cmd->resp.tmf.response != VIRTIO_SCSI_S_FUNCTION_SUCCEEDED) cmd->resp.tmf.response == VIRTIO_SCSI_S_FUNCTION_SUCCEEDED)
return FAILED; ret = SUCCESS;
return SUCCESS; out:
mempool_free(cmd, virtscsi_cmd_pool);
return ret;
} }
static int virtscsi_device_reset(struct scsi_cmnd *sc) static int virtscsi_device_reset(struct scsi_cmnd *sc)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment