Skip to content

Commit e4594bb

Browse files
bonziniJames Bottomley
authored andcommitted
[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 <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]> Signed-off-by: James Bottomley <[email protected]>
1 parent 3c8d9a9 commit e4594bb

File tree

1 file changed

+13
-11
lines changed

1 file changed

+13
-11
lines changed

drivers/scsi/virtio_scsi.c

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,8 @@ static void virtscsi_complete_free(void *buf)
175175

176176
if (cmd->comp)
177177
complete_all(cmd->comp);
178-
mempool_free(cmd, virtscsi_cmd_pool);
178+
else
179+
mempool_free(cmd, virtscsi_cmd_pool);
179180
}
180181

181182
static void virtscsi_ctrl_done(struct virtqueue *vq)
@@ -311,21 +312,22 @@ static int virtscsi_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc)
311312
static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd)
312313
{
313314
DECLARE_COMPLETION_ONSTACK(comp);
314-
int ret;
315+
int ret = FAILED;
315316

316317
cmd->comp = &comp;
317-
ret = virtscsi_kick_cmd(vscsi, vscsi->ctrl_vq, cmd,
318-
sizeof cmd->req.tmf, sizeof cmd->resp.tmf,
319-
GFP_NOIO);
320-
if (ret < 0)
321-
return FAILED;
318+
if (virtscsi_kick_cmd(vscsi, vscsi->ctrl_vq, cmd,
319+
sizeof cmd->req.tmf, sizeof cmd->resp.tmf,
320+
GFP_NOIO) < 0)
321+
goto out;
322322

323323
wait_for_completion(&comp);
324-
if (cmd->resp.tmf.response != VIRTIO_SCSI_S_OK &&
325-
cmd->resp.tmf.response != VIRTIO_SCSI_S_FUNCTION_SUCCEEDED)
326-
return FAILED;
324+
if (cmd->resp.tmf.response == VIRTIO_SCSI_S_OK ||
325+
cmd->resp.tmf.response == VIRTIO_SCSI_S_FUNCTION_SUCCEEDED)
326+
ret = SUCCESS;
327327

328-
return SUCCESS;
328+
out:
329+
mempool_free(cmd, virtscsi_cmd_pool);
330+
return ret;
329331
}
330332

331333
static int virtscsi_device_reset(struct scsi_cmnd *sc)

0 commit comments

Comments
 (0)