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 = spdk_vhost_gpa_to_vva(vdev, (*desc)->addr);
*desc_table_size = (*desc)->len / sizeof(**desc); *desc_table_size = (*desc)->len / sizeof(**desc);
*desc = *desc_table; *desc = *desc_table;
if (*desc == NULL) {
return -1;
}
return 0; return 0;
} }

View File

@ -148,7 +148,7 @@ bool spdk_vhost_vq_should_notify(struct spdk_vhost_dev *vdev, struct spdk_vhost_
* table. * table.
* \param desc_table_size size of the *desc_table* * \param desc_table_size size of the *desc_table*
* \return 0 on success, -1 if given index is invalid. * \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, 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, 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) { switch (ctrl_req->type) {
case VIRTIO_SCSI_T_TMF: case VIRTIO_SCSI_T_TMF:
task->tmf_resp = spdk_vhost_gpa_to_vva(vdev, desc->addr); 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 */ /* Check if we are processing a valid request */
if (task->scsi_dev == NULL) { 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_QUERY:
case VIRTIO_SCSI_T_AN_SUBSCRIBE: { case VIRTIO_SCSI_T_AN_SUBSCRIBE: {
an_resp = spdk_vhost_gpa_to_vva(vdev, desc->addr); 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; an_resp->response = VIRTIO_SCSI_S_ABORTED;
break; 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); rc = spdk_vhost_vq_get_desc(vdev, task->vq, task->req_idx, &desc, &desc_table, &desc_table_len);
/* First descriptor must be readable */ /* 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", SPDK_WARNLOG("%s: invalid first (request) descriptor at index %"PRIu16".\n",
vdev->name, task->req_idx); vdev->name, task->req_idx);
goto invalid_task; goto invalid_task;
} }
*req = spdk_vhost_gpa_to_vva(vdev, desc->addr); *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) */ /* 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); 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] * FROM_DEV (READ): [RD_req][WR_resp][WR_buf0]...[WR_bufN]
*/ */
task->resp = spdk_vhost_gpa_to_vva(vdev, desc->addr); 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); rc = spdk_vhost_vring_desc_get_next(&desc, desc_table, desc_table_len);
if (spdk_unlikely(rc != 0)) { if (spdk_unlikely(rc != 0)) {
SPDK_WARNLOG("%s: invalid descriptor chain at request index %d (descriptor id overflow?).\n", 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); 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) { if (iovcnt == iovcnt_max) {