Skip to content

Commit

Permalink
[SCSI] virtio_scsi: fix TMF use-after-free
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Paolo Bonzini authored and James Bottomley committed May 10, 2012
1 parent 3c8d9a9 commit e4594bb
Showing 1 changed file with 13 additions and 11 deletions.
24 changes: 13 additions & 11 deletions drivers/scsi/virtio_scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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 = &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)
Expand Down

0 comments on commit e4594bb

Please sign in to comment.