vhost_scsi: validate length of virtio descriptors

Casting pointers without checking their length could
potentially lead to a crash

Change-Id: I7c61e5818ecfbf32bb363858965503341353c51e
Signed-off-by: Pawel Niedzwiecki <pawelx.niedzwiecki@intel.com>
Reviewed-on: https://review.gerrithub.io/382420
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Dariusz Stojaczyk <dariuszx.stojaczyk@intel.com>
Reviewed-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>
Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
This commit is contained in:
Pawel Niedzwiecki 2017-10-13 15:30:05 +02:00 committed by Daniel Verkamp
parent 3f9cbe513b
commit 97e82c0c06
3 changed files with 33 additions and 3 deletions

View File

@ -138,6 +138,10 @@ spdk_vhost_vq_get_desc(struct spdk_vhost_dev *vdev, struct spdk_vhost_virtqueue
*desc_table = spdk_vhost_gpa_to_vva(vdev, (*desc)->addr);
*desc_table_size = (*desc)->len / sizeof(**desc);
*desc = *desc_table;
if (*desc == NULL) {
return -1;
}
return 0;
}

View File

@ -148,7 +148,7 @@ bool spdk_vhost_vq_should_notify(struct spdk_vhost_dev *vdev, struct spdk_vhost_
* table.
* \param desc_table_size size of the *desc_table*
* \return 0 on success, -1 if given index is invalid.
* If -1 is returned, the params won't be changed.
* If -1 is returned, the content of params is undefined.
*/
int spdk_vhost_vq_get_desc(struct spdk_vhost_dev *vdev, struct spdk_vhost_virtqueue *vq,
uint16_t req_idx, struct vring_desc **desc, struct vring_desc **desc_table,

View File

@ -335,6 +335,11 @@ process_ctrl_request(struct spdk_vhost_scsi_task *task)
switch (ctrl_req->type) {
case VIRTIO_SCSI_T_TMF:
task->tmf_resp = spdk_vhost_gpa_to_vva(vdev, desc->addr);
if (spdk_unlikely(desc->len < sizeof(struct virtio_scsi_ctrl_tmf_resp) || task->tmf_resp == NULL)) {
SPDK_ERRLOG("%s: TMF response descriptor at index %d points to invalid guest memory region\n",
vdev->name, task->req_idx);
goto out;
}
/* Check if we are processing a valid request */
if (task->scsi_dev == NULL) {
@ -359,6 +364,12 @@ process_ctrl_request(struct spdk_vhost_scsi_task *task)
case VIRTIO_SCSI_T_AN_QUERY:
case VIRTIO_SCSI_T_AN_SUBSCRIBE: {
an_resp = spdk_vhost_gpa_to_vva(vdev, desc->addr);
if (spdk_unlikely(desc->len < sizeof(struct virtio_scsi_ctrl_an_resp) || an_resp == NULL)) {
SPDK_WARNLOG("%s: Asynchronous response descriptor points to invalid guest memory region\n",
vdev->name);
goto out;
}
an_resp->response = VIRTIO_SCSI_S_ABORTED;
break;
}
@ -393,13 +404,19 @@ task_data_setup(struct spdk_vhost_scsi_task *task,
rc = spdk_vhost_vq_get_desc(vdev, task->vq, task->req_idx, &desc, &desc_table, &desc_table_len);
/* First descriptor must be readable */
if (rc != 0 || spdk_unlikely(spdk_vhost_vring_desc_is_wr(desc))) {
if (spdk_unlikely(rc != 0 || spdk_vhost_vring_desc_is_wr(desc) ||
desc->len < sizeof(struct virtio_scsi_cmd_req))) {
SPDK_WARNLOG("%s: invalid first (request) descriptor at index %"PRIu16".\n",
vdev->name, task->req_idx);
goto invalid_task;
}
*req = spdk_vhost_gpa_to_vva(vdev, desc->addr);
if (spdk_unlikely(*req == NULL)) {
SPDK_WARNLOG("%s: Request descriptor at index %d points to invalid guest memory region\n",
vdev->name, task->req_idx);
goto invalid_task;
}
/* Each request must have at least 2 descriptors (e.g. request and response) */
spdk_vhost_vring_desc_get_next(&desc, desc_table, desc_table_len);
@ -417,7 +434,11 @@ task_data_setup(struct spdk_vhost_scsi_task *task,
* FROM_DEV (READ): [RD_req][WR_resp][WR_buf0]...[WR_bufN]
*/
task->resp = spdk_vhost_gpa_to_vva(vdev, desc->addr);
if (spdk_unlikely(desc->len < sizeof(struct virtio_scsi_cmd_resp) || task->resp == NULL)) {
SPDK_WARNLOG("%s: Response descriptor at index %d points to invalid guest memory region\n",
vdev->name, task->req_idx);
goto invalid_task;
}
rc = spdk_vhost_vring_desc_get_next(&desc, desc_table, desc_table_len);
if (spdk_unlikely(rc != 0)) {
SPDK_WARNLOG("%s: invalid descriptor chain at request index %d (descriptor id overflow?).\n",
@ -480,6 +501,11 @@ task_data_setup(struct spdk_vhost_scsi_task *task,
}
task->resp = spdk_vhost_gpa_to_vva(vdev, desc->addr);
if (spdk_unlikely(desc->len < sizeof(struct virtio_scsi_cmd_resp) || task->resp == NULL)) {
SPDK_WARNLOG("%s: Response descriptor at index %d points to invalid guest memory region\n",
vdev->name, task->req_idx);
goto invalid_task;
}
}
if (iovcnt == iovcnt_max) {