[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:
Родитель
3c8d9a957d
Коммит
e4594bb505
|
@ -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 @@ out:
|
||||||
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 = ∁
|
cmd->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)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче