[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:
parent
3c8d9a957d
commit
e4594bb505
1 changed files with 13 additions and 11 deletions
|
@ -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 @@ 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)
|
||||
{
|
||||
DECLARE_COMPLETION_ONSTACK(comp);
|
||||
int ret;
|
||||
int ret = FAILED;
|
||||
|
||||
cmd->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)
|
||||
|
|
Loading…
Reference in a new issue